Skip to content

Commit 9640e3a

Browse files
committed
[#398] Support Exception Chain Metadata (PExceptionMetaData)
1 parent a08c4a0 commit 9640e3a

File tree

6 files changed

+112
-64
lines changed

6 files changed

+112
-64
lines changed

lib/client/data-sender.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class DataSender {
5151
this.dataSender.sendSqlMetaInfo(data)
5252
} else if (data instanceof SqlUidMetaData) {
5353
this.dataSender.sendSqlUidMetaData(data)
54+
} else if (data?.isExceptionMetaData?.()) {
55+
this.dataSender.sendExceptionMetaData(data)
5456
}
5557
}
5658

lib/client/grpc-data-sender.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,14 @@ class GrpcDataSender {
235235
})
236236
}
237237

238+
sendExceptionMetaData(exceptionMetaData) {
239+
const pExceptionMetaData = exceptionMetaData.valueOfProtocolBuffer()
240+
const options = this.unaryDeadlineOptionsBuilder.build()
241+
this.metadataClient.requestExceptionMetaData(pExceptionMetaData, options, (err) => {
242+
logError(err)
243+
})
244+
}
245+
238246
sendSpan(span) {
239247
try {
240248
const pSpan = span.toProtocolBuffer()

lib/context/trace/exception-builder.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const { namedGroupCallSite } = require('../../instrumentation/call-stack')
1111
const { LongAnnotation } = require('../../instrumentation/context/annotation/long-annotation')
1212
const AnnotationKey = require('../annotation-key')
1313
const exceptionChainIdAnnotationKey = new AnnotationKey(-52, 'ExceptionChainId')
14+
const spanMessages = require('../../data/v1/Span_pb')
1415

1516
class Frame {
1617
constructor(className = '', fileName = 'unknown', lineNumber = 0, methodName = '') {
@@ -19,6 +20,15 @@ class Frame {
1920
this.lineNumber = lineNumber
2021
this.methodName = methodName
2122
}
23+
24+
toProtocolBuffer() {
25+
const pFrame = new spanMessages.PFrame()
26+
pFrame.setClassname(this.className)
27+
pFrame.setFilename(this.fileName)
28+
pFrame.setLinenumber(this.lineNumber)
29+
pFrame.setMethodname(this.methodName)
30+
return pFrame
31+
}
2232
}
2333

2434
class Exception {
@@ -36,7 +46,17 @@ class Exception {
3646
}
3747

3848
toProtocolBuffer() {
39-
49+
const pException = new spanMessages.PException()
50+
pException.setExceptiontype(exception.type)
51+
pException.setExceptionmessage(exception.message)
52+
pException.setStarttime(exception.startTime)
53+
pException.setExceptionid(exception.exceptionId)
54+
pException.setExceptiondepth(exception.exceptionDepth)
55+
56+
this.frameStack.forEach(frame => {
57+
pException.addStacktraceelement(frame.toProtocolBuffer())
58+
})
59+
return pException
4060
}
4161
}
4262

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Pinpoint Node.js Agent
3+
* Copyright 2020-present NAVER Corp.
4+
* Apache License v2.0
5+
*/
6+
7+
'use strict'
8+
const spanMessages = require('../../data/v1/Span_pb')
9+
10+
class ExceptionMetaData {
11+
constructor(traceRoot, exceptions, uriTemplate) {
12+
this.traceRoot = traceRoot
13+
this.exceptions = exceptions
14+
this.uriTemplate = uriTemplate
15+
}
16+
17+
isExceptionMetaData() {
18+
return true
19+
}
20+
21+
valueOfProtocolBuffer() {
22+
const pExceptionMetaData = new spanMessages.pExceptionMetaData()
23+
pExceptionMetaData.setTransactionid(this.traceRoot.getTraceId().toProtocolBuffer())
24+
pExceptionMetaData.setSpanid(this.traceRoot.getTraceId().getSpanId())
25+
pExceptionMetaData.setUriTemplate(this.uriTemplate)
26+
27+
const pExceptions = this.exceptions.map(exception => {
28+
return exception.toProtocolBuffer()
29+
})
30+
pExceptionMetaData.setExceptionsList(pExceptions)
31+
}
32+
}
33+
34+
class ExceptionMetaDataBuilder {
35+
constructor(traceRoot) {
36+
this.traceRoot = traceRoot
37+
this.exceptions = []
38+
this.uriTemplate = 'NULL'
39+
}
40+
41+
setUriTemplate(uriTemplate) {
42+
this.uriTemplate = uriTemplate
43+
return this
44+
}
45+
46+
addException(exception) {
47+
this.exceptions.push(exception)
48+
return this
49+
}
50+
51+
build() {
52+
return new ExceptionMetaData(this.traceRoot, this.exceptions, this.uriTemplate)
53+
}
54+
}
55+
56+
module.exports = {
57+
ExceptionMetaData,
58+
ExceptionMetaDataBuilder
59+
}

lib/context/trace/exceptions-builder.js

Lines changed: 0 additions & 44 deletions
This file was deleted.

lib/context/trace/span-repository.js

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
'use strict'
88

99
const SpanEventBuilder = require('./span-event-builder')
10-
const { ExceptionsBuilder } = require('./exceptions-builder')
10+
const { ExceptionMetaDataBuilder } = require('./exception-meta-data-builder')
1111

1212
// bufferSize in DefaultContextConfig.java
1313
const bufferSize = 20
@@ -18,7 +18,6 @@ class SpanRepository {
1818
this.dataSender = dataSender
1919
this.buffer = []
2020
this.agentInfo = agentInfo
21-
this.exceptionsBuilder = null
2221
this.exceptions = []
2322
}
2423

@@ -58,39 +57,43 @@ class SpanRepository {
5857
this.dataSender.send(this.spanChunkBuilder.build(spanEvents))
5958
}
6059

60+
filterExceptions(spanEvents) {
61+
if (!Array.isArray(spanEvents) || spanEvents.length === 0) {
62+
return []
63+
}
64+
65+
const exceptions = spanEvents
66+
.map(spanEvent => spanEvent?.exception)
67+
.filter(Boolean)
68+
69+
if (exceptions.length === 0) {
70+
return []
71+
}
72+
73+
return exceptions
74+
}
75+
6176
storeSpan(spanBuilder) {
6277
if (!spanBuilder) {
6378
return
6479
}
6580
// GrpcSpanProcessorV2.java: postProcess(Span span, pSpan)
6681
const sortedSpanEventBuilders = calculateStartElapsedTime(this.bufferDrain(), spanBuilder.getStartTime())
6782
const spanEvents = sortedSpanEventBuilders.map(builder => builder.build())
68-
this.exceptions = this.exceptions.concat(this.filterExceptions(spanEvents))
6983
spanBuilder.setSpanEventList(spanEvents)
7084
spanBuilder.setApplicationServiceType(this.agentInfo.getApplicationServiceType())
7185
this.dataSender.send(spanBuilder.build())
86+
87+
const exceptions = this.exceptions.concat(this.filterExceptions(spanEvents))
88+
const builder = new ExceptionMetaDataBuilder(spanBuilder.getTraceRoot())
89+
exceptions.forEach(exception => builder.addException(exception))
90+
this.dataSender.send(builder.build())
7291
}
7392

7493
flush() {
7594
const buffer = this.bufferDrain()
7695
this.sendSpanChunk(buffer)
7796
}
78-
79-
filterExceptions(spanEvents) {
80-
if (!Array.isArray(spanEvents) || spanEvents.length === 0) {
81-
return []
82-
}
83-
84-
const exceptions = spanEvents
85-
.map(spanEvent => spanEvent?.exception)
86-
.filter(Boolean)
87-
88-
if (exceptions.length === 0) {
89-
return []
90-
}
91-
92-
return exceptions
93-
}
9497
}
9598

9699
module.exports = SpanRepository

0 commit comments

Comments
 (0)