From c97e66edce2bae0efe6b68b192a60ccbf8161ac8 Mon Sep 17 00:00:00 2001 From: Minwoo Jung Date: Tue, 17 Mar 2015 15:48:14 +0900 Subject: [PATCH] [#234] Add function to see log of application using pinpoint agent --- .../profiler/modifier/log/MdcKey.java | 3 +- .../LoggingEventOfLog4jInterceptor.java | 2 + .../LoggingEventOfLogbackInterceptor.java | 2 + .../BusinessTransactionController.java | 30 ++++-- .../controller/ScatterChartController.java | 18 +++- .../service/TransactionInfoServiceImpl.java | 102 ++++++++++++++++-- .../pinpoint/web/vo/callstacks/Record.java | 36 ++++++- .../main/resources/pinpoint-web.properties | 7 +- .../WEB-INF/views/transactionInfoJson.jsp | 19 +++- .../WEB-INF/views/transactionmetadata.jsp | 9 +- .../scripts/directives/distributedCallFlow.js | 53 +++++---- .../scripts/directives/transactionTable.js | 2 - .../main/webapp/views/transactionTable.html | 2 +- 13 files changed, 238 insertions(+), 47 deletions(-) diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/MdcKey.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/MdcKey.java index 8e2086d2c..153898b9a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/MdcKey.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/MdcKey.java @@ -19,5 +19,6 @@ package com.navercorp.pinpoint.profiler.modifier.log; * @author minwoo.jung */ public class MdcKey { - public static final String TRANSACTION_ID = "TransactionID"; + public static final String TRANSACTION_ID = "PtransactionId"; + public static final String SPAN_ID = "PspanId"; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/log4j/interceptor/LoggingEventOfLog4jInterceptor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/log4j/interceptor/LoggingEventOfLog4jInterceptor.java index 5f2d6f957..39ed1d2ba 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/log4j/interceptor/LoggingEventOfLog4jInterceptor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/log4j/interceptor/LoggingEventOfLog4jInterceptor.java @@ -46,9 +46,11 @@ public class LoggingEventOfLog4jInterceptor implements SimpleAroundInterceptor, if (trace == null) { MDC.remove(MdcKey.TRANSACTION_ID); + MDC.remove(MdcKey.SPAN_ID); return; } else { MDC.put(MdcKey.TRANSACTION_ID, trace.getTraceId().getTransactionId()); + MDC.put(MdcKey.SPAN_ID, String.valueOf(trace.getTraceId().getSpanId())); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/logback/interceptor/LoggingEventOfLogbackInterceptor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/logback/interceptor/LoggingEventOfLogbackInterceptor.java index b23e8824f..09a445b8f 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/logback/interceptor/LoggingEventOfLogbackInterceptor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/modifier/log/logback/interceptor/LoggingEventOfLogbackInterceptor.java @@ -46,9 +46,11 @@ public class LoggingEventOfLogbackInterceptor implements SimpleAroundInterceptor if (trace == null) { MDC.remove(MdcKey.TRANSACTION_ID); + MDC.remove(MdcKey.SPAN_ID); return; } else { MDC.put(MdcKey.TRANSACTION_ID, trace.getTraceId().getTransactionId()); + MDC.put(MdcKey.SPAN_ID, String.valueOf(trace.getTraceId().getSpanId())); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java index 015af8204..6527ffd6c 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java @@ -18,10 +18,24 @@ package com.navercorp.pinpoint.web.controller; import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; + import com.navercorp.pinpoint.web.applicationmap.ApplicationMap; import com.navercorp.pinpoint.web.calltree.span.SpanAlign; import com.navercorp.pinpoint.web.filter.Filter; @@ -36,19 +50,9 @@ import com.navercorp.pinpoint.web.vo.BusinessTransactions; import com.navercorp.pinpoint.web.vo.LimitedScanResult; import com.navercorp.pinpoint.web.vo.Range; import com.navercorp.pinpoint.web.vo.TransactionId; +import com.navercorp.pinpoint.web.vo.callstacks.Record; import com.navercorp.pinpoint.web.vo.callstacks.RecordSet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.servlet.ModelAndView; - /** * @author emeroad */ @@ -68,6 +72,9 @@ public class BusinessTransactionController { @Autowired private FilterBuilder filterBuilder; + + @Value("#{pinpointWebProps['log.enable'] ?: false}") + private boolean logLinkEnable; /** * executed URLs in applicationname query within from ~ to timeframe @@ -164,6 +171,7 @@ public class BusinessTransactionController { ApplicationMap map = filteredMapService.selectApplicationMap(traceId); mv.addObject("nodes", map.getNodes()); mv.addObject("links", map.getLinks()); + mv.addObject("logLinkEnable", logLinkEnable); // call stacks RecordSet recordSet = this.transactionInfoService.createRecordSet(spanAligns, focusTimestamp); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java index 86ae08b4f..2da2bb419 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java @@ -38,6 +38,7 @@ import com.navercorp.pinpoint.web.vo.scatter.ScatterIndex; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.StopWatch; @@ -64,6 +65,16 @@ public class ScatterChartController { @Autowired private FilterBuilder filterBuilder; + + + @Value("#{pinpointWebProps['log.enable'] ?: false}") + private boolean logLinkEnable; + + @Value("#{pinpointWebProps['log.button.name'] ?: ''}") + private String logButtonName; + + @Value("#{pinpointWebProps['log.page.url'] ?: ''}") + private String logPageUrl; private static final String PREFIX_TRANSACTION_ID = "I"; private static final String PREFIX_TIME = "T"; @@ -222,7 +233,12 @@ public class ScatterChartController { List metadata = scatter.selectTransactionMetadata(query); model.addAttribute("metadata", metadata); } - + + if (logLinkEnable) { + model.addAttribute("logButtonName", logButtonName); + model.addAttribute("logPageUrl", logPageUrl); + } + return "transactionmetadata"; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java index 09250d1e2..aa5744dc5 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java @@ -18,6 +18,8 @@ package com.navercorp.pinpoint.web.service; import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import com.navercorp.pinpoint.common.AnnotationKey; @@ -68,6 +70,15 @@ public class TransactionInfoServiceImpl implements TransactionInfoService { @Autowired private AnnotationKeyRegistryService annotationKeyRegistryService; + @Value("#{pinpointWebProps['log.enable'] ?: false}") + private boolean logLinkEnable; + + @Value("#{pinpointWebProps['log.button.name'] ?: ''}") + private String logButtonName; + + @Value("#{pinpointWebProps['log.page.url'] ?: ''}") + private String logPageUrl; + @Override public BusinessTransactions selectBusinessTransactions(List transactionIdList, String applicationName, Range range, Filter filter) { if (transactionIdList == null) { @@ -153,6 +164,11 @@ public class TransactionInfoServiceImpl implements TransactionInfoService { } recordSet.setRecordList(recordList); + + if (logLinkEnable) { + addlogLink(recordSet); + } + return recordSet; } @@ -165,6 +181,66 @@ public class TransactionInfoServiceImpl implements TransactionInfoService { } } + private void addlogLink(RecordSet recordSet) { + List records = recordSet.getRecordList(); + List transactionInfoes = new LinkedList(); + + for (Iterator iterator = records.iterator(); iterator.hasNext();) { + Record record = (Record) iterator.next(); + + if(record.getTransactionId() == null) { + continue; + } + + TransactionInfo transactionInfo = new TransactionInfo(record.getTransactionId(), record.getSpanId()); + + if (transactionInfoes.contains(transactionInfo)) { + continue; + }; + + record.setLogPageUrl(logPageUrl); + record.setLogButtonName(logButtonName); + + transactionInfoes.add(transactionInfo); + } + } + + private class TransactionInfo { + + private final String transactionId; + private final long spanId; + + public TransactionInfo(String transactionId, long spanId) { + this.transactionId = transactionId; + this.spanId = spanId; + } + + public String getTransactionId() { + return transactionId; + } + + public long getSpanId() { + return spanId; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TransactionInfo == false) { + return false; + } + + TransactionInfo transactionInfo = (TransactionInfo)obj; + + if (!transactionId.equals(transactionInfo.getTransactionId())) { + return false; + } + if (spanId != transactionInfo.getSpanId()) { + return false; + } + + return true; + } + } private long getStartTime(List spanAlignList) { if (spanAlignList == null || spanAlignList.size() == 0) { @@ -314,7 +390,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService { registry.findServiceType(spanBo.getServiceType()), null, spanAlign.isHasChild(), - false); + false, + spanBo.getTransactionId(), + spanBo.getSpanId()); record.setSimpleClassName(apiDescription.getSimpleClassName()); record.setFullApiDescription(method); recordList.add(record); @@ -334,7 +412,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService { registry.findServiceType(spanBo.getServiceType()), null, spanAlign.isHasChild(), - false); + false, + spanBo.getTransactionId(), + spanBo.getSpanId()); record.setSimpleClassName(""); record.setFullApiDescription(""); recordList.add(record); @@ -388,7 +468,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService { /* spanEventBo.getDestinationId(), spanEventBo.getServiceTypeCode(),*/ destinationId, spanAlign.isHasChild(), - false); + false, + spanBo.getTransactionId(), + spanBo.getSpanId()); record.setSimpleClassName(apiDescription.getSimpleClassName()); record.setFullApiDescription(method); @@ -416,7 +498,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService { /*spanEventBo.getDestinationId(), spanEventBo.getServiceTypeCode(),*/ destinationId, spanAlign.isHasChild(), - false); + false, + spanBo.getTransactionId(), + spanBo.getSpanId()); record.setSimpleClassName(""); record.setFullApiDescription(method); @@ -454,7 +538,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService { null, null, false, - false); + false, + spanBo.getTransactionId(), + spanBo.getSpanId()); } } else { final SpanEventBo spanEventBo = spanAlign.getSpanEventBo(); @@ -474,7 +560,9 @@ public class TransactionInfoServiceImpl implements TransactionInfoService { null, null, false, - true); + true, + null, + 0); } } return null; @@ -529,7 +617,7 @@ public class TransactionInfoServiceImpl implements TransactionInfoService { for (AnnotationBo ann : annotationBoList) { AnnotationKey annotation = findAnnotationKey(ann.getKey()); if (annotation.isViewInRecordSet()) { - Record record = new Record(depth, getNextId(), parentId, false, annotation.getName(), ann.getValue().toString(), 0L, 0L, 0, null, null, null, null, false, false); + Record record = new Record(depth, getNextId(), parentId, false, annotation.getName(), ann.getValue().toString(), 0L, 0L, 0, null, null, null, null, false, false, null, 0); recordList.add(record); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/Record.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/Record.java index 636c37eb4..7747a8cfa 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/Record.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/Record.java @@ -44,11 +44,18 @@ public class Record { private final String destinationId; private final boolean excludeFromTimeline; + private final String transactionId; + private final long spanId; + private boolean focused; private boolean hasChild; private boolean hasException; + private String logPageUrl; + private String logButtonName; + + - public Record(int tab, int id, int parentId, boolean method, String title, String arguments, long begin, long elapsed, long gap, String agent, String applicationName, ServiceType serviceType, String destinationId, boolean hasChild, boolean hasException) { + public Record(int tab, int id, int parentId, boolean method, String title, String arguments, long begin, long elapsed, long gap, String agent, String applicationName, ServiceType serviceType, String destinationId, boolean hasChild, boolean hasException, String transactionId, long spanId) { this.tab = tab; this.id = id; this.parentId = parentId; @@ -68,6 +75,9 @@ public class Record { this.excludeFromTimeline = serviceType == null || serviceType.isInternalMethod(); this.hasChild = hasChild; this.hasException = hasException; + + this.transactionId = transactionId; + this.spanId = spanId; } public int getId() { @@ -175,6 +185,30 @@ public class Record { public boolean getHasException() { return hasException; } + + public String getTransactionId() { + return transactionId; + } + + public long getSpanId() { + return spanId; + } + + public void setLogPageUrl(String logPageUrl) { + this.logPageUrl = logPageUrl; + } + + public void setLogButtonName(String logButtonName) { + this.logButtonName = logButtonName; + } + + public String getLogPageUrl() { + return this.logPageUrl; + } + + public String getLogButtonName() { + return this.logButtonName; + } @Override diff --git a/web/src/main/resources/pinpoint-web.properties b/web/src/main/resources/pinpoint-web.properties index 51604645c..550306ee8 100644 --- a/web/src/main/resources/pinpoint-web.properties +++ b/web/src/main/resources/pinpoint-web.properties @@ -6,4 +6,9 @@ cluster.zookeeper.sessiontimeout=3000 cluster.zookeeper.retry.interval=5000 # FIXME - should be removed for proper authentication -admin.password=admin \ No newline at end of file +admin.password=admin + +#log site link +#log.enable=false +#log.page.url= +#log.button.name= diff --git a/web/src/main/webapp/WEB-INF/views/transactionInfoJson.jsp b/web/src/main/webapp/WEB-INF/views/transactionInfoJson.jsp index dafdc2cc8..dd7b2c4a3 100644 --- a/web/src/main/webapp/WEB-INF/views/transactionInfoJson.jsp +++ b/web/src/main/webapp/WEB-INF/views/transactionInfoJson.jsp @@ -10,6 +10,7 @@ "callStackStart" : ${callstackStart}, "callStackEnd" : ${callstackEnd}, "completeState" : "${completeState}", + "logLinkEnable" : ${logLinkEnable}, "callStackIndex" : { "depth":0, "begin":1, @@ -31,7 +32,9 @@ "apiType":17, "agent":18, "isFocused":19, - "hasException":20 + "hasException":20, + "logButtonName":21, + "logPageUrl":22 }, "callStack" : [ [ @@ -55,7 +58,19 @@ ${record.hasChild}, "${record.apiType}", "${record.agent}", ${record.focused}, -${record.hasException} +${record.hasException}, +"${record.logButtonName}", + + + + + + + + "${logPageUrl}" + + "" + ], ], "applicationMapData" : { diff --git a/web/src/main/webapp/WEB-INF/views/transactionmetadata.jsp b/web/src/main/webapp/WEB-INF/views/transactionmetadata.jsp index bfa3b9a67..1386f815e 100644 --- a/web/src/main/webapp/WEB-INF/views/transactionmetadata.jsp +++ b/web/src/main/webapp/WEB-INF/views/transactionmetadata.jsp @@ -13,7 +13,14 @@ "agentId" : "${span.agentId}", "endpoint" : "${span.endPoint}", "exception" : ${span.errCode}, - "remoteAddr" : "${span.remoteAddr}" + "remoteAddr" : "${span.remoteAddr}", + "logButtonName" : "${logButtonName}", + + + + + "logPageUrl" : "${url}" + } , diff --git a/web/src/main/webapp/scripts/directives/distributedCallFlow.js b/web/src/main/webapp/scripts/directives/distributedCallFlow.js index 0567c78a7..4be3976d1 100644 --- a/web/src/main/webapp/scripts/directives/distributedCallFlow.js +++ b/web/src/main/webapp/scripts/directives/distributedCallFlow.js @@ -12,7 +12,7 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', link: function postLink(scope, element, attrs) { // initialize variables - var grid, columns, dataView, lastAgent; + var grid, dataView, lastAgent; // initialize variables of methods var initialize, treeFormatter, treeFilter, parseData, execTimeFormatter, @@ -125,12 +125,24 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', }; - linkFormatter = function (row, cell, value, columnDef, dataConrtext) { + linkFormatter = function (row, cell, value, columnDef, dataContext) { + + if (!value || 0 === value.length) { + return; + } + var html = []; html.push('nelo'); + html.push('" target="_blank">'); + + var item = dataView.getItemById(dataContext.id); + var logButtonName = item.logButtonName; + html.push(logButtonName); + + html.push(''); + return html.join(''); }; @@ -171,21 +183,6 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', return ""; }; - // columns - columns = [ - {id: "method", name: "Method", field: "method", width: 400, formatter: treeFormatter}, - {id: "argument", name: "Argument", field: "argument", width: 300, formatter: argumentFormatter}, - {id: "exec-time", name: "Exec Time", field: "execTime", width: 90, formatter: execTimeFormatter}, - {id: "gap-ms", name: "Gap(ms)", field: "gapMs", width: 60, cssClass: "right-align"}, - {id: "time-ms", name: "Time(ms)", field: "timeMs", width: 60, cssClass: "right-align"}, - {id: "time-per", name: "Time(%)", field: "timePer", width: 100, formatter: progressBarFormatter}, - {id: "class", name: "Class", field: "class", width: 120}, - {id: "api-type", name: "Api Type", field: "apiType", width: 90}, - {id: "agent", name: "Agent", field: "agent", width: 130}, - {id: "application-name", name: "Application Name", field: "applicationName", width: 150}, - {id: "Loglink", name: "log", field: "logLink", width: 50, formatter:linkFormatter} - ]; - /** * parse data * @param index @@ -212,7 +209,8 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', applicationName: val[index['applicationName']], hasException: val[index['hasException']], isMethod: val[index['isMethod']] , - logLink : "http://localhost/NeloLogWithTransactionId.pinpoint?transactionId=minwoo_local_tomcat%5E1425368654938%5E10" + logLink : val[index['logPageUrl']], + logButtonName : val[index['logButtonName']], }); }); return result; @@ -253,6 +251,23 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', // }; dataView.endUpdate(); + var columns = [ + {id: "method", name: "Method", field: "method", width: 400, formatter: treeFormatter}, + {id: "argument", name: "Argument", field: "argument", width: 300, formatter: argumentFormatter}, + {id: "exec-time", name: "Exec Time", field: "execTime", width: 90, formatter: execTimeFormatter}, + {id: "gap-ms", name: "Gap(ms)", field: "gapMs", width: 60, cssClass: "right-align"}, + {id: "time-ms", name: "Time(ms)", field: "timeMs", width: 60, cssClass: "right-align"}, + {id: "time-per", name: "Time(%)", field: "timePer", width: 100, formatter: progressBarFormatter}, + {id: "class", name: "Class", field: "class", width: 120}, + {id: "api-type", name: "Api Type", field: "apiType", width: 90}, + {id: "agent", name: "Agent", field: "agent", width: 130}, + {id: "application-name", name: "Application Name", field: "applicationName", width: 150} + ]; + + if (t.logLinkEnable) { + columns.push({id: "Loglink", name: "log", field: "logLink", width: 50, formatter:linkFormatter}); + } + grid = new Slick.Grid(element.get(0), dataView, columns, options); var isSingleClick = true, clickTimeout = false; diff --git a/web/src/main/webapp/scripts/directives/transactionTable.js b/web/src/main/webapp/scripts/directives/transactionTable.js index bfd0b484c..30a38b39d 100644 --- a/web/src/main/webapp/scripts/directives/transactionTable.js +++ b/web/src/main/webapp/scripts/directives/transactionTable.js @@ -45,8 +45,6 @@ pinpointApp.directive('transactionTable', ['$window', function ($window) { var index = 1; angular.forEach(scope.transactionList, function (val, key) { val['index'] = index++; - val['logName'] = "nelo"; - val['logUrl'] = "http://localhost/NeloLogWithTransactionId.pinpoint?transactionId=minwoo_local_tomcat%5E1425368654938%5E10"; }); }; diff --git a/web/src/main/webapp/views/transactionTable.html b/web/src/main/webapp/views/transactionTable.html index 3f663d04e..fdd422558 100644 --- a/web/src/main/webapp/views/transactionTable.html +++ b/web/src/main/webapp/views/transactionTable.html @@ -66,7 +66,7 @@ {{transaction.agentId}} {{transaction.remoteAddr}} - {{transaction.traceId}} {{transaction.logName}} + {{transaction.traceId}} {{transaction.logButtonName}}