mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-16 08:16:15 +10:00
Merge pull request #813 from koo-taejin/active_thread
Trace current active requests info. #751
This commit is contained in:
@@ -207,6 +207,11 @@
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-websocket</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
|
||||
@@ -30,6 +30,11 @@ public class TimerFactory {
|
||||
|
||||
public static HashedWheelTimer createHashedWheelTimer(String threadName, long tickDuration, TimeUnit unit, int ticksPerWheel) {
|
||||
final PinpointThreadFactory threadFactory = new PinpointThreadFactory(threadName, true);
|
||||
return createHashedWheelTimer(threadFactory, tickDuration, unit, ticksPerWheel);
|
||||
}
|
||||
|
||||
public static HashedWheelTimer createHashedWheelTimer(PinpointThreadFactory threadFactory, long tickDuration, TimeUnit unit, int ticksPerWheel) {
|
||||
return new HashedWheelTimer(threadFactory, ThreadNameDeterminer.CURRENT, tickDuration, unit, ticksPerWheel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -121,6 +121,10 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.web.config;
|
||||
|
||||
|
||||
import com.navercorp.pinpoint.web.websocket.PinpointWebSocketHandler;
|
||||
import com.navercorp.pinpoint.web.websocket.WebSocketHandlerRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSocket
|
||||
@Component
|
||||
public class WebSocketConfig implements WebSocketConfigurer {
|
||||
|
||||
private static final String WEBSOCKET_SUFFIX = ".pinpointws";
|
||||
|
||||
@Autowired
|
||||
private WebSocketHandlerRepository handlerRepository;
|
||||
|
||||
@Override
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||
for (PinpointWebSocketHandler handler : handlerRepository.getWebSocketHandlerRepository()) {
|
||||
registry.addHandler(handler, handler.getRequestMapping() + WEBSOCKET_SUFFIX).addInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import java.util.Map;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import com.navercorp.pinpoint.common.bo.AgentInfoBo;
|
||||
import org.apache.zookeeper.KeeperException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -113,6 +114,10 @@ public class PinpointSocketManager {
|
||||
return serverAcceptor.getWritableServerList();
|
||||
}
|
||||
|
||||
public PinpointServer getCollector(AgentInfoBo agentInfo) {
|
||||
return getCollector(agentInfo.getApplicationName(), agentInfo.getAgentId(), agentInfo.getStartTime());
|
||||
}
|
||||
|
||||
public PinpointServer getCollector(String applicationName, String agentId, long startTimeStamp) {
|
||||
List<String> agentNameList = clusterManager.getRegisteredAgentList(applicationName, agentId, startTimeStamp);
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.web.service;
|
||||
|
||||
import com.navercorp.pinpoint.common.bo.AgentInfoBo;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TActiveThreadResponse;
|
||||
import org.apache.thrift.TBase;
|
||||
import org.apache.thrift.TException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
public interface AgentService {
|
||||
|
||||
List<AgentInfoBo> get(String applicationName);
|
||||
|
||||
Map<String, TActiveThreadResponse> getActiveThreadStatus(List<AgentInfoBo> agentInfoList) throws TException;
|
||||
|
||||
Map<String, TActiveThreadResponse> getActiveThreadStatus(List<AgentInfoBo> agentInfoList, byte[] payload) throws TException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.web.service;
|
||||
|
||||
import com.navercorp.pinpoint.common.bo.AgentInfoBo;
|
||||
import com.navercorp.pinpoint.rpc.Future;
|
||||
import com.navercorp.pinpoint.rpc.ResponseMessage;
|
||||
import com.navercorp.pinpoint.rpc.server.PinpointServer;
|
||||
import com.navercorp.pinpoint.rpc.util.ListUtils;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TActiveThread;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TActiveThreadResponse;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TCommandTransfer;
|
||||
import com.navercorp.pinpoint.thrift.io.DeserializerFactory;
|
||||
import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer;
|
||||
import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer;
|
||||
import com.navercorp.pinpoint.thrift.io.SerializerFactory;
|
||||
import com.navercorp.pinpoint.thrift.util.SerializationUtils;
|
||||
import com.navercorp.pinpoint.web.server.PinpointSocketManager;
|
||||
import com.navercorp.pinpoint.web.vo.Range;
|
||||
import org.apache.thrift.TBase;
|
||||
import org.apache.thrift.TException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
@Service
|
||||
public class AgentServiceImpl implements AgentService {
|
||||
|
||||
@Autowired
|
||||
private AgentInfoService agentInfoService;
|
||||
|
||||
@Autowired
|
||||
private PinpointSocketManager pinpointSocketManager;
|
||||
|
||||
@Autowired
|
||||
private SerializerFactory<HeaderTBaseSerializer> commandSerializerFactory;
|
||||
|
||||
@Autowired
|
||||
private DeserializerFactory<HeaderTBaseDeserializer> commandDeserializerFactory;
|
||||
|
||||
@Override
|
||||
public List<AgentInfoBo> get(String applicationName) {
|
||||
List<AgentInfoBo> agentInfoList = new ArrayList<AgentInfoBo>();
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
Range range = new Range(currentTime, currentTime);
|
||||
SortedMap<String, List<AgentInfoBo>> applicationAgentList = agentInfoService.getApplicationAgentList(applicationName, range);
|
||||
for (Map.Entry<String, List<AgentInfoBo>> entry : applicationAgentList.entrySet()) {
|
||||
AgentInfoBo agentInfo = ListUtils.getFirst(entry.getValue(), null);
|
||||
ListUtils.addIfValueNotNull(agentInfoList, agentInfo);
|
||||
}
|
||||
|
||||
return agentInfoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, TActiveThreadResponse> getActiveThreadStatus(List<AgentInfoBo> agentInfoList) throws TException {
|
||||
byte[] activeThread = serialize(new TActiveThread());
|
||||
return getActiveThreadStatus(agentInfoList, activeThread);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, TActiveThreadResponse> getActiveThreadStatus(List<AgentInfoBo> agentInfoList, byte[] payload) throws TException {
|
||||
Map<String, Future<ResponseMessage>> futureMap = invoke(agentInfoList, payload);
|
||||
|
||||
Map<String, TActiveThreadResponse> responseMap = new HashMap<String, TActiveThreadResponse>();
|
||||
for (Map.Entry<String, Future<ResponseMessage>> futureEntry : futureMap.entrySet()) {
|
||||
String hostName = futureEntry.getKey();
|
||||
Future<ResponseMessage> future = futureEntry.getValue();
|
||||
future.await();
|
||||
|
||||
ResponseMessage responseMessage = future.getResult();
|
||||
TBase result = deserialize(responseMessage.getMessage());
|
||||
if (result instanceof TActiveThreadResponse) {
|
||||
responseMap.put(hostName, (TActiveThreadResponse) result);
|
||||
}
|
||||
}
|
||||
|
||||
return responseMap;
|
||||
}
|
||||
|
||||
private Map<String, Future<ResponseMessage>> invoke(List<AgentInfoBo> agentInfoList, byte[] payload) throws TException {
|
||||
Map<String, Future<ResponseMessage>> futureMap = new HashMap<String, Future<ResponseMessage>>();
|
||||
for (AgentInfoBo agentInfo : agentInfoList) {
|
||||
TCommandTransfer transferObject = createCommandTransferObject(agentInfo, payload);
|
||||
PinpointServer collector = pinpointSocketManager.getCollector(agentInfo);
|
||||
Future<ResponseMessage> future = collector.request(serialize(transferObject));
|
||||
|
||||
futureMap.put(agentInfo.getHostName(), future);
|
||||
}
|
||||
return futureMap;
|
||||
}
|
||||
|
||||
private byte[] serialize(TBase tBase) throws TException {
|
||||
return SerializationUtils.serialize(tBase, commandSerializerFactory);
|
||||
}
|
||||
|
||||
private TBase deserialize(byte[] objectData) throws TException {
|
||||
return SerializationUtils.deserialize(objectData, commandDeserializerFactory);
|
||||
}
|
||||
|
||||
private TCommandTransfer createCommandTransferObject(AgentInfoBo agentInfo, byte[] payload) {
|
||||
TCommandTransfer transferObject = new TCommandTransfer();
|
||||
transferObject.setApplicationName(agentInfo.getApplicationName());
|
||||
transferObject.setAgentId(agentInfo.getAgentId());
|
||||
transferObject.setStartTime(agentInfo.getStartTime());
|
||||
transferObject.setPayload(payload);
|
||||
|
||||
return transferObject;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.web.vo;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TActiveThreadResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
@JsonSerialize(using = AgentActiveThreadStatusListSerializer.class)
|
||||
public class AgentActiveThreadStatusList {
|
||||
|
||||
private final Map<String, TActiveThreadResponse> agentActiveThreadReposioty;
|
||||
|
||||
public AgentActiveThreadStatusList(Map<String, TActiveThreadResponse> agentActiveThreadReposioty) {
|
||||
this.agentActiveThreadReposioty = new HashMap<String, TActiveThreadResponse>();
|
||||
}
|
||||
|
||||
public AgentActiveThreadStatusList(int initialCapacity) {
|
||||
agentActiveThreadReposioty = new HashMap<String, TActiveThreadResponse>(initialCapacity);
|
||||
}
|
||||
|
||||
public void add(String hostName, TActiveThreadResponse activeThreadStatus) {
|
||||
agentActiveThreadReposioty.put(hostName, activeThreadStatus);
|
||||
}
|
||||
|
||||
public void addAll(Map<String, TActiveThreadResponse> activeThreadStatuses) {
|
||||
agentActiveThreadReposioty.putAll(activeThreadStatuses);
|
||||
}
|
||||
|
||||
public Map<String, TActiveThreadResponse> getAgentActiveThreadReposioty() {
|
||||
return agentActiveThreadReposioty;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class AgentActiveThreadStatusListSerializer extends JsonSerializer<AgentActiveThreadStatusList>
|
||||
{
|
||||
@Override
|
||||
public void serialize(AgentActiveThreadStatusList agentActiveThreadStatusList, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
|
||||
Map<String, TActiveThreadResponse> agentActiveThreadReposioty = agentActiveThreadStatusList.getAgentActiveThreadReposioty();
|
||||
|
||||
jgen.writeStartObject();
|
||||
for (Map.Entry<String, TActiveThreadResponse> entry : agentActiveThreadReposioty.entrySet()) {
|
||||
List<Integer> activeThreadStatus = entry.getValue().getActiveThreadCount();
|
||||
if (activeThreadStatus == null || activeThreadStatus.size() < 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
jgen.writeFieldName(entry.getKey());
|
||||
jgen.writeStartObject();
|
||||
|
||||
jgen.writeFieldName("status");
|
||||
jgen.writeStartArray();
|
||||
jgen.writeNumber(activeThreadStatus.get(0));
|
||||
jgen.writeNumber(activeThreadStatus.get(1));
|
||||
jgen.writeNumber(activeThreadStatus.get(2));
|
||||
jgen.writeNumber(activeThreadStatus.get(3));
|
||||
jgen.writeEndArray();
|
||||
|
||||
jgen.writeNumberField("code", 0);
|
||||
// will be added codeMessage
|
||||
|
||||
jgen.writeEndObject();
|
||||
}
|
||||
|
||||
jgen.writeEndObject();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.web.websocket;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.navercorp.pinpoint.common.bo.AgentInfoBo;
|
||||
import com.navercorp.pinpoint.common.util.PinpointThreadFactory;
|
||||
import com.navercorp.pinpoint.rpc.util.TimerFactory;
|
||||
import com.navercorp.pinpoint.thrift.dto.command.TActiveThreadResponse;
|
||||
import com.navercorp.pinpoint.web.service.AgentService;
|
||||
import com.navercorp.pinpoint.web.vo.AgentActiveThreadStatusList;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.jboss.netty.util.Timeout;
|
||||
import org.jboss.netty.util.Timer;
|
||||
import org.jboss.netty.util.TimerTask;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
public class ActiveThreadHandler extends TextWebSocketHandler implements PinpointWebSocketHandler {
|
||||
|
||||
private static final String APPLICATION_NAME_KEY = "applicationName";
|
||||
private static final String DEFAULT_REQUEST_MAPPING = "/agent/activeThread";
|
||||
|
||||
private final String requestMapping;
|
||||
private final AgentService agentSerivce;
|
||||
|
||||
// it will be changed.
|
||||
private final long time = 1000;
|
||||
|
||||
private final PinpointThreadFactory threadFactory = new PinpointThreadFactory("ActiveThread Handler", true);
|
||||
private final TimerFactory timerFactory = new TimerFactory();
|
||||
|
||||
private final Map<String, List<WebSocketSession>> applicationGroup = new HashMap<String, List<WebSocketSession>>();
|
||||
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final Lock readLock = lock.readLock();
|
||||
private final Lock writeLock = lock.writeLock();
|
||||
|
||||
private final ObjectMapper jsonConverter = new ObjectMapper();
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private Timer timer;
|
||||
|
||||
public ActiveThreadHandler(AgentService agentSerivce) {
|
||||
this(DEFAULT_REQUEST_MAPPING, agentSerivce);
|
||||
}
|
||||
|
||||
public ActiveThreadHandler(String requestMapping, AgentService agentSerivce) {
|
||||
this.requestMapping = requestMapping;
|
||||
this.agentSerivce = agentSerivce;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestMapping() {
|
||||
return requestMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession newSession) throws Exception {
|
||||
logger.info("ConnectionEstablished : {}", newSession);
|
||||
|
||||
List<NameValuePair> params = URLEncodedUtils.parse(newSession.getUri(), "UTF-8");
|
||||
String applicationName = getValue(params, APPLICATION_NAME_KEY);
|
||||
if (applicationName == null) {
|
||||
logger.warn("Connection established refused. required parameter is missiong({}).", APPLICATION_NAME_KEY);
|
||||
newSession.close(CloseStatus.POLICY_VIOLATION);
|
||||
}
|
||||
newSession.getAttributes().put(APPLICATION_NAME_KEY, applicationName);
|
||||
|
||||
writeLock.lock();
|
||||
try {
|
||||
List<WebSocketSession> webSocketSessions = applicationGroup.get(applicationName);
|
||||
if (webSocketSessions == null) {
|
||||
webSocketSessions = new ArrayList<WebSocketSession>();
|
||||
applicationGroup.put(applicationName, webSocketSessions);
|
||||
}
|
||||
webSocketSessions.add(newSession);
|
||||
|
||||
if (timer == null) {
|
||||
timer = timerFactory.createHashedWheelTimer(threadFactory, 100, TimeUnit.MILLISECONDS, 512);
|
||||
Timeout timeout = timer.newTimeout(new ActiveThreadTimerTask(), time, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
super.afterConnectionEstablished(newSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession closeSession, CloseStatus status) throws Exception {
|
||||
logger.info("ConnectionClosed : {}, caused : {}", closeSession, status);
|
||||
|
||||
String applicationName = (String) closeSession.getAttributes().get(APPLICATION_NAME_KEY);
|
||||
|
||||
writeLock.lock();
|
||||
try {
|
||||
if (applicationName != null) {
|
||||
List<WebSocketSession> webSocketSessions = applicationGroup.get(applicationName);
|
||||
if (webSocketSessions == null) {
|
||||
webSocketSessions = new ArrayList<WebSocketSession>();
|
||||
}
|
||||
webSocketSessions.remove(closeSession);
|
||||
|
||||
if (webSocketSessions.size() == 0) {
|
||||
applicationGroup.remove(applicationName);
|
||||
}
|
||||
|
||||
if (applicationGroup.size() == 0) {
|
||||
if (timer != null) {
|
||||
timer.stop();
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
super.afterConnectionClosed(closeSession, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
logger.info("handleTextMessage. session : {}, message : {}.", session, message);
|
||||
|
||||
// this method will be checked socket status.
|
||||
super.handleTextMessage(session, message);
|
||||
}
|
||||
|
||||
private String getValue(List<NameValuePair> params, String key) {
|
||||
for (NameValuePair nv : params) {
|
||||
if (key.equals(nv.getName())) {
|
||||
return nv.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class ActiveThreadTimerTask implements TimerTask {
|
||||
|
||||
@Override
|
||||
public void run(Timeout timeout) throws Exception {
|
||||
logger.info("ActiveThreadTimerTask started.");
|
||||
|
||||
readLock.lock();
|
||||
try {
|
||||
for (Map.Entry<String, List<WebSocketSession>> applicationEntry : applicationGroup.entrySet()) {
|
||||
List<AgentInfoBo> agentInfoList = agentSerivce.get(applicationEntry.getKey());
|
||||
Map<String, TActiveThreadResponse> activeThreadStatuses = agentSerivce.getActiveThreadStatus(agentInfoList);
|
||||
|
||||
AgentActiveThreadStatusList agentActiveThreadStatusList = new AgentActiveThreadStatusList(activeThreadStatuses.size());
|
||||
agentActiveThreadStatusList.addAll(activeThreadStatuses);
|
||||
String textMessage = jsonConverter.writeValueAsString(agentActiveThreadStatusList);
|
||||
|
||||
for (WebSocketSession session : applicationEntry.getValue()) {
|
||||
session.sendMessage(new TextMessage(textMessage));
|
||||
}
|
||||
}
|
||||
|
||||
if (timer != null) {
|
||||
timer.newTimeout(new ActiveThreadTimerTask(), time, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.web.websocket;
|
||||
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
public interface PinpointWebSocketHandler extends WebSocketHandler {
|
||||
|
||||
String getRequestMapping();
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2014 NAVER Corp.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navercorp.pinpoint.web.websocket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author Taejin Koo
|
||||
*/
|
||||
public class WebSocketHandlerRepository {
|
||||
|
||||
private final List<PinpointWebSocketHandler> webSocketHandlerRepository;
|
||||
|
||||
public WebSocketHandlerRepository(List<PinpointWebSocketHandler> webSocketHandlerRepository) {
|
||||
this.webSocketHandlerRepository = webSocketHandlerRepository;
|
||||
}
|
||||
|
||||
public List<PinpointWebSocketHandler> getWebSocketHandlerRepository() {
|
||||
return new ArrayList<PinpointWebSocketHandler>(webSocketHandlerRepository);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -58,6 +58,8 @@
|
||||
|
||||
<import resource="classpath:applicationContext-cache.xml" />
|
||||
|
||||
<import resource="classpath:applicationContext-websocket.xml" />
|
||||
|
||||
<bean id="spanMapper" class="com.navercorp.pinpoint.web.mapper.SpanMapper"></bean>
|
||||
<bean id="annotationMapper" class="com.navercorp.pinpoint.web.mapper.AnnotationMapper"></bean>
|
||||
<bean id="spanAnnotationMapper" class="com.navercorp.pinpoint.web.mapper.SpanMapper">
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ /*
|
||||
~ * Copyright 2014 NAVER Corp.
|
||||
~ *
|
||||
~ * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ * you may not use this file except in compliance with the License.
|
||||
~ * You may obtain a copy of the License at
|
||||
~ *
|
||||
~ * http://www.apache.org/licenses/LICENSE-2.0
|
||||
~ *
|
||||
~ * Unless required by applicable law or agreed to in writing, software
|
||||
~ * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ * See the License for the specific language governing permissions and
|
||||
~ * limitations under the License.
|
||||
~ */
|
||||
~
|
||||
-->
|
||||
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
">
|
||||
|
||||
<bean id="remoteService" class="com.navercorp.pinpoint.web.service.AgentServiceImpl">
|
||||
</bean>
|
||||
|
||||
<bean id="activeThreadHandler" class="com.navercorp.pinpoint.web.websocket.ActiveThreadHandler">
|
||||
<!-- default value.
|
||||
<constructor-arg value="/agent/activeThread" />
|
||||
-->
|
||||
<constructor-arg ref="remoteService" />
|
||||
</bean>
|
||||
|
||||
<bean id="handlerRepository" class="com.navercorp.pinpoint.web.websocket.WebSocketHandlerRepository">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref bean="activeThreadHandler" />
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -37,6 +37,11 @@
|
||||
<url-pattern>*.pinpoint</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>pinpoint-web</servlet-name>
|
||||
<url-pattern>*.pinpointws</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<filter>
|
||||
<filter-name>encodingFilter</filter-name>
|
||||
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
|
||||
|
||||
Reference in New Issue
Block a user