From ccdc0ec25976c51cefda1da57d1fb1f7c9302698 Mon Sep 17 00:00:00 2001 From: Yongseok Date: Sun, 8 Dec 2024 19:21:47 +0900 Subject: [PATCH] [#233] Support SpanChunk and AsyncSpanChunk * Implement TraceRoot class for tracing functionality * Support SpanChunk and AsyncSpanChunk * Support ChildTrace * Fix node@16 test failure --- lib/agent.js | 17 +- lib/client/data-sender-factory.js | 8 +- lib/client/data-sender.js | 7 +- lib/client/grpc-data-sender.js | 4 +- lib/context/async-id.js | 14 +- lib/context/disable-span-event-recorder.js | 5 +- lib/context/disable-span-recorder.js | 6 +- lib/context/disable-trace.js | 14 +- lib/context/remote-trace-root-builder.js | 22 +- lib/context/span-builder.js | 82 +- lib/context/span-chunk-builder.js | 19 +- lib/context/trace-context.js | 29 +- lib/context/trace-root-builder.js | 16 +- lib/context/trace/async-span-chunk-builder.js | 26 +- lib/context/trace/call-stack.js | 25 +- lib/context/trace/child-trace-builder.js | 35 +- lib/context/trace/disable-async-id.js | 16 + lib/context/trace/disable-child-trace.js | 37 + lib/context/trace/id-generator.js | 12 + lib/context/trace/long-id-generator.js | 3 +- lib/context/trace/span-chunk2.js | 43 + lib/context/trace/span-event-builder.js | 74 +- lib/context/trace/span-event-recorder2.js | 60 +- lib/context/trace/span-recorder2.js | 10 +- lib/context/trace/span-repository.js | 47 +- lib/context/trace/trace-id-builder.js | 32 +- lib/context/trace/trace-root.js | 58 ++ lib/context/trace/trace-sampler.js | 16 +- lib/context/trace/trace2.js | 45 +- lib/data/dto/agent-info.js | 4 + .../callback-interceptor-runner.js | 16 +- lib/instrumentation/http-shared.js | 37 +- .../http/http-outgoing-request-header.js | 21 +- .../http/http-request-trace-builder.js | 35 +- lib/instrumentation/http/pinpoint-header.js | 18 +- .../http/trace-header-builder.js | 29 +- .../instrument-arrow-function.js | 14 +- lib/instrumentation/instrument-method.js | 110 ++- lib/instrumentation/module/bluebird.js | 2 +- .../module/callback-interceptor.js | 4 +- lib/instrumentation/module/express.js | 5 +- .../express/express-route-interceptor.js | 7 +- .../module/express/express-use-interceptor.js | 5 +- lib/instrumentation/module/http.js | 4 +- lib/instrumentation/module/https.js | 4 +- lib/instrumentation/module/ioredis.js | 3 +- .../ioredis-send-command-interceptor.js | 7 +- lib/instrumentation/module/koa-router.js | 3 +- lib/instrumentation/module/mysql.js | 12 +- .../mysql/mysql-cluster-of-interceptor.js | 5 +- .../mysql-create-connection-interceptor.js | 7 +- .../mysql-create-pool-cluster-interceptor.js | 5 +- .../mysql/mysql-create-pool-interceptor.js | 5 +- .../mysql/mysql-get-connection-interceptor.js | 5 +- lib/instrumentation/module/mysql2.js | 12 +- lib/instrumentation/module/redis.js | 5 +- ...redis-internal-send-command-interceptor.js | 5 +- test/client/data-sender.test.js | 19 +- ...rpc-data-sender-client-side-stream.test.js | 92 +- test/client/grpc-data-sender.test.js | 889 ++++++------------ test/client/grpc-fixture.js | 5 + test/client/mock-grpc-data-sender.js | 13 +- test/context/callstack.test.js | 84 +- test/context/trace-context.test.js | 44 +- test/fixture.js | 25 +- test/fixtures/mock-data-sender.js | 65 ++ .../context/nested-async-trace.test.js | 106 +-- .../fix-async-call-stack.test.js | 17 +- test/instrumentation/module/complex.test.js | 12 +- test/instrumentation/module/express.test.js | 136 +-- test/instrumentation/module/fix-redis.test.js | 68 +- test/instrumentation/module/http.test.js | 9 +- test/instrumentation/module/koa.test.js | 12 +- test/instrumentation/module/mysql-uid.test.js | 8 +- test/instrumentation/module/mysql.test.js | 104 +- test/instrumentation/module/mysql2.test.js | 180 ++-- test/instrumentation/module/redis.test.js | 145 +-- .../pinpoint-http-header.test.js | 78 +- .../request-header-utils.test.js | 85 +- test/stats/active-trace.test.js | 4 +- test/support/agent-singleton-mock.js | 64 +- test/support/data-sender-mock.js | 15 +- test/utils/ant-path-matcher.test.js | 6 +- 83 files changed, 1866 insertions(+), 1590 deletions(-) create mode 100644 lib/context/trace/disable-async-id.js create mode 100644 lib/context/trace/disable-child-trace.js create mode 100644 lib/context/trace/trace-root.js create mode 100644 test/fixtures/mock-data-sender.js diff --git a/lib/agent.js b/lib/agent.js index 26d2ba9d..ea2606d7 100644 --- a/lib/agent.js +++ b/lib/agent.js @@ -67,7 +67,7 @@ class Agent { } createTraceObject(requestData) { - return this.traceContext.makeTrace(requestData) + return this.traceContext.newTraceObject2() } currentTraceObject() { @@ -79,7 +79,15 @@ class Agent { } createAgentInfo(config, agentStartTime) { - return AgentInfo.create(config, agentStartTime) + return AgentInfo.create(config, '' + agentStartTime) + } + + getAgentInfo() { + return this.agentInfo + } + + getTraceContext() { + return this.traceContext } startSchedule(agentId, agentStartTime) { @@ -91,6 +99,11 @@ class Agent { } this.pingScheduler = new PinScheduler(this.dataSender) } + + shutdown() { + this.mainScheduler?.stop() + this.pingScheduler?.stop() + } } module.exports = Agent diff --git a/lib/client/data-sender-factory.js b/lib/client/data-sender-factory.js index 44955111..d27a5e11 100644 --- a/lib/client/data-sender-factory.js +++ b/lib/client/data-sender-factory.js @@ -9,9 +9,8 @@ const GrpcDataSender = require('./grpc-data-sender') const DataSender = require('./data-sender') -let dataSender const create = (config, agentInfo) => { - dataSender = new DataSender(config, new GrpcDataSender( + const dataSender = new DataSender(config, new GrpcDataSender( config.collectorIp, config.collectorTcpPort, config.collectorStatPort, @@ -22,11 +21,6 @@ const create = (config, agentInfo) => { return dataSender } -const setDataSender = (sender) => { - dataSender = sender -} - module.exports = { create, - setDataSender } diff --git a/lib/client/data-sender.js b/lib/client/data-sender.js index 1cd8a8bb..cb8dd7f8 100644 --- a/lib/client/data-sender.js +++ b/lib/client/data-sender.js @@ -17,6 +17,7 @@ const SqlUidMetaData = require('./sql-uid-meta-data') class DataSender { constructor(config, dataSender) { + this.config = config this.enabledDataSending = config.enabledDataSending this.dataSender = dataSender } @@ -46,8 +47,12 @@ class DataSender { this.dataSender.sendStringMetaInfo(data) } else if (data instanceof Span) { this.dataSender.sendSpan(data) + } else if (data?.isSpan?.()) { + this.dataSender.sendSpan(data) } else if (data instanceof SpanChunk) { this.dataSender.sendSpanChunk(data) + } else if (data?.isAsyncSpanChunk?.()) { + this.dataSender.sendSpanChunk(data) } else if (data instanceof SqlMetaData) { this.dataSender.sendSqlMetaInfo(data) } else if (data instanceof SqlUidMetaData) { @@ -75,7 +80,7 @@ class DataSender { // TODO Remove it after implementing grpc sendActiveThreadCountRes() { - + } } diff --git a/lib/client/grpc-data-sender.js b/lib/client/grpc-data-sender.js index c4b85efa..40c66b93 100644 --- a/lib/client/grpc-data-sender.js +++ b/lib/client/grpc-data-sender.js @@ -316,7 +316,7 @@ class GrpcDataSender { sendSpan(span) { try { - const pSpan = span.spanMessage + const pSpan = span.toProtocolBuffer() if (log.isDebug()) { log.debug(`sendSpan pSpan: ${pSpan}`) } @@ -330,7 +330,7 @@ class GrpcDataSender { sendSpanChunk(spanChunk) { try { - const pSpanChunk = spanChunk.spanMessage + const pSpanChunk = spanChunk.toProtocolBuffer() if (log.isDebug()) { log.debug(`sendSpanChunk spanChunk: ${JSON.stringify(spanChunk)}`) } diff --git a/lib/context/async-id.js b/lib/context/async-id.js index 20e3df42..517938a0 100644 --- a/lib/context/async-id.js +++ b/lib/context/async-id.js @@ -7,6 +7,7 @@ 'use strict' const SequenceGenerator = require('./sequence-generator') +const spanMessages = require('../data/v1/Span_pb') // ref: DefaultAsyncId.java class AsyncId { @@ -43,11 +44,22 @@ class AsyncId { sequenceNextLocalAsyncId() { if (this === AsyncId.nonAsyncId) { - return this.nextLocalAsyncId() + return this.nextLocalAsyncId() } return new AsyncId(this.asyncId, this.sequence + 1) } + + toProtocolBuffer() { + const pLocalAsyncId = new spanMessages.PLocalAsyncId() + pLocalAsyncId.setAsyncid(this.getAsyncId()) + pLocalAsyncId.setSequence(this.getSequence()) + return pLocalAsyncId + } + + tosString() { + return `AsyncId(asyncId=${this.asyncId}, sequence=${this.sequence})` + } } module.exports = AsyncId \ No newline at end of file diff --git a/lib/context/disable-span-event-recorder.js b/lib/context/disable-span-event-recorder.js index adf15534..de831022 100644 --- a/lib/context/disable-span-event-recorder.js +++ b/lib/context/disable-span-event-recorder.js @@ -6,6 +6,8 @@ 'use strict' +const disableAsyncId = require('./trace/disable-async-id') + class DisableSpanEventRecorder { constructor() { this.nextAsyncId = null @@ -59,7 +61,8 @@ class DisableSpanEventRecorder { this.ended = true } - getLocalAsyncId() { + getNextAsyncId() { + return disableAsyncId } } diff --git a/lib/context/disable-span-recorder.js b/lib/context/disable-span-recorder.js index b8c9dc73..8899d924 100644 --- a/lib/context/disable-span-recorder.js +++ b/lib/context/disable-span-recorder.js @@ -21,9 +21,13 @@ class DisableSpanRecorder { recordEndPoint() {} - recordRemoteAddr() {} + recordRemoteAddress() {} recordException() {} + + recordAcceptorHost() {} + + recordParentApplication() {} } module.exports = DisableSpanRecorder \ No newline at end of file diff --git a/lib/context/disable-trace.js b/lib/context/disable-trace.js index c94fcc54..dde61730 100644 --- a/lib/context/disable-trace.js +++ b/lib/context/disable-trace.js @@ -16,9 +16,6 @@ class DisableTrace { this.spanRecorder = new DisableSpanRecorder() } - getTraceRoot() { - return this.traceRoot - } traceBlockBegin() { return new DisableSpanEventRecorder() @@ -26,15 +23,16 @@ class DisableTrace { traceBlockEnd() {} - completeSpanEvent() { + getSpanRecorder() { + return this.spanRecorder } - canSampled() { - return false + getTraceRoot() { + return this.traceRoot } - getStartTime() { - return 0 + canSampled() { + return false } close() { diff --git a/lib/context/remote-trace-root-builder.js b/lib/context/remote-trace-root-builder.js index 1f535b4f..a65a6294 100644 --- a/lib/context/remote-trace-root-builder.js +++ b/lib/context/remote-trace-root-builder.js @@ -6,17 +6,13 @@ 'use strict' -const TraceRootBuilder = require('./trace-root-builder') +const TraceRoot = require('./trace/trace-root') const TraceIdBuilder = require('./trace/trace-id-builder') -class RemoteTraceRoot { - constructor(traceId, traceRoot) { +class RemoteTraceRoot extends TraceRoot { + constructor(traceId, agentId, transactionId) { + super(agentId, Date.now(), transactionId) this.traceId = traceId - this.traceRoot = traceRoot - } - - getTraceStartTime() { - return this.traceRoot.getTraceStartTime() } isSampled() { @@ -26,6 +22,10 @@ class RemoteTraceRoot { getTraceId() { return this.traceId } + + toString() { + return `RemoteTraceRoot{traceId=${this.traceId.toString()}, ${super.toString()}}` + } } class RemoteTraceRootBuilder { @@ -46,11 +46,11 @@ class RemoteTraceRootBuilder { build() { const agentId = this.agentInfo.getAgentId() if (this.isNewTraceRoot()) { - const traceId = new TraceIdBuilder(this.agentInfo, this.transactionId).build() - return new RemoteTraceRoot(traceId, new TraceRootBuilder(agentId, this.transactionId).build()) + const traceId = new TraceIdBuilder(this.agentInfo.getAgentId(), this.agentInfo.getAgentStartTime(), this.transactionId).build() + return new RemoteTraceRoot(traceId, agentId, this.transactionId) } - return new RemoteTraceRoot(this.traceId, new TraceRootBuilder(agentId, this.transactionId).build()) + return new RemoteTraceRoot(this.traceId, agentId, this.transactionId) } isNewTraceRoot() { diff --git a/lib/context/span-builder.js b/lib/context/span-builder.js index fa72778d..3e1d94b3 100644 --- a/lib/context/span-builder.js +++ b/lib/context/span-builder.js @@ -6,6 +6,7 @@ 'use strict' +const spanMessages = require('../data/v1/Span_pb') class Span { constructor(traceRoot) { this.traceRoot = traceRoot @@ -14,6 +15,57 @@ class Span { isSpan() { return true } + + toProtocolBuffer() { + const pSpanMessage = new spanMessages.PSpanMessage() + const pSpan = new spanMessages.PSpan() + pSpan.setVersion(1) + + const pTransactionId = this.traceRoot.getTraceId().toProtocolBuffer() + pSpan.setTransactionid(pTransactionId) + + pSpan.setSpanid(this.traceRoot.getTraceId().getSpanId()) + pSpan.setParentspanid(this.traceRoot.getTraceId().getParentSpanId()) + pSpan.setStarttime(this.startTime) + pSpan.setElapsed(this.elapsedTime) + pSpan.setApiid(this.apiId) + pSpan.setServicetype(this.serviceType) + + const pAcceptEvent = new spanMessages.PAcceptEvent() + pAcceptEvent.setRpc(this.rpc) + pAcceptEvent.setEndpoint(this.endPoint ?? 'UNKNOWN') + pAcceptEvent.setRemoteaddr(this.remoteAddress ?? 'UNKNOWN') + + const pParentInfo = new spanMessages.PParentInfo() + if (this.parentApplicationType) { + pParentInfo.setParentapplicationtype(this.parentApplicationType) + } + if (this.parentApplicationName) { + pParentInfo.setParentapplicationname(this.parentApplicationName) + } + if (this.acceptorHost) { + pParentInfo.setAcceptorhost(this.acceptorHost) + } + pAcceptEvent.setParentinfo(pParentInfo) + pSpan.setAcceptevent(pAcceptEvent) + + pSpan.setFlag(this.traceRoot.getTraceId().getFlags()) + + if (this.traceRoot.hasErrorCode()) { + pSpan.setErr(this.traceRoot.getShared().getErrorCode()) + } + + if (this.applicationServiceType) { + pSpan.setApplicationservicetype(this.applicationServiceType) + } + // TODO: SpanMessageMapperImpl.java: spanTraceRootSharedLoggingInfo loggingTransactionInfo + + this.spanEventList.forEach(spanEvent => pSpan.addSpanevent(spanEvent.toProtocolBuffer())) + this.annotations.forEach(annotation => pSpan.addAnnotation(annotation.pAnnotation())) + + pSpanMessage.setSpan(pSpan) + return pSpanMessage + } } class SpanBuilder { @@ -23,6 +75,15 @@ class SpanBuilder { this.startTime = traceRoot.getTraceStartTime() } + setServiceType(serviceType) { + this.serviceType = serviceType + return this + } + + getStartTime() { + return this.startTime + } + setApiId(apiId) { this.apiId = apiId return this @@ -72,9 +133,26 @@ class SpanBuilder { return this.traceRoot } + setSpanEventList(spanEventList) { + this.spanEventList = spanEventList + return this + } + + setApplicationServiceType(applicationServiceType) { + this.applicationServiceType = applicationServiceType + return this + } + + markAfterTime() { + this.elapsedTime = Date.now() - this.startTime + return this + } + build() { const span = new Span(this.traceRoot) - this.startTime = this.startTime || Date.now() + span.serviceType = this.serviceType + span.startTime = this.startTime || Date.now() + span.elapsedTime = this.elapsedTime span.apiId = this.apiId span.rpc = this.rpc span.endPoint = this.endPoint @@ -84,6 +162,8 @@ class SpanBuilder { span.acceptorHost = this.acceptorHost span.parentApplicationName = this.parentApplicationName span.parentApplicationType = this.parentApplicationType + span.spanEventList = this.spanEventList ?? [] + span.applicationServiceType = this.applicationServiceType return span } } diff --git a/lib/context/span-chunk-builder.js b/lib/context/span-chunk-builder.js index a450c4cf..9643472d 100644 --- a/lib/context/span-chunk-builder.js +++ b/lib/context/span-chunk-builder.js @@ -13,8 +13,25 @@ class SpanChunkBuilder { this.traceRoot = traceRoot } + setKeyTime(keyTime) { + this.keyTime = keyTime + return this + } + + setApplicationServiceType(applicationServiceType) { + this.applicationServiceType = applicationServiceType + return this + } + build(spanEventList) { - return new SpanChunk(this.traceRoot, spanEventList) + const spanChunk = new SpanChunk(this.traceRoot, spanEventList) + spanChunk.keyTime = this.keyTime + spanChunk.applicationServiceType = this.applicationServiceType + return spanChunk + } + + toString() { + return `SpanChunkBuilder(traceRoot=${this.traceRoot}, keyTime=${this.keyTime})` } } diff --git a/lib/context/trace-context.js b/lib/context/trace-context.js index 7dcd24d6..913e2a07 100644 --- a/lib/context/trace-context.js +++ b/lib/context/trace-context.js @@ -22,6 +22,8 @@ const SpanRepository = require('./trace/span-repository') const Trace2 = require('./trace/trace2') const AsyncSpanChunkBuilder = require('./trace/async-span-chunk-builder') const ChildTraceBuilder = require('./trace/child-trace-builder') +const DisableChildTrace = require('./trace/disable-child-trace') +const disableAsyncId = require('./trace/disable-async-id') class TraceContext { constructor(agentInfo, dataSender, config) { @@ -79,9 +81,6 @@ class TraceContext { return } try { - if (trace.spanRecorder && trace.spanRecorder.span && typeof trace.spanRecorder.span.markElapsedTime === 'function') { - trace.spanRecorder.span.markElapsedTime() - } trace.close() // activeTrace.remove(trace) } catch (e) { @@ -128,9 +127,14 @@ class TraceContext { return this.newLocalTrace(traceRoot) } + return this.newTrace(traceRoot) + } + + // newTraceObject method in DefaultBaseTraceFactory.java + newTrace(traceRoot) { const spanBuilder = new SpanBuilder(traceRoot) const spanChunkBuilder = new SpanChunkBuilder(traceRoot) - const repository = new SpanRepository(spanChunkBuilder, this.dataSender) + const repository = new SpanRepository(spanChunkBuilder, this.dataSender, this.agentInfo) return new Trace2(spanBuilder, repository) } @@ -138,10 +142,25 @@ class TraceContext { // DefaultBaseTraceFactory.java: continueAsyncContextTraceObject // AsyncContextSpanEventEndPointApiAwareInterceptor.java : before continueAsyncContextTraceObject(traceRoot, localAsyncId) { + if (localAsyncId === disableAsyncId) { + return this.continueDisableAsyncContextTraceObject(traceRoot) + } + const spanChunkBuilder = new AsyncSpanChunkBuilder(traceRoot, localAsyncId) - const repository = new SpanRepository(spanChunkBuilder, this.dataSender) + const repository = new SpanRepository(spanChunkBuilder, this.dataSender, this.agentInfo) return new ChildTraceBuilder(traceRoot, repository, localAsyncId) } + + // DefaultBaseTraceFactory.java: continueDisableAsyncContextTraceObject + continueDisableAsyncContextTraceObject(traceRoot) { + return new DisableChildTrace(traceRoot) + } + + // DefaultBaseTraceFactory.java: continueTraceObject + continueTraceObject2(traceId) { + const traceRoot = this.traceSampler.makeContinueTraceRoot(traceId) + return this.newTrace(traceRoot) + } } module.exports = TraceContext \ No newline at end of file diff --git a/lib/context/trace-root-builder.js b/lib/context/trace-root-builder.js index 394a9a39..64f36ba4 100644 --- a/lib/context/trace-root-builder.js +++ b/lib/context/trace-root-builder.js @@ -6,21 +6,7 @@ 'use strict' -class TraceRoot { - constructor(agentId, traceStartTime, transactionId) { - this.agentId = agentId - this.traceStartTime = traceStartTime - this.transactionId = transactionId - } - - getTraceStartTime() { - return this.traceStartTime - } - - isSampled() { - return false - } -} +const TraceRoot = require('./trace/trace-root') class TraceRootBuilder { constructor(agentId, localTransactionId) { diff --git a/lib/context/trace/async-span-chunk-builder.js b/lib/context/trace/async-span-chunk-builder.js index 7fea4d79..e8412a3b 100644 --- a/lib/context/trace/async-span-chunk-builder.js +++ b/lib/context/trace/async-span-chunk-builder.js @@ -23,6 +23,13 @@ class AsyncSpanChunk extends SpanChunk { return true } + toProtocolBuffer() { + const pSpanMessage = super.toProtocolBuffer() + const pSpanChunk = pSpanMessage.getSpanchunk() + pSpanChunk.setLocalasyncid(this.localAsyncId.toProtocolBuffer()) + return pSpanMessage + } + toString() { return `AsyncSpanChunk(traceRoot=${this.traceRoot}, spanEventList=${this.spanEventList}, localAsyncId=${this.localAsyncId})` } @@ -35,12 +42,25 @@ class AsyncSpanChunkBuilder { this.localAsyncId = localAsyncId } - build(spanEventList) { - return new AsyncSpanChunk(this.traceRoot, spanEventList, this.asyncId) + setKeyTime(keyTime) { + this.keyTime = keyTime + return this + } + + setApplicationServiceType(applicationServiceType) { + this.applicationServiceType = applicationServiceType + return this + } + + build(spanEventBuilders) { + const asyncSpanChunk = new AsyncSpanChunk(this.traceRoot, spanEventBuilders, this.localAsyncId) + asyncSpanChunk.keyTime = this.keyTime + asyncSpanChunk.applicationServiceType = this.applicationServiceType + return asyncSpanChunk } toString() { - return `AsyncSpanChunkBuilder(traceRoot=${this.traceRoot}, localAsyncId=${this.localAsyncId})` + return `AsyncSpanChunkBuilder(traceRoot=${this.traceRoot}, localAsyncId=${this.localAsyncId}, keyTime=${this.keyTime})` } } diff --git a/lib/context/trace/call-stack.js b/lib/context/trace/call-stack.js index 63169d67..9d0c8c29 100644 --- a/lib/context/trace/call-stack.js +++ b/lib/context/trace/call-stack.js @@ -13,14 +13,15 @@ const SpanEventRecorder = require('./span-event-recorder2') * DefaultCallStack.java in Java agent */ class CallStack { - constructor() { + constructor(traceRoot) { + this.traceRoot = traceRoot this.stack = [] this.sequence = 0 - this.depth = 0 + this.depth = 1 } makeSpanEventRecorder(stackId) { - const recorder = new SpanEventRecorder(SpanEventBuilder.make(stackId)) + const recorder = new SpanEventRecorder(SpanEventBuilder.make(stackId), this.traceRoot) this.push(recorder.getSpanEventBuilder()) return recorder } @@ -31,19 +32,29 @@ class CallStack { } if (spanEventBuilder.needsDepth()) { - spanEventBuilder.setDepth(this.stack.length + 1) + spanEventBuilder.setDepth(this.depth++) } this.stack.push(spanEventBuilder) } // pop in java agent - pop() { - if (this.stack.length < 1) { - return SpanEventBuilder.nullObject() + pop(builder) { + const index = this.stack.findIndex(item => item === builder) + if (index < 0) { + return + } + + this.depth-- + if (index < this.stack.length - 1) { + return this.stack.splice(index, 1)[0] } return this.stack.pop() } + + getByStackId(stackId) { + return this.stack.find(item => item.stackId === stackId) + } } module.exports = CallStack \ No newline at end of file diff --git a/lib/context/trace/child-trace-builder.js b/lib/context/trace/child-trace-builder.js index 1b58cb3b..7bb462da 100644 --- a/lib/context/trace/child-trace-builder.js +++ b/lib/context/trace/child-trace-builder.js @@ -7,17 +7,11 @@ 'use strict' const SpanEventRecorder = require('./span-event-recorder2') -const Trace = require('./trace2') const TraceRootSpanRecorder = require('./trace-root-span-recorder') const StackId = require('./stack-id') const CallStack = require('./call-stack') - -class ChildTrace extends Trace { - constructor(spanBuilder, repository, localAsyncId) { - super(spanBuilder, repository) - this.localAsyncId = localAsyncId - } -} +const serviceType = require('../../instrumentation/context/async-service-type') +const defaultPredefinedMethodDescriptorRegistry = require('../../constant/default-predefined-method-descriptor-registry') class ChildTraceBuilder { constructor(traceRoot, repository, localAsyncId) { @@ -26,27 +20,33 @@ class ChildTraceBuilder { this.spanRecorder = new TraceRootSpanRecorder(traceRoot) this.localAsyncId = localAsyncId - this.callStack = new CallStack() + this.callStack = new CallStack(traceRoot) this.closed = false - this.traceBlockBegin(StackId.asyncBeginStackId) + const spanEventRecorder = this.traceBlockBegin(StackId.asyncBeginStackId) + spanEventRecorder.recordServiceType(serviceType) + spanEventRecorder.recordApiId(defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.getApiId()) } traceBlockBegin(stackId = StackId.default) { if (this.closed) { - return SpanEventRecorder.nullObject() + return SpanEventRecorder.nullObject(this.traceRoot) } return this.callStack.makeSpanEventRecorder(stackId) } - traceBlockEnd() { + traceBlockEnd(spanEventRecorder) { if (this.closed) { return } - const spanEventBuilder = this.callStack.pop() - spanEventBuilder.markAfterTime() + this.endSpanEventBuilder(spanEventRecorder.getSpanEventBuilder()) + } + + endSpanEventBuilder(builder) { + const spanEventBuilder = this.callStack.pop(builder) + spanEventBuilder?.markAfterTime() this.repository.storeSpanEvent(spanEventBuilder) } @@ -58,8 +58,13 @@ class ChildTraceBuilder { return this.traceRoot.getTraceId() } + canSampled() { + return true + } + close() { - this.traceBlockEnd(StackId.asyncBeginStackId) + const spanEventBuilder = this.callStack.getByStackId(StackId.asyncBeginStackId) + this.endSpanEventBuilder(spanEventBuilder) this.closed = true this.repository.flush() } diff --git a/lib/context/trace/disable-async-id.js b/lib/context/trace/disable-async-id.js new file mode 100644 index 00000000..01d84ba3 --- /dev/null +++ b/lib/context/trace/disable-async-id.js @@ -0,0 +1,16 @@ +/** + * Pinpoint Node.js Agent + * Copyright 2020-present NAVER Corp. + * Apache License v2.0 + */ + +'use strict' + +class DisableAsyncId { + nextLocalAsyncId2() { + return disableAsyncId + } +} + +const disableAsyncId = new DisableAsyncId() +module.exports = disableAsyncId \ No newline at end of file diff --git a/lib/context/trace/disable-child-trace.js b/lib/context/trace/disable-child-trace.js new file mode 100644 index 00000000..10e05610 --- /dev/null +++ b/lib/context/trace/disable-child-trace.js @@ -0,0 +1,37 @@ +/** + * Pinpoint Node.js Agent + * Copyright 2020-present NAVER Corp. + * Apache License v2.0 + */ + +'use strict' + +const DisableSpanEventRecorder = require('../disable-span-event-recorder') +const DisableSpanRecorder = require('../disable-span-recorder') + +class DisableChildTrace { + constructor(traceRoot) { + this.traceRoot = traceRoot + this.spanRecorder = new DisableSpanRecorder() + this.spanEventRecorder = new DisableSpanEventRecorder() + } + + traceBlockBegin() { + return this.spanEventRecorder + } + + traceBlockEnd() {} + + getTraceRoot() { + return this.traceRoot + } + + canSampled() { + return false + } + + close() { + } +} + +module.exports = DisableChildTrace \ No newline at end of file diff --git a/lib/context/trace/id-generator.js b/lib/context/trace/id-generator.js index b220016d..6648fa48 100644 --- a/lib/context/trace/id-generator.js +++ b/lib/context/trace/id-generator.js @@ -29,5 +29,17 @@ module.exports = { }, nextContinuedDisabledId: function () { return continueDisabledId.next(-5) + }, + getTransactionId: function () { + return transactionId + }, + getContinuedTransactionId: function () { + return continuedTransactionId + }, + getDisabledId: function () { + return disabledId + }, + getContinuedDisabledId: function () { + return continueDisabledId } } \ No newline at end of file diff --git a/lib/context/trace/long-id-generator.js b/lib/context/trace/long-id-generator.js index 2c84c5f1..0ea0f336 100644 --- a/lib/context/trace/long-id-generator.js +++ b/lib/context/trace/long-id-generator.js @@ -18,8 +18,9 @@ class LongIdGenerator { if (this.sequence > this.maxValue) { this.sequence = this.initValue } + const returnValue = this.sequence this.sequence = this.sequence + delta - return '' + this.sequence + return '' + returnValue } // for test diff --git a/lib/context/trace/span-chunk2.js b/lib/context/trace/span-chunk2.js index 2830552d..dec8aa85 100644 --- a/lib/context/trace/span-chunk2.js +++ b/lib/context/trace/span-chunk2.js @@ -6,11 +6,54 @@ 'use strict' +const spanMessages = require('../../data/v1/Span_pb') + class SpanChunk { constructor(traceRoot, spanEventList) { this.traceRoot = traceRoot this.spanEventList = spanEventList } + + getTraceRoot() { + return this.traceRoot + } + + toProtocolBuffer() { + const pSpanMessage = new spanMessages.PSpanMessage() + const pSpanChunk = new spanMessages.PSpanChunk() + pSpanChunk.setVersion(1) + + const pTransactionId = this.traceRoot.getTraceId().toProtocolBuffer() + pSpanChunk.setTransactionid(pTransactionId) + + pSpanChunk.setSpanid(this.traceRoot.getTraceId().getSpanId()) + pSpanChunk.setEndpoint(this.endPoint) + + if (this.applicationServiceType) { + pSpanChunk.setApplicationservicetype(this.applicationServiceType) + } + + // GrpcSpanProcessorV2.java: postProcess + if (this.keyTime) { + pSpanChunk.setKeytime(this.keyTime) + } + + this.spanEventList.forEach(spanEvent => { + pSpanChunk.addSpanevent(spanEvent.toProtocolBuffer()) + }) + + pSpanMessage.setSpanchunk(pSpanChunk) + return pSpanMessage + } + + // GrpcSpanProcessorV2.java: getKeyTime + getKeyTime() { + return this.keyTime + } + + toString() { + return `SpanChunk(traceRoot=${this.traceRoot}, spanEventList=${this.spanEventList})` + } } module.exports = SpanChunk \ No newline at end of file diff --git a/lib/context/trace/span-event-builder.js b/lib/context/trace/span-event-builder.js index 1e0dd346..3f4e4b2b 100644 --- a/lib/context/trace/span-event-builder.js +++ b/lib/context/trace/span-event-builder.js @@ -7,19 +7,56 @@ 'use strict' const StackId = require('./stack-id') -const AsyncId = require('../async-id') +const spanMessages = require('../../data/v1/Span_pb') +const IntStringValue = require('../../instrumentation/context/annotation/int-string-value') class SpanEvent { - static nullObject = new SpanEvent(0, 0) - constructor(sequence, depth) { this.sequence = sequence this.depth = depth } + + getStartTime() { + return this.startTime + } + + toProtocolBuffer() { + const pSpanEvent = new spanMessages.PSpanEvent() + pSpanEvent.setSequence(this.sequence) + pSpanEvent.setDepth(this.depth) + pSpanEvent.setStartelapsed(this.startElapsedTime) + pSpanEvent.setEndelapsed(this.elapsedTime) + pSpanEvent.setServicetype(this.serviceType) + pSpanEvent.setApiid(this.apiId) + + if (typeof this.exceptionInfo?.pAnnotation === 'function') { + pSpanEvent.setExceptioninfo(this.exceptionInfo.pAnnotation()) + } + + const pNextEvent = new spanMessages.PNextEvent() + const pMessageEvent = new spanMessages.PMessageEvent() + pMessageEvent.setNextspanid(this.nextSpanId) + pMessageEvent.setEndpoint(this.endPoint) + pMessageEvent.setDestinationid(this.destinationId) + pNextEvent.setMessageevent(pMessageEvent) + pSpanEvent.setNextevent(pNextEvent) + + if (this.asyncId) { + pSpanEvent.setAsyncevent(this.asyncId.getAsyncId()) + } + + this.annotations.forEach(annotation => { + pSpanEvent.addAnnotation(annotation.pAnnotation()) + }) + + return pSpanEvent + } } class SpanEventBuilder { + static comparator = (a, b) => a.sequence - b.sequence + // DefaultCallStack.java: push sequence 0 start value, depth 1 start value static nullObject() { return new SpanEventBuilder(StackId.nullObject) @@ -76,11 +113,24 @@ class SpanEventBuilder { return this } + getStartTime() { + return this.startTime + } + setServiceType(serviceType) { this.serviceType = serviceType return this } + getStartElapsedTime() { + return this.startElapsedTime + } + + setStartElapsedTime(startElapsedTime) { + this.startElapsedTime = startElapsedTime + return this + } + addAnnotation(annotation) { this.annotations.push(annotation) return this @@ -93,9 +143,6 @@ class SpanEventBuilder { // WrappedSpanEventRecorder.java: getNextAsyncId getAsyncId() { - if (!this.asyncId) { - this.asyncId = AsyncId.make() - } return this.asyncId } @@ -124,8 +171,18 @@ class SpanEventBuilder { return this } + setEndPoint(endPoint) { + this.endPoint = endPoint + return this + } + + setExceptionInfo(id, message) { + this.exceptionInfo = new IntStringValue(id, message) + return this + } + build() { - if (this.stackId === nullObjectStackId) { + if (this.stackId === StackId.nullObject) { return SpanEvent.nullObject } @@ -137,11 +194,14 @@ class SpanEventBuilder { spanEvent.startTime = this.startTime spanEvent.serviceType = this.serviceType spanEvent.annotations = this.annotations + spanEvent.startElapsedTime = this.startElapsedTime spanEvent.apiId = this.apiId spanEvent.asyncId = this.asyncId spanEvent.elapsedTime = this.elapsedTime spanEvent.nextSpanId = this.nextSpanId spanEvent.destinationId = this.destinationId + spanEvent.endPoint = this.endPoint + spanEvent.exceptionInfo = this.exceptionInfo return spanEvent } } diff --git a/lib/context/trace/span-event-recorder2.js b/lib/context/trace/span-event-recorder2.js index 4699ecc4..a4653512 100644 --- a/lib/context/trace/span-event-recorder2.js +++ b/lib/context/trace/span-event-recorder2.js @@ -11,14 +11,18 @@ const Annotations = require('../../instrumentation/context/annotation/annotation const SpanEventBuilder = require('./span-event-builder') const log = require('../../utils/logger') const AnnotationKeyUtils = require('../annotation-key-utils') +const sqlMetaDataService = require('../../instrumentation/sql/sql-metadata-service') +const stringMetaService = require('../string-meta-service') +const AsyncId = require('../async-id') class SpanEventRecorder { - static nullObject() { - return new SpanEventRecorder(SpanEventBuilder.nullObject()) + static nullObject(traceRoot) { + return new SpanEventRecorder(SpanEventBuilder.nullObject(), traceRoot) } - constructor(spanEventBuilder) { + constructor(spanEventBuilder, traceRoot) { this.spanEventBuilder = spanEventBuilder + this.traceRoot = traceRoot } getSpanEventBuilder() { @@ -49,8 +53,13 @@ class SpanEventRecorder { this.spanEventBuilder.setApiId(apiId) } - recordNextAsyncId() { - return this.spanEventBuilder.getAsyncId() + getNextAsyncId() { + let nextAsyncId = this.spanEventBuilder.getAsyncId() + if (!nextAsyncId) { + nextAsyncId = AsyncId.make() + this.spanEventBuilder.setAsyncId(nextAsyncId) + } + return nextAsyncId } recordNextSpanId(nextSpanId) { @@ -94,6 +103,47 @@ class SpanEventRecorder { log.error(`recordArgs error ${error}`) } } + + recordEndPoint(endPoint) { + this.spanEventBuilder.setEndPoint(endPoint) + } + + recordException(error, markError) { + if (typeof error?.name !== 'string') { + return + } + + const metaInfo = stringMetaService.get(error.name || 'Error') + const errorMessage = error && typeof error.stack === 'string' ? error.stack.split(/\r?\n/, 2).join('') : '' + this.spanEventBuilder.setExceptionInfo(metaInfo.stringId, errorMessage) + if (markError) { + const shared = this.traceRoot.getShared() + shared.maskErrorCode(1) + } + } + + recordSqlInfo(sql, bindString) { + if (typeof sql !== 'string' || this.spanEvent === null) { + return + } + + const parsingResult = sqlMetaDataService.cacheSql(sql) + this.recordSqlParsingResult(parsingResult, bindString) + return parsingResult + } + + recordSqlParsingResult(parsingResult, bindString) { + if (!parsingResult) { + return + } + + if (typeof bindString !== 'string') { + bindString = null + } + + const annotation = parsingResult.newSqlAnnotation(bindString) + this.spanEventBuilder.addAnnotation(annotation) + } } module.exports = SpanEventRecorder \ No newline at end of file diff --git a/lib/context/trace/span-recorder2.js b/lib/context/trace/span-recorder2.js index 3219d3bc..a4aafcc9 100644 --- a/lib/context/trace/span-recorder2.js +++ b/lib/context/trace/span-recorder2.js @@ -16,15 +16,17 @@ class SpanRecorder { } recordServiceType(code) { - if (code) { - this.spanBuilder.setServiceType(code) + if (typeof code.getCode !== 'function') { + return } + this.spanBuilder.setServiceType(code.getCode()) } recordApiId(apiId) { - if (apiId) { - this.spanBuilder.setApiId(apiId) + if (typeof apiId !== 'number') { + return } + this.spanBuilder.setApiId(apiId) } recordApi(methodDescriptor) { diff --git a/lib/context/trace/span-repository.js b/lib/context/trace/span-repository.js index 8a2164cb..840f74c4 100644 --- a/lib/context/trace/span-repository.js +++ b/lib/context/trace/span-repository.js @@ -6,14 +6,17 @@ 'use strict' +const SpanEventBuilder = require('./span-event-builder') + // bufferSize in DefaultContextConfig.java const bufferSize = 20 // BufferedStorage.java class SpanRepository { - constructor(spanChunkBuilder, dataSender) { + constructor(spanChunkBuilder, dataSender, agentInfo) { this.spanChunkBuilder = spanChunkBuilder this.dataSender = dataSender this.buffer = [] + this.agentInfo = agentInfo } storeSpanEvent(spanEvent) { @@ -39,16 +42,28 @@ class SpanRepository { return copy } - sendSpanChunk(spanEvents) { - const spanChunk = this.spanChunkBuilder.build(spanEvents) - this.dataSender.send(spanChunk) + sendSpanChunk(spanEventBuilders) { + if (spanEventBuilders.length < 1) { + return + } + // GrpcSpanProcessorV2.java: postProcess(SpanChunk spanChunk, pSpanChunk) + const sortedSpanEventBuilders = calculateStartElapsedTime(spanEventBuilders) + const spanEvents = sortedSpanEventBuilders.map(builder => builder.build()) + this.spanChunkBuilder.setKeyTime(spanEvents[0]?.getStartTime()) + this.spanChunkBuilder.setApplicationServiceType(this.agentInfo.getApplicationServiceType()) + this.dataSender.send(this.spanChunkBuilder.build(spanEvents)) } - storeSpan(span) { - if (span) { - span.spanEventList = this.bufferDrain() + storeSpan(spanBuilder) { + if (!spanBuilder) { + return } - this.dataSender.send(span) + // GrpcSpanProcessorV2.java: postProcess(Span span, pSpan) + const sortedSpanEventBuilders = calculateStartElapsedTime(this.bufferDrain(), spanBuilder.getStartTime()) + const spanEvents = sortedSpanEventBuilders.map(builder => builder.build()) + spanBuilder.setSpanEventList(spanEvents) + spanBuilder.setApplicationServiceType(this.agentInfo.getApplicationServiceType()) + this.dataSender.send(spanBuilder.build()) } flush() { @@ -57,4 +72,18 @@ class SpanRepository { } } -module.exports = SpanRepository \ No newline at end of file +module.exports = SpanRepository + +function calculateStartElapsedTime(spanEvents, keyTime) { + if (spanEvents.length === 0) { + return spanEvents + } + + const sorted = Array.from(spanEvents).sort(SpanEventBuilder.comparator) + sorted.reduce((previousStartTime, spanEventBuilder) => { + const startElapsedTime = spanEventBuilder.getStartTime() - previousStartTime + spanEventBuilder.setStartElapsedTime(startElapsedTime) + return spanEventBuilder.getStartTime() + }, keyTime ?? sorted[0].getStartTime()) + return sorted +} diff --git a/lib/context/trace/trace-id-builder.js b/lib/context/trace/trace-id-builder.js index a6dc5369..b0ffca56 100644 --- a/lib/context/trace/trace-id-builder.js +++ b/lib/context/trace/trace-id-builder.js @@ -7,6 +7,7 @@ 'use strict' const spanId = require('../span-id') +const spanMessages = require('../../data/v1/Span_pb') const delimiter = '^' // DefaultTraceId.java @@ -60,17 +61,31 @@ class TraceId { toStringDelimiterFormatted() { return [this.agentId, this.agentStartTime, this.transactionId].join(delimiter) } + + toProtocolBuffer() { + const pTransactionId = new spanMessages.PTransactionId() + pTransactionId.setAgentid(this.agentId) + pTransactionId.setAgentstarttime(this.agentStartTime) + pTransactionId.setSequence(this.transactionId) + return pTransactionId + } } class TraceIdBuilder { - constructor(agentInfo, transactionId) { - this.agentInfo = agentInfo + constructor(agentId, agentStartTime, transactionId) { + this.agentId = agentId + this.agentStartTime = agentStartTime this.transactionId = transactionId this.parentSpanId = spanId.nullSpanId() + this.flags = '0' } - make(transactionId) { - return new TraceIdBuilder(this.agentInfo, transactionId) + static makeByHeader(traceIdHeader) { + const headers = traceIdHeader.split(delimiter) + if (headers.length !== 3) { + return + } + return new TraceIdBuilder(headers[0], headers[1], headers[2]) } setSpanId(spanId) { @@ -83,9 +98,14 @@ class TraceIdBuilder { return this } + setFlags(flags) { + this.flags = flags + return this + } + build() { - return new TraceId(this.agentInfo.getAgentId(), this.agentInfo.getAgentStartTime() - , this.transactionId, this.parentSpanId, this.spanId ?? spanId.newSpanId(), 0) + return new TraceId(this.agentId, this.agentStartTime + , this.transactionId, this.parentSpanId, this.spanId ?? spanId.newSpanId(), this.flags) } } diff --git a/lib/context/trace/trace-root.js b/lib/context/trace/trace-root.js new file mode 100644 index 00000000..d65e4172 --- /dev/null +++ b/lib/context/trace/trace-root.js @@ -0,0 +1,58 @@ +/** + * Pinpoint Node.js Agent + * Copyright 2020-present NAVER Corp. + * Apache License v2.0 + */ + +'use strict' + +class TraceRoot { + constructor(agentId, traceStartTime, transactionId) { + this.agentId = agentId + this.traceStartTime = traceStartTime + this.transactionId = transactionId + } + + getAgentId() { + return this.agentId + } + + getTraceStartTime() { + return this.traceStartTime + } + + getTransactionId() { + return this.transactionId + } + + isSampled() { + return false + } + + getShared() { + if (!this.shared) { + this.shared = new Shared() + } + return this.shared + } + + hasErrorCode() { + return this.shared?.getErrorCode?.() + } + + toString() { + return `TraceRoot(agentId=${this.agentId}, traceStartTime=${this.traceStartTime}, transactionId=${this.transactionId})` + } +} + +class Shared { + maskErrorCode(errorCode) { + this.errorCode = errorCode + } + + getErrorCode() { + return this.errorCode + } +} + +module.exports = TraceRoot \ No newline at end of file diff --git a/lib/context/trace/trace-sampler.js b/lib/context/trace/trace-sampler.js index 7c28531b..1a299f86 100644 --- a/lib/context/trace/trace-sampler.js +++ b/lib/context/trace/trace-sampler.js @@ -61,6 +61,9 @@ class TraceSampler { if (config.sampleRate === 1) { return true } + if (config.sampleRate < 1) { + return false + } return this.counter.getAndIncrement() % config.sampleRate === 0 } } @@ -70,21 +73,28 @@ class TraceSampler { makeContinueDisableTraceRoot() { const nextId = this.continueDisableState.nextId() - return this.localTraceRootBuilder.build(nextId) + return this.localTraceRootBuilder.make(nextId).build() } makeNewTraceRoot(urlPath) { const state = this.newState(urlPath) if (!state.isSampled()) { - return this.localTraceRootBuilder.build(state.nextId()) + return this.localTraceRootBuilder.make(state.nextId()).build() } - return new RemoteTraceRootBuilder(this.agentInfo).build(state.nextId()) + return new RemoteTraceRootBuilder(this.agentInfo, state.nextId()).build() } getContinueSuccessState() { return this.continueSuccessState } + makeContinueTraceRoot(traceId) { + const nextId = this.continueSuccessState.nextId() + const builder = new RemoteTraceRootBuilder(this.agentInfo, nextId) + builder.setTraceId(traceId) + return builder.build() + } + getContinueDisabledState() { return this.continueDisableState } diff --git a/lib/context/trace/trace2.js b/lib/context/trace/trace2.js index e3ee610b..5dd8cd33 100644 --- a/lib/context/trace/trace2.js +++ b/lib/context/trace/trace2.js @@ -24,70 +24,53 @@ class Trace { this.repository = repository this.spanRecorder = new SpanRecorder(spanBuilder) - this.callStack = new CallStack() + this.callStack = new CallStack(spanBuilder.getTraceRoot()) this.closed = false } // DefaultTrace.java: traceBlockEnd traceBlockBegin(stackId = StackId.default) { if (this.closed) { - return SpanEventRecorder.nullObject() + return SpanEventRecorder.nullObject(this.spanBuilder.getTraceRoot()) } - // GrpcSpanProcessorV2: postProcess return this.callStack.makeSpanEventRecorder(stackId) } - traceBlockEnd() { + traceBlockEnd(spanEventRecorder) { if (this.closed) { return } - const spanEventBuilder = this.callStack.pop() - spanEventBuilder.markAfterTime() - this.repository.storeSpanEvent(spanEventBuilder) - } - - recordServiceType(serviceType) { - this.spanRecorder.recordServiceType(serviceType) - } - - recordApi(methodDescriptor) { - this.spanRecorder.recordApi(methodDescriptor) - } - - recordRpc(pathName) { - this.spanRecorder.recordRpc(pathName) + this.endSpanEventBuilder(spanEventRecorder.getSpanEventBuilder()) } - recordEndPoint(endPoint) { - this.spanRecorder.recordEndPoint(endPoint) + endSpanEventBuilder(builder) { + const spanEventBuilder = this.callStack.pop(builder) + spanEventBuilder?.markAfterTime() + this.repository.storeSpanEvent(spanEventBuilder) } - recordRemoteAddress(remoteAddress) { - this.spanRecorder.recordRemoteAddress(remoteAddress) + getSpanRecorder() { + return this.spanRecorder } - recordAcceptorHost(host) { - this.spanRecorder.recordAcceptorHost(host) + getTraceRoot() { + return this.spanBuilder.getTraceRoot() } getTraceId() { return this.spanBuilder.getTraceRoot().getTraceId() } - getTraceRoot() { - return this.spanBuilder.getTraceRoot() - } - canSampled() { return true } close() { - this.traceBlockEnd() this.closed = true - this.repository.storeSpan(this.spanBuilder.build()) + this.spanBuilder.markAfterTime() + this.repository.storeSpan(this.spanBuilder) } } diff --git a/lib/data/dto/agent-info.js b/lib/data/dto/agent-info.js index d0a9d966..328a1e29 100644 --- a/lib/data/dto/agent-info.js +++ b/lib/data/dto/agent-info.js @@ -54,6 +54,10 @@ class AgentInfo { getApplicationName() { return this.applicationName } + + getApplicationServiceType() { + return this.applicationServiceType + } } module.exports = AgentInfo diff --git a/lib/instrumentation/callback-interceptor-runner.js b/lib/instrumentation/callback-interceptor-runner.js index 30d3b63d..91a7e5c2 100644 --- a/lib/instrumentation/callback-interceptor-runner.js +++ b/lib/instrumentation/callback-interceptor-runner.js @@ -7,13 +7,13 @@ 'use strict' const localStorage = require('./context/local-storage') -const TraceBuilder = require('./context/trace-builder') class CallbackInterceptorRunner { - constructor(trace, localAsyncId, hookFunctionArguments) { + constructor(trace, localAsyncId, hookFunctionArguments, traceContext) { this.trace = trace this.localAsyncId = localAsyncId this.original = hookFunctionArguments.getOriginal() + this.traceContext = traceContext } run(wrapper, thisArg, argsArray) { @@ -21,19 +21,19 @@ class CallbackInterceptorRunner { if (!this.trace) { return this.original.apply(thisArg, argsArray) } - + if (!wrapper) { wrapper = {} } - + if (typeof wrapper.prepareBeforeTrace === 'function') { wrapper.prepareBeforeTrace() } - - const asyncTrace = TraceBuilder.valueOfTrace(this.trace).buildAsyncTrace(this.localAsyncId) - return localStorage.run(asyncTrace, () => { + + const childTraceBuilder = this.traceContext.continueAsyncContextTraceObject(this.trace.getTraceRoot(), this.localAsyncId.nextLocalAsyncId2()) + return localStorage.run(childTraceBuilder, () => { const result = this.original.apply(thisArg, argsArray) - asyncTrace.close() + childTraceBuilder.close() return result }) }) diff --git a/lib/instrumentation/http-shared.js b/lib/instrumentation/http-shared.js index e6d0b3dd..3bf25a5b 100644 --- a/lib/instrumentation/http-shared.js +++ b/lib/instrumentation/http-shared.js @@ -39,9 +39,25 @@ exports.instrumentRequest2 = function (agent) { return original.apply(this, arguments) } - const requestTrace = new HttpRequestTraceBuilder(agent.traceContext, req).build() + const requestTrace = new HttpRequestTraceBuilder(agent.getTraceContext(), req).build() const trace = requestTrace.makeTrace() return localStorage.run(trace, () => { + endOfStream(res, function (err) { + const spanRecorder = trace.spanRecorder + if (err) { + const end = res.end + res.end = function () { + const result = end.apply(this, arguments) + spanRecorder.recordAttribute(annotationKey.HTTP_STATUS_CODE, this.statusCode) + agent.completeTraceObject(trace) + return result + } + return + } + + spanRecorder.recordAttribute(annotationKey.HTTP_STATUS_CODE, this.statusCode) + return agent.completeTraceObject(trace) + }) return original.apply(this, arguments) }) } @@ -108,27 +124,31 @@ exports.instrumentRequest = function (agent) { } // HttpMethodBaseExecuteMethodInterceptor.java: before -exports.traceOutgoingRequest2 = function (agent, moduleName) { +exports.traceOutgoingRequest2 = function (agent) { return function (original) { return function () { const req = original.apply(this, arguments) - const requestHeader = new HttpOutgoingRequestHeader(agent.traceContext, req) - requestHeader.writePinpointHeader() + const traceContext = agent.getTraceContext() + const trace = traceContext.currentTraceObject() + if (!trace) { + return req + } - const trace = agent.traceContext.currentTraceObject() - if (!trace?.canSampled()) { + const requestHeader = new HttpOutgoingRequestHeader(agent.getAgentInfo(), req) + if (!trace.canSampled()) { + requestHeader.writeSampledHeaderFalse() return req } const spanEventRecorder = trace.traceBlockBegin() spanEventRecorder.recordServiceType(ServiceType.asyncHttpClientInternal) spanEventRecorder.recordApiDesc('http.request') - const asyncId = spanEventRecorder.recordNextAsyncId() + const asyncId = spanEventRecorder.getNextAsyncId() trace.traceBlockEnd(spanEventRecorder) // DefaultAsyncContext.java: newAsyncContextTrace - const childTraceBuilder = agent.traceContext.continueAsyncContextTraceObject(trace.getTraceRoot(), asyncId.nextLocalAsyncId2()) + const childTraceBuilder = traceContext.continueAsyncContextTraceObject(trace.getTraceRoot(), asyncId.nextLocalAsyncId2()) const recorder = childTraceBuilder.traceBlockBegin() recorder.recordServiceType(ServiceType.asyncHttpClient) recorder.recordApiDesc(req.method) @@ -137,6 +157,7 @@ exports.traceOutgoingRequest2 = function (agent, moduleName) { const nextId = childTraceBuilder.getTraceId().getNextTraceId() recorder.recordNextSpanId(nextId.getSpanId()) recorder.recordDestinationId(requestHeader.getHost()) + requestHeader.write(nextId) req.on('response', function (res) { // Inspired by: diff --git a/lib/instrumentation/http/http-outgoing-request-header.js b/lib/instrumentation/http/http-outgoing-request-header.js index 4ed7507d..3af0e5e4 100644 --- a/lib/instrumentation/http/http-outgoing-request-header.js +++ b/lib/instrumentation/http/http-outgoing-request-header.js @@ -22,6 +22,7 @@ class HttpClientRequest { } // write(T header, final TraceId traceId, final String host) + // fLucyNetUtil.java: createOptions write(traceId, agentInfo) { this.setHeader(Header.traceId, traceId.toStringDelimiterFormatted()) this.setHeader(Header.spanId, traceId.getSpanId()) @@ -53,8 +54,8 @@ class HttpClientRequest { } class HttpOutgoingRequestHeader { - constructor(context, request) { - this.traceContext = context + constructor(agentInfo, request) { + this.agentInfo = agentInfo this.request = new HttpClientRequest(request) } @@ -66,18 +67,12 @@ class HttpOutgoingRequestHeader { return this.request.getHost() } - writePinpointHeader() { - const trace = this.traceContext.currentTraceObject() - if (!trace) { - return - } - - if (!trace.canSampled()) { - this.request.writeSampledHeaderFalse() - return - } + writeSampledHeaderFalse() { + this.request.writeSampledHeaderFalse() + } - this.request.write(trace.getTraceId(), this.traceContext.getAgentInfo()) + write(nextTraceId) { + this.request.write(nextTraceId, this.agentInfo) } } diff --git a/lib/instrumentation/http/http-request-trace-builder.js b/lib/instrumentation/http/http-request-trace-builder.js index 753af630..3f70e8be 100644 --- a/lib/instrumentation/http/http-request-trace-builder.js +++ b/lib/instrumentation/http/http-request-trace-builder.js @@ -8,7 +8,8 @@ const defaultPredefinedMethodDescriptorRegistry = require('../../constant/default-predefined-method-descriptor-registry') const TraceHeaderBuilder = require('./trace-header-builder') -const ServiceType = require('../../constant/service-type') +const ServiceType = require('../../context/service-type') +const annotationKey = require('../../constant/annotation-key') class HttpRequestTrace { constructor(rpcName, traceFactory) { @@ -24,6 +25,7 @@ class HttpRequestTrace { class IncomingMessageHeaderReader { constructor(request) { this.request = request + this.url = new URL(`http://${process.env.HOST ?? 'localhost'}${this.request.url}`) } getHeader(name) { @@ -35,12 +37,16 @@ class IncomingMessageHeaderReader { } getUrlPathname() { - return new URL(`http://${process.env.HOST ?? 'localhost'}${this.request.url}`).pathname + return this.url.pathname } getRemoteAddress() { return this.getHeader('x-forwarded-for')?.split(',').trim().shift() ?? this.socket?.remoteAddress } + + getQuery() { + return this.url.searchParams?.toString() + } } @@ -63,18 +69,20 @@ class HttpRequestTraceBuilder { if (traceHeader.isNewTrace()) { return new HttpRequestTrace(this.request.getUrlPathname(), () => { const trace = this.traceContext.newTraceObject2() - this.record(trace) + const spanRecorder = trace.getSpanRecorder() + this.record(spanRecorder) return trace }) } return new HttpRequestTrace(this.request.getUrlPathname(), () => { - const trace = this.traceContext.continueTraceObject() - this.record(trace) + const trace = this.traceContext.continueTraceObject2(traceHeader.getTraceId()) + const spanRecorder = trace.getSpanRecorder() + this.record(spanRecorder) // ServerRequestRecorder.java: recordParentInfo - trace.recordAcceptorHost(traceHeader.getHost()) - trace.recordParentApplication(traceHeader.getParentApplicationName(), traceHeader.getParentApplicationType()) + spanRecorder.recordAcceptorHost(traceHeader.getHost()) + spanRecorder.recordParentApplication(traceHeader.getParentApplicationName(), traceHeader.getParentApplicationType()) return trace }) } @@ -84,12 +92,13 @@ class HttpRequestTraceBuilder { // this.cookieRecorder.recordCookie(recorder, request); unsupport features // record serviceType: traceContext.newTraceObject() Trace class constructor // ServletRequestListener.java: createTrace(REQ request) - record(trace) { - trace.recordServiceType(ServiceType.node) - trace.recordApi(defaultPredefinedMethodDescriptorRegistry.nodeServerMethodDescriptor) - trace.recordRpc(this.request.getUrlPathname()) - trace.recordEndPoint(this.request.getHeader('host')) - trace.recordRemoteAddress(this.request.getRemoteAddress()) + record(spanRecorder) { + spanRecorder.recordServiceType(ServiceType.node.getCode()) + spanRecorder.recordApi(defaultPredefinedMethodDescriptorRegistry.nodeServerMethodDescriptor) + spanRecorder.recordRpc(this.request.getUrlPathname()) + spanRecorder.recordEndPoint(this.request.getHeader('host')) + spanRecorder.recordRemoteAddress(this.request.getRemoteAddress()) + spanRecorder.recordAttribute(annotationKey.HTTP_PARAM, this.request.getQuery()) } } diff --git a/lib/instrumentation/http/pinpoint-header.js b/lib/instrumentation/http/pinpoint-header.js index 9dc6cfcd..bf2a21be 100644 --- a/lib/instrumentation/http/pinpoint-header.js +++ b/lib/instrumentation/http/pinpoint-header.js @@ -7,15 +7,15 @@ 'use strict' class Header { - static traceId = 'Pinpoint-TraceID' - static spanId = 'Pinpoint-SpanID' - static parentSpanId = 'Pinpoint-pSpanID' - static sampled = 'Pinpoint-Sampled' - static flags = 'Pinpoint-Flags' - static parentApplicationName = 'Pinpoint-pAppName' - static parentApplicationType = 'Pinpoint-pAppType' - static parentApplicationNamespace = 'Pinpoint-pAppNamespace' - static host = 'Pinpoint-Host' + static traceId = 'Pinpoint-TraceID'.toLowerCase() + static spanId = 'Pinpoint-SpanID'.toLowerCase() + static parentSpanId = 'Pinpoint-pSpanID'.toLowerCase() + static sampled = 'Pinpoint-Sampled'.toLowerCase() + static flags = 'Pinpoint-Flags'.toLowerCase() + static parentApplicationName = 'Pinpoint-pAppName'.toLowerCase() + static parentApplicationType = 'Pinpoint-pAppType'.toLowerCase() + static parentApplicationNamespace = 'Pinpoint-pAppNamespace'.toLowerCase() + static host = 'Pinpoint-Host'.toLowerCase() } module.exports = Header \ No newline at end of file diff --git a/lib/instrumentation/http/trace-header-builder.js b/lib/instrumentation/http/trace-header-builder.js index 4b980f71..541946f1 100644 --- a/lib/instrumentation/http/trace-header-builder.js +++ b/lib/instrumentation/http/trace-header-builder.js @@ -6,6 +6,7 @@ 'use strict' +const TraceIdBuilder = require('../../context/trace/trace-id-builder') const samplingFlag = require('../../sampler/sampling-flag') const Header = require('./pinpoint-header') @@ -13,11 +14,8 @@ class TraceHeader { static newTrace = new TraceHeader() static disable = new TraceHeader() - constructor(transactionId, spanId, parentSpanId, flags) { - this.transactionId = transactionId - this.spanId = spanId - this.parentSpanId = parentSpanId - this.flags = flags + constructor(traceId) { + this.traceId = traceId } isNewTrace() { @@ -28,6 +26,10 @@ class TraceHeader { return this === TraceHeader.disable } + getTraceId() { + return this.traceId + } + getHost() { return this.host } @@ -56,8 +58,12 @@ class TraceHeaderBuilder { return TraceHeader.disable } - const traceId = this.request.getHeader(Header.traceId) - if (!traceId) { + const traceIdSemicolonDelimiterFormatted = this.request.getHeader(Header.traceId) + if (!traceIdSemicolonDelimiterFormatted) { + return TraceHeader.newTrace + } + const traceIdBuilder = TraceIdBuilder.makeByHeader(traceIdSemicolonDelimiterFormatted) + if (!traceIdBuilder) { return TraceHeader.newTrace } @@ -65,18 +71,21 @@ class TraceHeaderBuilder { if (!parentSpanId) { return TraceHeader.newTrace } + traceIdBuilder.setParentSpanId(parentSpanId) const spanId = this.request.getHeader(Header.spanId) if (!spanId) { return TraceHeader.newTrace } + traceIdBuilder.setSpanId(spanId) - flags = parseInt(this.request.getHeader(Header.flags) ?? '0') + const flags = parseInt(this.request.getHeader(Header.flags) ?? '0') if (Number.isNaN(flags)) { - flags = 0 + flags = '0' } + traceIdBuilder.setFlags(flags) - const traceHeader = new TraceHeader(traceId, spanId, parentSpanId, flags) + const traceHeader = new TraceHeader(traceIdBuilder.build()) // ServerRequestRecorder.java: recordParentInfo const parentApplicationName = this.request.getHeader(Header.parentApplicationName) diff --git a/lib/instrumentation/instrument-arrow-function.js b/lib/instrumentation/instrument-arrow-function.js index dec46378..cc36653b 100644 --- a/lib/instrumentation/instrument-arrow-function.js +++ b/lib/instrumentation/instrument-arrow-function.js @@ -12,13 +12,14 @@ const localStorage = require('./context/local-storage') // ref: SpanEventSimpleAroundInterceptorForPlugin.java class InstrumentArrowFunction { - constructor(target, method) { + constructor(target, method, traceContext) { this.target = target this.method = method + this.traceContext = traceContext } - static make(target, method) { - return new InstrumentArrowFunction(target, method) + static make(target, method, traceContext) { + return new InstrumentArrowFunction(target, method, traceContext) } addScopedInterceptor(interceptor) { @@ -46,16 +47,17 @@ class InstrumentArrowFunction { return } - if (!callerSpanEventRecorder || typeof callerSpanEventRecorder.recordNextAsyncId !== 'function') { + if (!callerSpanEventRecorder || typeof callerSpanEventRecorder.getNextAsyncId !== 'function') { return } - callerSpanEventRecorder.recordNextAsyncId() + const asyncId = callerSpanEventRecorder.getNextAsyncId() const target = this.target const method = this.method const trace = localStorage.getStore() + const traceContext = this.traceContext shimmer.wrap(target, method, function (original) { - return interceptor.makeHookCallbackFunction(trace, callerSpanEventRecorder.getLocalAsyncId(), new HookFunctionArguments(target, method, original)) + return interceptor.makeHookCallbackFunction(trace, asyncId, new HookFunctionArguments(target, method, original), traceContext) }) } } diff --git a/lib/instrumentation/instrument-method.js b/lib/instrumentation/instrument-method.js index 72b6bebf..2b949477 100644 --- a/lib/instrumentation/instrument-method.js +++ b/lib/instrumentation/instrument-method.js @@ -10,18 +10,19 @@ const shimmer = require('@pinpoint-apm/shimmer') const apiMetaService = require('../context/api-meta-service') const { callSite } = require('./call-stack') const InstrumentMethodContext = require('./instrument-method-context') -const TraceBuilder = require('./context/trace-builder') const localStorage = require('./context/local-storage') +const log = require('../utils/logger') // ref: SpanEventSimpleAroundInterceptorForPlugin.java class InstrumentMethod { - constructor(target, method) { + constructor(target, method, traceContext) { this.target = target this.method = method + this.traceContext = traceContext } - static make(target, method) { - return new InstrumentMethod(target, method) + static make(target, method, traceContext) { + return new InstrumentMethod(target, method, traceContext) } addScopedInterceptor(interceptor) { @@ -33,6 +34,7 @@ class InstrumentMethod { return } + const traceContext = this.traceContext shimmer.wrap(this.target, this.method, function (original) { return function () { let builder @@ -48,55 +50,58 @@ class InstrumentMethod { if (typeof interceptor.prepareBeforeTrace === 'function') { interceptor.prepareBeforeTrace(this, arguments, context) } - + const trace = localStorage.getStore() let recorder - if (trace && builder.isDetectedFunctionName()) { - recorder = trace.traceBlockBegin() - - if (interceptor.serviceType) { - recorder.recordServiceType(interceptor.serviceType) - } + try { + if (trace && builder.isDetectedFunctionName()) { + recorder = trace.traceBlockBegin() - const methodDescriptor = apiMetaService.cacheApiWithBuilder(builder) - if (methodDescriptor) { - recorder.recordApi(methodDescriptor) - } - if (typeof interceptor.doInBeforeTrace === 'function') { - interceptor.doInBeforeTrace(recorder, this, arguments) - } - } + if (interceptor.serviceType) { + recorder.recordServiceType(interceptor.serviceType) + } - if (recorder && arguments.length > 0 && typeof interceptor.callbackIndexOf === 'function' && typeof interceptor.callbackIndexOf(arguments) === 'number') { - recorder.recordNextAsyncId() - const callbackIndex = interceptor.callbackIndexOf(arguments) - const callback = arguments[callbackIndex] - arguments[callbackIndex] = function () { - if (typeof interceptor.prepareBeforeAsyncTrace === 'function') { - interceptor.prepareBeforeAsyncTrace(this, arguments) + const methodDescriptor = apiMetaService.cacheApiWithBuilder(builder) + if (methodDescriptor) { + recorder.recordApi(methodDescriptor) + } + if (typeof interceptor.doInBeforeTrace === 'function') { + interceptor.doInBeforeTrace(recorder, this, arguments) } + } - const asyncTrace = TraceBuilder.valueOfTrace(trace).buildAsyncTrace(recorder.getLocalAsyncId()) - return localStorage.run(asyncTrace, () => { - const returnedValue = callback.apply(this, arguments) - asyncTrace.close() - return returnedValue - }) + if (recorder && arguments.length > 0 && typeof interceptor.callbackIndexOf === 'function' && typeof interceptor.callbackIndexOf(arguments) === 'number') { + const asyncId = recorder.getNextAsyncId() + const callbackIndex = interceptor.callbackIndexOf(arguments) + const callback = arguments[callbackIndex] + arguments[callbackIndex] = function () { + try { + interceptor.prepareBeforeAsyncTrace?.(this, arguments) + } catch (error) { + log.error(`arguments: ${error}`) + } + const childTraceBuilder = traceContext.continueAsyncContextTraceObject(trace.getTraceRoot(), asyncId.nextLocalAsyncId2()) + return localStorage.run(childTraceBuilder, () => { + const returnedValue = callback.apply(this, arguments) + childTraceBuilder?.close() + return returnedValue + }) + } } + } catch (error) { + // TODO: INTERNAL ERROR logger + log.error(error) } var returned = original.apply(this, arguments) - if (typeof interceptor.prepareAfterTrace === 'function') { - interceptor.prepareAfterTrace(this, arguments, returned, context) - } - - if (recorder && typeof interceptor.doInAfterTrace === 'function') { - interceptor.doInAfterTrace(recorder, this, arguments, returned) - } - - if (trace) { - trace.traceBlockEnd(recorder) + try { + interceptor.prepareAfterTrace?.(this, arguments, returned, context) + interceptor.doInAfterTrace?.(recorder, this, arguments, returned) + trace?.traceBlockEnd(recorder) + } catch (error) { + // TODO: INTERNAL ERROR logger + log.error(error) } return returned } @@ -112,28 +117,31 @@ class InstrumentMethod { return } - if (!callerSpanEventRecorder || typeof callerSpanEventRecorder.recordNextAsyncId !== 'function') { + if (!callerSpanEventRecorder || typeof callerSpanEventRecorder.getNextAsyncId !== 'function') { return } - + + const traceContext = this.traceContext shimmer.wrap(this.target, this.method, function (original) { return function () { const trace = localStorage.getStore() if (!trace) { return original.apply(this, arguments) } - callerSpanEventRecorder.recordNextAsyncId() + const asyncId = callerSpanEventRecorder.getNextAsyncId() - if (typeof interceptor.prepareBeforeAsyncTrace === 'function') { - interceptor.prepareBeforeAsyncTrace(this, arguments) + try { + interceptor.prepareBeforeAsyncTrace?.(this, arguments) + } catch (error) { + log.error(`addCallbackInterceptor: ${error}`) } - const asyncTrace = TraceBuilder.valueOfTrace(trace).buildAsyncTrace(callerSpanEventRecorder.getLocalAsyncId()) - return localStorage.run(asyncTrace, () => { + const childTraceBuilder = traceContext.continueAsyncContextTraceObject(trace.getTraceRoot(), asyncId.nextLocalAsyncId2()) + return localStorage.run(childTraceBuilder, () => { const returnedValue = original.apply(this, arguments) - asyncTrace.close() + childTraceBuilder?.close() return returnedValue - }) + }) } }) } diff --git a/lib/instrumentation/module/bluebird.js b/lib/instrumentation/module/bluebird.js index 763f021f..6e8f9ec3 100644 --- a/lib/instrumentation/module/bluebird.js +++ b/lib/instrumentation/module/bluebird.js @@ -72,7 +72,7 @@ module.exports = function (agent, version, bluebird) { // todo. error 처리 어떻게 할 것인지?~ function bindEventRecord(original) { - const trace = agent.traceContext.currentTraceObject() + const trace = agent.getTraceContext().currentTraceObject() let spanEventRecorder = null if (trace) { spanEventRecorder = trace.traceBlockBegin() diff --git a/lib/instrumentation/module/callback-interceptor.js b/lib/instrumentation/module/callback-interceptor.js index 9b9e6f37..aa843cb0 100644 --- a/lib/instrumentation/module/callback-interceptor.js +++ b/lib/instrumentation/module/callback-interceptor.js @@ -9,9 +9,9 @@ const CallbackInterceptorRunner = require('../callback-interceptor-runner') class CallbackInterceptor { - makeHookCallbackFunction(trace, localAsyncId, hookFunctionArguments) { + makeHookCallbackFunction(trace, localAsyncId, hookFunctionArguments, traceContext) { return function () { - return new CallbackInterceptorRunner(trace, localAsyncId, hookFunctionArguments).run(null, this, arguments) + return new CallbackInterceptorRunner(trace, localAsyncId, hookFunctionArguments, traceContext).run(null, this, arguments) } } } diff --git a/lib/instrumentation/module/express.js b/lib/instrumentation/module/express.js index afba2e93..e1372fc8 100644 --- a/lib/instrumentation/module/express.js +++ b/lib/instrumentation/module/express.js @@ -23,8 +23,9 @@ module.exports = function (agent, version, express) { log.error('Invalid Version error') return express } - InstrumentMethod.make(express.Router, 'use').addScopedInterceptor(new ExpressUseInterceptor()) - InstrumentMethod.make(express.Router, 'route').addScopedInterceptor(new ExpressRouteInterceptor()) + const traceContext = agent.getTraceContext() + InstrumentMethod.make(express.Router, 'use', traceContext).addScopedInterceptor(new ExpressUseInterceptor(traceContext)) + InstrumentMethod.make(express.Router, 'route', traceContext).addScopedInterceptor(new ExpressRouteInterceptor(traceContext)) return express } diff --git a/lib/instrumentation/module/express/express-route-interceptor.js b/lib/instrumentation/module/express/express-route-interceptor.js index d832a374..33282794 100644 --- a/lib/instrumentation/module/express/express-route-interceptor.js +++ b/lib/instrumentation/module/express/express-route-interceptor.js @@ -11,19 +11,20 @@ const InstrumentArrowFunction = require('../../instrument-arrow-function') const ExpressLayerInterceptor = require('./express-layer-interceptor') class ExpressRouteInterceptor { - constructor() { + constructor(traceContext) { + this.traceContext = traceContext this.methodDescriptorBuilder = MethodDescriptorBuilder.makeRuntimeDetectionMethodDescriptorBuilder() .setClassName('Router') .setFileNameIndex(3) } - + prepareAfterTrace(router, args, returnedValue, context) { if (router.stack && router.stack.length) { const layer = router.stack[router.stack.length - 1] if (!layer) { return } - InstrumentArrowFunction.make(layer, 'handle').addScopedInterceptor(new ExpressLayerInterceptor(context.getMethodDescriptorBuilder())) + InstrumentArrowFunction.make(layer, 'handle', this.traceContext).addScopedInterceptor(new ExpressLayerInterceptor(context.getMethodDescriptorBuilder())) } } } diff --git a/lib/instrumentation/module/express/express-use-interceptor.js b/lib/instrumentation/module/express/express-use-interceptor.js index d27e0af8..e47ec233 100644 --- a/lib/instrumentation/module/express/express-use-interceptor.js +++ b/lib/instrumentation/module/express/express-use-interceptor.js @@ -10,7 +10,8 @@ const MethodDescriptorBuilder = require('../../../context/method-descriptor-buil const InstrumentArrowFunction = require('../../instrument-arrow-function') const ExpressLayerInterceptor = require('./express-layer-interceptor') class ExpressUseInterceptor { - constructor() { + constructor(traceContext) { + this.traceContext = traceContext this.methodDescriptorBuilder = new MethodDescriptorBuilder('use') .setClassName('Router') .setFileNameIndex(5) @@ -23,7 +24,7 @@ class ExpressUseInterceptor { if (!layer) { return } - InstrumentArrowFunction.make(layer, 'handle').addScopedInterceptor(new ExpressLayerInterceptor(context.getMethodDescriptorBuilder())) + InstrumentArrowFunction.make(layer, 'handle', this.traceContext).addScopedInterceptor(new ExpressLayerInterceptor(context.getMethodDescriptorBuilder())) } } } diff --git a/lib/instrumentation/module/http.js b/lib/instrumentation/module/http.js index d6c575a1..d17d1016 100644 --- a/lib/instrumentation/module/http.js +++ b/lib/instrumentation/module/http.js @@ -12,10 +12,10 @@ const httpShared = require('../http-shared') module.exports = function(agent, version, http) { log.debug('shimming http.Server.prototype.emit function') - shimmer.wrap(http && http.Server && http.Server.prototype, 'emit', httpShared.instrumentRequest(agent, 'http')) + shimmer.wrap(http && http.Server && http.Server.prototype, 'emit', httpShared.instrumentRequest2(agent, 'http')) log.debug('shimming http.request function') - shimmer.wrap(http, 'request', httpShared.traceOutgoingRequest(agent, 'http')) + shimmer.wrap(http, 'request', httpShared.traceOutgoingRequest2(agent, 'http')) return http } \ No newline at end of file diff --git a/lib/instrumentation/module/https.js b/lib/instrumentation/module/https.js index a6c7924f..9f034f98 100644 --- a/lib/instrumentation/module/https.js +++ b/lib/instrumentation/module/https.js @@ -13,12 +13,12 @@ const httpShared = require('../http-shared') module.exports = function(agent, version, https) { log.debug('shimming https.Server.prototype.emit function') - shimmer.wrap(https && https.Server && https.Server.prototype, 'emit', httpShared.instrumentRequest(agent, 'https')) + shimmer.wrap(https && https.Server && https.Server.prototype, 'emit', httpShared.instrumentRequest2(agent, 'https')) // https://github.com/nodejs/node/commit/5118f3146643dc55e7e7bd3082d1de4d0e7d5426 if (semver.gte(version, '9.0.0')) { log.debug('shimming https.request function') - shimmer.wrap(https, 'request', httpShared.traceOutgoingRequest(agent, 'https')) + shimmer.wrap(https, 'request', httpShared.traceOutgoingRequest2(agent, 'https')) } return https diff --git a/lib/instrumentation/module/ioredis.js b/lib/instrumentation/module/ioredis.js index 24d2233d..1f20a0fe 100644 --- a/lib/instrumentation/module/ioredis.js +++ b/lib/instrumentation/module/ioredis.js @@ -17,6 +17,7 @@ module.exports = function (agent, version, ioredis) { return ioredis } - InstrumentMethod.make(ioredis.prototype, 'sendCommand').addScopedInterceptor(new IoredisSendCommandInterceptor()) + const traceContext = agent.getTraceContext() + InstrumentMethod.make(ioredis.prototype, 'sendCommand', traceContext).addScopedInterceptor(new IoredisSendCommandInterceptor(traceContext)) return ioredis } diff --git a/lib/instrumentation/module/ioredis/ioredis-send-command-interceptor.js b/lib/instrumentation/module/ioredis/ioredis-send-command-interceptor.js index 44c7467d..55b94611 100644 --- a/lib/instrumentation/module/ioredis/ioredis-send-command-interceptor.js +++ b/lib/instrumentation/module/ioredis/ioredis-send-command-interceptor.js @@ -14,7 +14,8 @@ const CallbackInterceptor = require('../callback-interceptor') const endTraceSymbol = Symbol('ioredis-end-trace') class IoredisSendCommandInterceptor { - constructor() { + constructor(traceContext) { + this.traceContext = traceContext this.methodDescriptorBuilder = MethodDescriptorBuilder.makeRuntimeDetectionMethodDescriptorBuilder() .setClassName('Redis') this.serviceType = serviceType @@ -22,7 +23,7 @@ class IoredisSendCommandInterceptor { makeFunctionNameDetectedMethodDescriptorBuilder(thisArg, args) { if (!args || args.length < 1 || typeof args[0].name !== 'string') { - return this.methodDescriptorBuilder + return this.methodDescriptorBuilder } return this.methodDescriptorBuilder.makeCloneOf(args[0].name) } @@ -38,7 +39,7 @@ class IoredisSendCommandInterceptor { const command = args[0] command[endTraceSymbol] = function() {} - InstrumentArrowFunction.make(command, endTraceSymbol).addCallbackInterceptor(new CallbackInterceptor(), recorder) + InstrumentArrowFunction.make(command, endTraceSymbol, this.traceContext).addCallbackInterceptor(new CallbackInterceptor(), recorder) command.promise.finally(command[endTraceSymbol]) } } diff --git a/lib/instrumentation/module/koa-router.js b/lib/instrumentation/module/koa-router.js index 1d7c2896..9cb4422a 100644 --- a/lib/instrumentation/module/koa-router.js +++ b/lib/instrumentation/module/koa-router.js @@ -17,7 +17,8 @@ module.exports = function (agent, version, router) { return router } - InstrumentMethod.make(router.prototype, 'register').addScopedInterceptor(new KoaRegisterInterceptor()) + const traceContext = agent.getTraceContext() + InstrumentMethod.make(router.prototype, 'register', traceContext).addScopedInterceptor(new KoaRegisterInterceptor()) return router } \ No newline at end of file diff --git a/lib/instrumentation/module/mysql.js b/lib/instrumentation/module/mysql.js index 35913ae3..cf8139d2 100644 --- a/lib/instrumentation/module/mysql.js +++ b/lib/instrumentation/module/mysql.js @@ -20,14 +20,10 @@ module.exports = function (agent, version, mysql) { return mysql } - log.debug('shimming mysql.createPool') - InstrumentMethod.make(mysql, 'createPool').addScopedInterceptor(new MySQLCreatePoolInterceptor()) - - log.debug('shimming mysql.createPoolCluster') - InstrumentMethod.make(mysql, 'createPoolCluster').addScopedInterceptor(new MySQLCreatePoolClusterInterceptor()) - - log.debug('shimming mysql.createConnection') - InstrumentMethod.make(mysql, 'createConnection').addScopedInterceptor(new MySQLCreateConnectionInterceptor()) + const traceContext = agent.getTraceContext() + InstrumentMethod.make(mysql, 'createPool', traceContext).addScopedInterceptor(new MySQLCreatePoolInterceptor(traceContext)) + InstrumentMethod.make(mysql, 'createPoolCluster', traceContext).addScopedInterceptor(new MySQLCreatePoolClusterInterceptor(traceContext)) + InstrumentMethod.make(mysql, 'createConnection', traceContext).addScopedInterceptor(new MySQLCreateConnectionInterceptor(traceContext)) return mysql } diff --git a/lib/instrumentation/module/mysql/mysql-cluster-of-interceptor.js b/lib/instrumentation/module/mysql/mysql-cluster-of-interceptor.js index e0efed7a..1e2c0fbb 100644 --- a/lib/instrumentation/module/mysql/mysql-cluster-of-interceptor.js +++ b/lib/instrumentation/module/mysql/mysql-cluster-of-interceptor.js @@ -11,8 +11,9 @@ const InstrumentMethod = require('../../instrument-method') const MySQLGetConnectionInterceptor = require('./mysql-get-connection-interceptor') class MySQLClusterOfInterceptor { - constructor() { + constructor(traceContext) { this.methodDescriptorBuilder = new MethodDescriptorBuilder('of') + this.traceContext = traceContext } doInBeforeTrace(recorder, target, args) { @@ -23,7 +24,7 @@ class MySQLClusterOfInterceptor { if (!poolNamespace) { return } - InstrumentMethod.make(poolNamespace, 'getConnection').addScopedInterceptor(new MySQLGetConnectionInterceptor()) + InstrumentMethod.make(poolNamespace, 'getConnection', this.traceContext).addScopedInterceptor(new MySQLGetConnectionInterceptor(this.traceContext)) } } diff --git a/lib/instrumentation/module/mysql/mysql-create-connection-interceptor.js b/lib/instrumentation/module/mysql/mysql-create-connection-interceptor.js index 9245987b..10a99257 100644 --- a/lib/instrumentation/module/mysql/mysql-create-connection-interceptor.js +++ b/lib/instrumentation/module/mysql/mysql-create-connection-interceptor.js @@ -15,9 +15,10 @@ const databaseInfoSymbol = require('./mysql-database-information-symbol') const MySQLRecorder = require('./mysql-recorder') class MySQLCreateConnectionInterceptor { - constructor() { + constructor(traceContext) { this.methodDescriptorBuilder = new MethodDescriptorBuilder('createConnection') .setParameterVariableNames('connectionUri') + this.traceContext = traceContext } doInBeforeTrace(recorder) { @@ -27,8 +28,8 @@ class MySQLCreateConnectionInterceptor { prepareAfterTrace(target, args, connection) { if (connection) { connection[databaseInfoSymbol] = args[0] - InstrumentMethod.make(connection, 'connect').addScopedInterceptor(new MySQLConnectionInterceptor()) - InstrumentMethod.make(connection, 'query').addScopedInterceptor(new MySQLStatementExecuteQueryInterceptor('Connection')) + InstrumentMethod.make(connection, 'connect', this.traceContext).addScopedInterceptor(new MySQLConnectionInterceptor()) + InstrumentMethod.make(connection, 'query', this.traceContext).addScopedInterceptor(new MySQLStatementExecuteQueryInterceptor('Connection')) } } diff --git a/lib/instrumentation/module/mysql/mysql-create-pool-cluster-interceptor.js b/lib/instrumentation/module/mysql/mysql-create-pool-cluster-interceptor.js index 4f2a168b..f6ec1dd8 100644 --- a/lib/instrumentation/module/mysql/mysql-create-pool-cluster-interceptor.js +++ b/lib/instrumentation/module/mysql/mysql-create-pool-cluster-interceptor.js @@ -11,8 +11,9 @@ const InstrumentMethod = require('../../instrument-method') const MySQLClusterOfInterceptor = require('./mysql-cluster-of-interceptor') class MySQLCreatePoolClusterInterceptor { - constructor() { + constructor(traceContext) { this.methodDescriptorBuilder = new MethodDescriptorBuilder('createPoolCluster') + this.traceContext = traceContext } doInBeforeTrace(recorder) { @@ -23,7 +24,7 @@ class MySQLCreatePoolClusterInterceptor { if (!poolCluster) { return } - InstrumentMethod.make(poolCluster, 'of').addScopedInterceptor(new MySQLClusterOfInterceptor()) + InstrumentMethod.make(poolCluster, 'of', this.traceContext).addScopedInterceptor(new MySQLClusterOfInterceptor(this.traceContext)) } } diff --git a/lib/instrumentation/module/mysql/mysql-create-pool-interceptor.js b/lib/instrumentation/module/mysql/mysql-create-pool-interceptor.js index 7bf6577e..7e33b3e8 100644 --- a/lib/instrumentation/module/mysql/mysql-create-pool-interceptor.js +++ b/lib/instrumentation/module/mysql/mysql-create-pool-interceptor.js @@ -14,8 +14,9 @@ const MySQLGetConnectionInterceptor = require('./mysql-get-connection-intercepto const MySQLRecorder = require('./mysql-recorder') class MySQLCreatePoolInterceptor { - constructor() { + constructor(traceContext) { this.methodDescriptorBuilder = new MethodDescriptorBuilder('createPool') + this.traceContext = traceContext } doInBeforeTrace(recorder) { @@ -25,7 +26,7 @@ class MySQLCreatePoolInterceptor { prepareAfterTrace(target, args, pool) { if (pool) { pool[databaseInfoSymbol] = args[0] - InstrumentMethod.make(pool, 'getConnection').addScopedInterceptor(new MySQLGetConnectionInterceptor()) + InstrumentMethod.make(pool, 'getConnection', this.traceContext).addScopedInterceptor(new MySQLGetConnectionInterceptor(this.traceContext)) } } diff --git a/lib/instrumentation/module/mysql/mysql-get-connection-interceptor.js b/lib/instrumentation/module/mysql/mysql-get-connection-interceptor.js index cb926785..ce4f392f 100644 --- a/lib/instrumentation/module/mysql/mysql-get-connection-interceptor.js +++ b/lib/instrumentation/module/mysql/mysql-get-connection-interceptor.js @@ -14,10 +14,11 @@ const MySQLStatementExecuteQueryInterceptor = require('./mysql-statement-execute const MySQLRecorder = require('./mysql-recorder') class MySQLGetConnectionInterceptor { - constructor() { + constructor(traceContext) { this.methodDescriptorBuilder = new MethodDescriptorBuilder('getConnection') .setClassName('Pool') this.serviceType = serviceType + this.traceContext = traceContext } doInBeforeTrace(recorder, target) { @@ -27,7 +28,7 @@ class MySQLGetConnectionInterceptor { prepareBeforeAsyncTrace(target, args) { if (args.length > 1 && args[1]) { const connection = args[1] - InstrumentMethod.make(connection, 'query').addScopedInterceptor(new MySQLStatementExecuteQueryInterceptor('PoolConnection')) + InstrumentMethod.make(connection, 'query', this.traceContext).addScopedInterceptor(new MySQLStatementExecuteQueryInterceptor('PoolConnection')) } } diff --git a/lib/instrumentation/module/mysql2.js b/lib/instrumentation/module/mysql2.js index 57b4923d..d18b7e2f 100644 --- a/lib/instrumentation/module/mysql2.js +++ b/lib/instrumentation/module/mysql2.js @@ -19,14 +19,10 @@ module.exports = function (agent, version, mysql) { return mysql } - log.debug('shimming mysql.createPool') - InstrumentMethod.make(mysql, 'createPool').addScopedInterceptor(new MySQLCreatePoolInterceptor()) + const traceContext = agent.getTraceContext() + InstrumentMethod.make(mysql, 'createPool', traceContext).addScopedInterceptor(new MySQLCreatePoolInterceptor(traceContext)) + InstrumentMethod.make(mysql, 'createPoolCluster', traceContext).addScopedInterceptor(new MySQLCreatePoolClusterInterceptor(traceContext)) + InstrumentMethod.make(mysql, 'createConnection', traceContext).addScopedInterceptor(new MySQLCreateConnectionInterceptor(traceContext)) - log.debug('shimming mysql.createPoolCluster') - InstrumentMethod.make(mysql, 'createPoolCluster').addScopedInterceptor(new MySQLCreatePoolClusterInterceptor()) - - log.debug('shimming mysql.createConnection') - InstrumentMethod.make(mysql, 'createConnection').addScopedInterceptor(new MySQLCreateConnectionInterceptor()) - return mysql } \ No newline at end of file diff --git a/lib/instrumentation/module/redis.js b/lib/instrumentation/module/redis.js index a8228f62..125b9f2c 100644 --- a/lib/instrumentation/module/redis.js +++ b/lib/instrumentation/module/redis.js @@ -17,9 +17,8 @@ module.exports = function (agent, version, redis) { return redis } - const proto = redis.RedisClient && redis.RedisClient.prototype - log.debug('shimming redis.RedisClient.prototype.internal_send_command') - InstrumentMethod.make(proto, 'internal_send_command').addScopedInterceptor(new RedisInternalSendCommandInterceptor()) + const traceContext = agent.getTraceContext() + InstrumentMethod.make(redis.RedisClient && redis.RedisClient.prototype, 'internal_send_command', traceContext).addScopedInterceptor(new RedisInternalSendCommandInterceptor(traceContext)) return redis } diff --git a/lib/instrumentation/module/redis/redis-internal-send-command-interceptor.js b/lib/instrumentation/module/redis/redis-internal-send-command-interceptor.js index 81065be0..26f32fca 100644 --- a/lib/instrumentation/module/redis/redis-internal-send-command-interceptor.js +++ b/lib/instrumentation/module/redis/redis-internal-send-command-interceptor.js @@ -13,7 +13,8 @@ const InstrumentArrowFunction = require('../../instrument-arrow-function') const CallbackInterceptor = require('../callback-interceptor') class RedisInternalSendCommandInterceptor { - constructor() { + constructor(traceContext) { + this.traceContext = traceContext this.methodDescriptorBuilder = MethodDescriptorBuilder.makeRuntimeDetectionMethodDescriptorBuilder() .setClassName('RedisClient') this.serviceType = serviceType @@ -39,7 +40,7 @@ class RedisInternalSendCommandInterceptor { } const command = args[0] - InstrumentArrowFunction.make(command, 'callback').addCallbackInterceptor(new CallbackInterceptor(), recorder) + InstrumentArrowFunction.make(command, 'callback', this.traceContext).addCallbackInterceptor(new CallbackInterceptor(), recorder) } } diff --git a/test/client/data-sender.test.js b/test/client/data-sender.test.js index ae2cbc97..192dc54f 100644 --- a/test/client/data-sender.test.js +++ b/test/client/data-sender.test.js @@ -6,8 +6,8 @@ const test = require('tape') +require('../support/agent-singleton-mock') const { fixture } = require('../test-helper') -const Trace = require('../../lib/context/trace') const dataSenderMock = require('../support/data-sender-mock') const dataSender = dataSenderMock() const AgentInfo = require('../../lib/data/dto/agent-info') @@ -42,20 +42,3 @@ test('Should send string meta info', function (t) { t.deepEqual(dataSender.mockMetaInfo, stringMetaInfo, "agentInfo is equal in datasender") }) - -test('Should send string meta info', function (t) { - t.plan(1) - dataSender.mockSpan = null - - const traceId = fixture.getTraceId() - const agentInfo = fixture.getAgentInfo() - const trace = new Trace(traceId, agentInfo, dataSender) - const spanEventRecorder = trace.traceBlockBegin() - - trace.traceBlockEnd(spanEventRecorder) - const span = trace.span - - dataSender.send(span) - - t.equal(dataSender.mockSpan, span, "metaInfo is equal in datasender") -}) diff --git a/test/client/grpc-data-sender-client-side-stream.test.js b/test/client/grpc-data-sender-client-side-stream.test.js index 26b16cbc..461545b5 100644 --- a/test/client/grpc-data-sender-client-side-stream.test.js +++ b/test/client/grpc-data-sender-client-side-stream.test.js @@ -11,61 +11,27 @@ const services = require('../../lib/data/v1/Service_grpc_pb') const { Empty } = require('google-protobuf/google/protobuf/empty_pb') const { log } = require('../test-helper') const GrpcDataSender = require('../../lib/client/grpc-data-sender') -const Span = require('../../lib/context/span') const GrpcClientSideStream = require('../../lib/client/grpc-client-side-stream') +const SpanBuilder = require('../../lib/context/span-builder') +const RemoteTraceRootBuilder = require('../../lib/context/remote-trace-root-builder') +const AgentInfo = require('../../lib/data/dto/agent-info') +const agent = require('../support/agent-singleton-mock') +const SpanRepository = require('../../lib/context/trace/span-repository') +const DataSender = require('../../lib/client/data-sender') +const SpanChunkBuilder = require('../../lib/context/span-chunk-builder') let actuals -const expectedSpan = { - "traceId": { - "transactionId": { - "agentId": "express-node-sample-id", - "agentStartTime": 1592572771026, - "sequence": 5 - }, - "spanId": 2894367178713953, - "parentSpanId": -1, - "flag": 0 - }, - "agentId": "express-node-sample-id", - "applicationName": "express-node-sample-name", - "agentStartTime": 1592572771026, - "serviceType": 1400, - "spanId": '2894367178713953', - "parentSpanId": -1, - "transactionId": { - "type": "Buffer", - "data": [0, 44, 101, 120, 112, 114, 101, 115, 115, 45, 110, 111, 100, 101, 45, 115, 97, 109, 112, 108, 101, 45, 105, 100, 210, 245, 239, 229, 172, 46, 5] - }, - "startTime": 1592574173350, - "elapsedTime": 28644, - "rpc": "/", - "endPoint": "localhost:3000", - "remoteAddr": "::1", - "annotations": [], - "flag": 0, - "err": 1, - "spanEventList": null, - "apiId": 1, - "exceptionInfo": null, - "applicationServiceType": 1400, - "loggingTransactionInfo": null, - "version": 1 -} - -const span = Object.assign(new Span({ - spanId: 2894367178713953, - parentSpanId: -1, - transactionId: { - "agentId": "express-node-sample-id", - "agentStartTime": 1592574173350, - "sequence": 0 - } -}, { - agentId: "express-node-sample-id", - applicationName: "express-node-sample-name", - agentStartTime: 1592574173350 -}), expectedSpan) +const agentInfo = AgentInfo.create({ + agentId: 'express-node-sample-id', + applicationName: 'express-node-sample-name', + serviceType: 1400 + }, 1592572771026) +const traceRoot = new RemoteTraceRootBuilder(agentInfo, 5).build() +const expectedSpanBuilder = new SpanBuilder(traceRoot) +expectedSpanBuilder.setServiceType(1400) +expectedSpanBuilder.setEndPoint('localhost:3000') +expectedSpanBuilder.setRemoteAddress('::1') // https://github.com/agreatfool/grpc_tools_node_protoc_ts/blob/v5.0.0/examples/src/grpcjs/server.ts function sendAgentStat(call, callback) { @@ -90,7 +56,7 @@ function sendSpan(call, callback) { const span = spanMessage.getSpan() if (actuals.serverSpanDataCount == 1) { actuals.t.equal(actuals.serverSpanDataCount, 1, '1st sendSpan serverSpanDataCount is 1') - actuals.t.equal(span.getSpanid(), '2894367178713953', 'span ID match in 1st sendSpan') + actuals.t.equal(span.getSpanid(), expectedSpanBuilder.getTraceRoot().getTraceId().getSpanId(), 'span ID match in 1st sendSpan') } else if (actuals.serverSpanDataCount == 2) { actuals.t.equal(actuals.serverSpanDataCount, 2, '2st sendSpan serverSpanDataCount is 2') actuals.t.equal(span.getServicetype(), 1400, 'service type match in 2st sendSpan') @@ -151,11 +117,10 @@ test('client side streaming with deadline and cancellation', function (t) { actuals.serverSpanDataCount = 0 actuals.serverPingCount = 0 - this.grpcDataSender = new GrpcDataSender('localhost', port, port, port, { - 'agentid': '12121212', - 'applicationname': 'applicationName', - 'starttime': Date.now() - }) + this.grpcDataSender = new GrpcDataSender('localhost', port, port, port, agentInfo, agent.config) + this.dataSender = new DataSender(agent.config, this.grpcDataSender) + const spanChunkBuilder = new SpanChunkBuilder(traceRoot) + const repository = new SpanRepository(spanChunkBuilder, this.dataSender, agentInfo) this.grpcDataSender.spanStream.callback = (err) => { callOrder++ @@ -192,7 +157,7 @@ test('client side streaming with deadline and cancellation', function (t) { setTimeout(() => { // 6st sendSpan actuals.sendSpanCount++ - this.grpcDataSender.sendSpan(span) + repository.storeSpan(expectedSpanBuilder) registerEventListeners() }) } else if (callOrder == 6/* 6st sendSpan */) { @@ -201,7 +166,7 @@ test('client side streaming with deadline and cancellation', function (t) { setTimeout(() => { // 8st when spanStream end, recovery spanstream actuals.sendSpanCount++ - this.grpcDataSender.sendSpan(span) + repository.storeSpan(expectedSpanBuilder) registerEventListeners() this.grpcDataSender.spanStream.grpcStream.end() }) @@ -225,22 +190,21 @@ test('client side streaming with deadline and cancellation', function (t) { t.teardown(() => { server.forceShutdown() - this.grpcDataSender.close() }) // 1st sendSpan actuals.sendSpanCount++ - this.grpcDataSender.sendSpan(span) + repository.storeSpan(expectedSpanBuilder) // 2st sendSpan actuals.sendSpanCount++ - this.grpcDataSender.sendSpan(span) + repository.storeSpan(expectedSpanBuilder) // 3st spanStream end this.grpcDataSender.spanStream.grpcStream.end() // 4st sendSpan actuals.sendSpanCount++ - this.grpcDataSender.sendSpan(span) + repository.storeSpan(expectedSpanBuilder) registerEventListeners() // 5st spanStream end this.grpcDataSender.spanStream.grpcStream.end() @@ -336,7 +300,7 @@ test('spanStream ERR_STREAM_WRITE_AFTER_END', (t) => { if (0 == index % 2) { this.grpcDataSender.spanStream.grpcStream.end() } - this.grpcDataSender.sendSpan(span) + this.grpcDataSender.sendSpan(expectedSpanBuilder.build()) } this.grpcDataSender.pingStream.grpcStream.end() diff --git a/test/client/grpc-data-sender.test.js b/test/client/grpc-data-sender.test.js index 0572d937..c9165ce0 100644 --- a/test/client/grpc-data-sender.test.js +++ b/test/client/grpc-data-sender.test.js @@ -7,10 +7,8 @@ const test = require('tape') const annotationKey = require('../../lib/constant/annotation-key') const AsyncId = require('../../lib/context/async-id') -const SpanChunk = require('../../lib/context/span-chunk') const Span = require('../../lib/context/span') const SpanEvent = require('../../lib/context/span-event') -const MockGrpcDataSender = require('./mock-grpc-data-sender') const grpc = require('@grpc/grpc-js') const services = require('../../lib/data/v1/Service_grpc_pb') const { beforeSpecificOne, afterOne, getCallRequests, getMetadata, DataSourceCallCountable } = require('./grpc-fixture') @@ -19,18 +17,31 @@ const CommandType = require('../../lib/client/command/command-type') const { Empty } = require('google-protobuf/google/protobuf/empty_pb') const Annotations = require('../../lib/instrumentation/context/annotation/annotations') const CallArgumentsBuilder = require('../../lib/client/call-arguments-builder') +const agent = require('../support/agent-singleton-mock') +const RemoteTraceRootBuilder = require('../../lib/context/remote-trace-root-builder') +const SpanBuilder = require('../../lib/context/span-builder') +const AsyncSpanChunkBuilder = require('../../lib/context/trace/async-span-chunk-builder') +const SpanRepository = require('../../lib/context/trace/span-repository') +const ChildTraceBuilder = require('../../lib/context/trace/child-trace-builder') +const serviceType = require('../../lib/context/service-type') +const makeMockDataSender = require('../fixtures/mock-data-sender') +const SpanChunkBuilder = require('../../lib/context/span-chunk-builder') +const Trace = require('../../lib/context/trace/trace2') +const defaultPredefinedMethodDescriptorRegistry = require('../../lib/constant/default-predefined-method-descriptor-registry') let sendSpanMethodOnDataCallback function sendSpan(call) { call.on('error', function (error) { + console.log(`error ${error}`) }) call.on('data', function (spanMessage) { - const span = spanMessage.getSpan() - const callRequests = getCallRequests() - callRequests.push(span) - if (typeof sendSpanMethodOnDataCallback === 'function') { - sendSpanMethodOnDataCallback(span) + let spanOrChunk = spanMessage.getSpan() + if (!spanOrChunk) { + spanOrChunk = spanMessage.getSpanchunk() } + const callRequests = getCallRequests() + callRequests.push(spanOrChunk) + sendSpanMethodOnDataCallback?.(spanOrChunk) }) call.on('end', function () { }) @@ -52,57 +63,8 @@ class DataSource extends DataSourceCallCountable { } test('Should send span', function (t) { + agent.bindHttp() sendSpanMethodOnDataCallback = null - const expectedSpan = { - 'traceId': { - 'transactionId': { - 'agentId': 'express-node-sample-id', - 'agentStartTime': '1592572771026', - 'sequence': '5' - }, - 'spanId': '2894367178713953', - 'parentSpanId': '-1', - 'flag': 0 - }, - 'agentId': 'express-node-sample-id', - 'applicationName': 'express-node-sample-name', - 'agentStartTime': 1592572771026, - 'serviceType': 1400, - 'spanId': '2894367178713953', - 'parentSpanId': '-1', - 'transactionId': { - 'type': 'Buffer', - 'data': [0, 44, 101, 120, 112, 114, 101, 115, 115, 45, 110, 111, 100, 101, 45, 115, 97, 109, 112, 108, 101, 45, 105, 100, 210, 245, 239, 229, 172, 46, 5] - }, - 'startTime': 1592574173350, - 'elapsedTime': 28644, - 'rpc': '/', - 'endPoint': 'localhost:3000', - 'remoteAddr': '::1', - 'annotations': [], - 'flag': 0, - 'err': 1, - 'spanEventList': null, - 'apiId': 1, - 'exceptionInfo': null, - 'applicationServiceType': 1400, - 'loggingTransactionInfo': null, - 'version': 1 - } - - const span = Object.assign(new Span({ - spanId: 2894367178713953, - parentSpanId: -1, - transactionId: { - 'agentId': 'express-node-sample-id', - 'agentStartTime': 1592574173350, - 'sequence': 0 - } - }, { - agentId: 'express-node-sample-id', - applicationName: 'express-node-sample-name', - agentStartTime: 1592574173350 - }), expectedSpan) const server = new grpc.Server() server.addService(services.SpanService, { @@ -110,20 +72,47 @@ test('Should send span', function (t) { }) let dataSender server.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { - dataSender = beforeSpecificOne(port, DataSource) + const grpcDataSender = beforeSpecificOne(port, DataSource) + const traceRoot = new RemoteTraceRootBuilder(agent.agentInfo, '5').build() + dataSender = makeMockDataSender(agent.config, grpcDataSender) + const spanBuilder = new SpanBuilder(traceRoot) + spanBuilder.setServiceType(1400) + spanBuilder.setEndPoint('localhost:3000') + spanBuilder.setRemoteAddress('::1') + spanBuilder.markAfterTime() + spanBuilder.setApiId(1) + spanBuilder.setRpc('/') + spanBuilder.setApplicationServiceType(1400) + traceRoot.getShared().maskErrorCode(1) + const spanChunkBuilder = new SpanChunkBuilder(traceRoot) + const repository = new SpanRepository(spanChunkBuilder, dataSender, agent.agentInfo) + const trace = new Trace(spanBuilder, repository) + + const spanEventRecorder = trace.traceBlockBegin() + spanEventRecorder.spanEventBuilder.setSequence(10) + spanEventRecorder.spanEventBuilder.setDepth(1) + spanEventRecorder.recordApiDesc('http.request') + spanEventRecorder.spanEventBuilder.startTime = spanBuilder.startTime + 72 + spanEventRecorder.recordServiceType(serviceType.asyncHttpClientInternal) + + setTimeout(() => { + trace.traceBlockEnd(spanEventRecorder) + agent.completeTraceObject(trace) + }, 1000) + sendSpanMethodOnDataCallback = (actual) => { t.true(actual != null, 'spanChunk send') t.equal(actual.getVersion(), 1, `spanChunk version is ${actual.getVersion()}`) const actualTransactionId = actual.getTransactionid() - t.equal(actualTransactionId.getAgentid(), span.agentId, `agentId ${span.agentId}`) - t.equal(actualTransactionId.getAgentstarttime(), span.traceId.transactionId.agentStartTime, 'agent start time') - t.equal(actualTransactionId.getSequence(), span.traceId.transactionId.sequence, `sequence ${span.traceId.transactionId.sequence}`) - t.equal(actual.getSpanid(), span.spanId, 'span ID') - t.equal(actual.getParentspanid(), span.parentSpanId, 'parent span ID') - - t.equal(actual.getStarttime(), span.startTime, 'startTimeStamp') - t.equal(actual.getElapsed(), 28644, 'elapsed time') + t.equal(actualTransactionId.getAgentid(), traceRoot.getAgentId(), `agentId ${traceRoot.getAgentId()}`) + t.equal(actualTransactionId.getAgentstarttime(), traceRoot.getTraceId().getAgentStartTime(), 'agent start time') + t.equal(actualTransactionId.getSequence(), traceRoot.getTransactionId(), `sequence ${traceRoot.getTransactionId()}`) + t.equal(actual.getSpanid(), traceRoot.getTraceId().getSpanId(), 'span ID') + t.equal(actual.getParentspanid(), traceRoot.getTraceId().getParentSpanId(), 'parent span ID') + + t.equal(actual.getStarttime(), spanBuilder.startTime, 'startTimeStamp') + t.equal(actual.getElapsed(), spanBuilder.elapsedTime, 'elapsed time') t.equal(actual.getApiid(), 1, 'api ID') t.equal(actual.getServicetype(), 1400, 'service type') @@ -142,7 +131,7 @@ test('Should send span', function (t) { t.equal(pSpanEvent.getDepth(), 1, 'depth') t.equal(pSpanEvent.getStartelapsed(), 72, 'startElapsed') - t.equal(pSpanEvent.getEndelapsed(), 0, 'endElapsed') + t.equal(pSpanEvent.getEndelapsed(), dataSender.mockSpan.spanEventList[0].elapsedTime, 'endElapsed') t.equal(pSpanEvent.getServicetype(), 9057, 'serviceType') @@ -162,7 +151,6 @@ test('Should send span', function (t) { afterOne(t) } - dataSender.sendSpan(span) }) t.teardown(() => { dataSender.close() @@ -170,559 +158,252 @@ test('Should send span', function (t) { }) }) -const grpcDataSender = new MockGrpcDataSender('', 0, 0, 0, { agentId: 'agent', applicationName: 'applicationName', agentStartTime: 1234344 }) - test('sendSpanChunk redis.SET.end', function (t) { - let expectedSpanChunk = { - 'agentId': 'express-node-sample-id', - 'applicationName': 'express-node-sample-name', - 'agentStartTime': 1592872080170, - 'serviceType': 1400, - 'spanId': 7056897257955935, - 'parentSpanId': -1, - 'transactionId': { - 'type': 'Buffer', - 'data': [0, 44, 101, 120, 112, 114, 101, 115, 115, 45, 110, 111, 100, 101, 45, 115, 97, 109, 112, 108, 101, 45, 105, 100, 170, 166, 204, 244, 173, 46, 0] - }, - 'transactionIdObject': { - 'agentId': 'express-node-sample-id', - 'agentStartTime': 1592872080170, - 'sequence': 0 - }, - 'spanEventList': [Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:6379' - }, 0), { - 'spanId': 7056897257955935, - 'sequence': 0, - 'startTime': 1592872091543, - 'elapsedTime': 0, - 'startElapsed': 14, - 'serviceType': 100, - 'endPoint': null, - 'annotations': [], - 'depth': 1, - 'nextSpanId': -1, - 'destinationId': null, - 'apiId': 1, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': null, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }), - Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:6379' - }, 1), { - 'spanId': 7056897257955935, - 'sequence': 1, - 'startTime': 1592872091543, - 'elapsedTime': 2, - 'startElapsed': 7, - 'serviceType': 8200, - 'endPoint': 'localhost:6379', - 'annotations': [Annotations.of(annotationKey.API.getCode(), 'redis.SET.end')], - 'depth': 2, - 'nextSpanId': 1508182809976945, - 'destinationId': 'Redis', - 'apiId': 0, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': null, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }) - ], - 'endPoint': null, - 'applicationServiceType': 1400, - 'localAsyncId': new AsyncId(1) - } - const spanChunk = Object.assign(new SpanChunk({ - spanId: 2894367178713953, - parentSpanId: -1, - transactionId: { - 'agentId': 'express-node-sample-id', - 'agentStartTime': 1592872080170, - 'sequence': 0 - } - }, { - agentId: 'express-node-sample-id', - applicationName: 'express-node-sample-name', - agentStartTime: 1592872080170 - }), expectedSpanChunk) - - grpcDataSender.sendSpanChunk(spanChunk) - - const actual = grpcDataSender.actualSpan.getSpanchunk() - - t.plan(22) - t.true(actual != null, 'spanChunk send') - t.equal(actual.getVersion(), 1, 'spanChunk version is 1') - - const actualTransactionId = actual.getTransactionid() - t.equal(actualTransactionId.getAgentid(), 'express-node-sample-id', 'gRPC agentId') - t.equal(actualTransactionId.getAgentstarttime(), 1592872080170, 'agent start time') - t.equal(actualTransactionId.getSequence(), 0, 'sequence') - - t.equal(actual.getSpanid(), 7056897257955935, 'span ID') - t.equal(actual.getEndpoint(), '', 'endpoint') - t.equal(actual.getApplicationservicetype(), 1400, 'application service type') - - const actualLocalAsyncId = actual.getLocalasyncid() - t.equal(actualLocalAsyncId.getAsyncid(), 1, 'local async id') - t.equal(actualLocalAsyncId.getSequence(), 0, 'local async id sequence') - - t.equal(actual.getKeytime(), 1592872091543, 'keytime') - const actualSpanEvents = actual.getSpaneventList() - actualSpanEvents.forEach((pSpanEvent, index) => { - if (index == 0) { - t.equal(pSpanEvent.getSequence(), 0, 'sequence') - t.equal(pSpanEvent.getDepth(), 1, 'depth') - t.equal(pSpanEvent.getServicetype(), 100, 'serviceType') - t.equal(pSpanEvent.getStartelapsed(), 0, 'startElapsed') - } else if (index == 1) { - t.equal(pSpanEvent.getSequence(), 1, 'sequence') - t.equal(pSpanEvent.getDepth(), 2, 'depth') - - t.equal(pSpanEvent.getStartelapsed(), 0, 'startElapsed') - t.equal(pSpanEvent.getEndelapsed(), 2, 'endElapsed') - t.equal(pSpanEvent.getServicetype(), 8200, 'serviceType') - - const pAnnotations = pSpanEvent.getAnnotationList() - pAnnotations.forEach(annotation => { - t.equal(annotation.getKey(), 12, 'annotation key') - const pAnnotationValue = annotation.getValue() - t.equal(pAnnotationValue.getStringvalue(), 'redis.SET.end', 'annotation string value') + agent.bindHttp() + sendSpanMethodOnDataCallback = null + const server = new grpc.Server() + server.addService(services.SpanService, { + sendSpan: sendSpan + }) + + let dataSender + server.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + const grpcDataSender = beforeSpecificOne(port, DataSource) + const traceRoot = new RemoteTraceRootBuilder(agent.agentInfo, '5').build() + const asyncId = AsyncId.make() + dataSender = makeMockDataSender(agent.config, grpcDataSender) + const spanChunkBuilder = new AsyncSpanChunkBuilder(traceRoot, asyncId) + const repository = new SpanRepository(spanChunkBuilder, dataSender, agent.agentInfo) + const childTraceBuilder = new ChildTraceBuilder(traceRoot, repository, asyncId) + + const spanEventRecorder = childTraceBuilder.traceBlockBegin() + spanEventRecorder.recordServiceType(serviceType.redis) + spanEventRecorder.recordApiDesc('redis.SET.end') + childTraceBuilder.traceBlockEnd(spanEventRecorder) + + agent.completeTraceObject(childTraceBuilder) + + sendSpanMethodOnDataCallback = (actualSpanChunk) => { + t.plan(22) + t.true(actualSpanChunk != null, 'spanChunk send') + t.equal(actualSpanChunk.getVersion(), 1, 'spanChunk version is 1') + + const actualTransactionId = actualSpanChunk.getTransactionid() + t.equal(actualTransactionId.getAgentid(), traceRoot.getAgentId(), 'gRPC agentId') + t.equal(actualTransactionId.getAgentstarttime(), traceRoot.getTraceId().getAgentStartTime(), 'agent start time') + t.equal(actualTransactionId.getSequence(), traceRoot.getTransactionId(), 'sequence') + + t.equal(actualSpanChunk.getSpanid(), traceRoot.getTraceId().getSpanId(), 'span ID') + t.equal(actualSpanChunk.getEndpoint(), '', 'endpoint') + t.equal(actualSpanChunk.getApplicationservicetype(), actualSpanChunk.getApplicationservicetype(), 'application service type') + + const actualLocalAsyncId = actualSpanChunk.getLocalasyncid() + t.equal(actualLocalAsyncId.getAsyncid(), asyncId.getAsyncId(), 'local async id') + t.equal(actualLocalAsyncId.getSequence(), asyncId.getSequence(), 'local async id sequence') + + t.equal(actualSpanChunk.getKeytime(), spanChunkBuilder.keyTime, 'keytime') + const actualSpanEvents = actualSpanChunk.getSpaneventList() + actualSpanEvents.forEach((pSpanEvent, index) => { + if (index == 0) { + t.equal(pSpanEvent.getSequence(), 0, 'sequence') + t.equal(pSpanEvent.getDepth(), 1, 'depth') + t.equal(pSpanEvent.getServicetype(), 100, 'serviceType') + t.equal(pSpanEvent.getStartelapsed(), 0, 'startElapsed') + } else if (index == 1) { + t.equal(pSpanEvent.getSequence(), 1, 'sequence') + t.equal(pSpanEvent.getDepth(), 2, 'depth') + + const expectedSpanChunk = repository.dataSender.findSpanChunk(childTraceBuilder.localAsyncId) + const expectedSpanEvent = expectedSpanChunk.spanEventList[0] + t.equal(pSpanEvent.getStartelapsed(), expectedSpanEvent.startElapsedTime, `pSpanEvent.getStartelapsed() : ${pSpanEvent.getStartelapsed()}, expectedSpanEvent.startElapsedTime : ${expectedSpanEvent.startElapsedTime}`) + t.equal(pSpanEvent.getEndelapsed(), expectedSpanEvent.elapsedTime, `pSpanEvent.getEndelapsed() : ${pSpanEvent.getEndelapsed()}, expectedSpanEvent.elapsedTime : ${expectedSpanEvent.elapsedTime}`) + t.equal(pSpanEvent.getServicetype(), 8200, 'serviceType') + + const pAnnotations = pSpanEvent.getAnnotationList() + pAnnotations.forEach(annotation => { + t.equal(annotation.getKey(), 12, 'annotation key') + const pAnnotationValue = annotation.getValue() + t.equal(pAnnotationValue.getStringvalue(), 'redis.SET.end', 'annotation string value') + }) + } }) + afterOne(t) } }) + t.teardown(() => { + dataSender.close() + server.forceShutdown() + }) }) test('sendSpanChunk redis.GET.end', (t) => { - let expectedSpanChunk = { - 'agentId': 'express-node-sample-id', - 'applicationName': 'express-node-sample-name', - 'agentStartTime': 1592872080170, - 'serviceType': 1400, - 'spanId': 7056897257955935, - 'parentSpanId': -1, - 'transactionId': { - 'type': 'Buffer', - 'data': [0, 44, 101, 120, 112, 114, 101, 115, 115, 45, 110, 111, 100, 101, 45, 115, 97, 109, 112, 108, 101, 45, 105, 100, 170, 166, 204, 244, 173, 46, 0] - }, - 'transactionIdObject': { - 'agentId': 'express-node-sample-id', - 'agentStartTime': 1592872080170, - 'sequence': 0 - }, - 'spanEventList': [Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:6379' - }, 0), { - 'spanId': 7056897257955935, - 'sequence': 0, - 'startTime': 1592872091543, - 'elapsedTime': 0, - 'startElapsed': 14, - 'serviceType': 100, - 'endPoint': null, - 'annotations': [], - 'depth': 1, - 'nextSpanId': -1, - 'destinationId': null, - 'apiId': 1, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': null, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }), - { - 'spanId': 7056897257955935, - 'sequence': 1, - 'startTime': 1592872091543, - 'elapsedTime': 0, - 'startElapsed': 7, - 'serviceType': 8200, - 'endPoint': 'localhost:6379', - 'annotations': [Annotations.of(annotationKey.API.getCode(), 'redis.GET.end')], - 'depth': 2, - 'nextSpanId': 6277978728741477, - 'destinationId': 'Redis', - 'apiId': 0, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': null, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - } - ], - 'endPoint': null, - 'applicationServiceType': 1400, - 'localAsyncId': new AsyncId(2) - } + agent.bindHttp() + sendSpanMethodOnDataCallback = null + const server = new grpc.Server() + server.addService(services.SpanService, { + sendSpan: sendSpan + }) - const spanChunk = Object.assign(new SpanChunk({ - spanId: 7056897257955935, - parentSpanId: -1, - transactionId: { - 'agentId': 'express-node-sample-id', - 'agentStartTime': 1592872080170, - 'sequence': 0 - } - }, { - agentId: 'express-node-sample-id', - applicationName: 'express-node-sample-name', - agentStartTime: 1592872080170 - }), expectedSpanChunk) - grpcDataSender.sendSpanChunk(spanChunk) - const actual = grpcDataSender.actualSpan.getSpanchunk() - - t.plan(16) - t.equal(actual.getVersion(), 1, 'version') - - const actualTransactionId = actual.getTransactionid() - t.equal(actualTransactionId.getAgentid(), 'express-node-sample-id', 'gRPC agentId') - t.equal(actualTransactionId.getAgentstarttime(), 1592872080170, 'agent start time') - t.equal(actualTransactionId.getSequence(), 0, 'sequence') - - t.equal(actual.getSpanid(), 7056897257955935, 'span ID') - t.equal(actual.getEndpoint(), '', 'endpoint') - t.equal(actual.getApplicationservicetype(), 1400, 'application service type') - - const actualLocalAsyncId = actual.getLocalasyncid() - t.equal(actualLocalAsyncId.getAsyncid(), 2, 'local async id') - t.equal(actualLocalAsyncId.getSequence(), 0, 'local async id sequence') - - t.equal(actual.getKeytime(), 1592872091543, 'keytime') - const actualSpanEvents = actual.getSpaneventList() - actualSpanEvents.forEach((pSpanEvent, index) => { - if (index == 1) { - t.equal(pSpanEvent.getSequence(), 1, 'sequence') - t.equal(pSpanEvent.getDepth(), 2, 'depth') - - t.equal(pSpanEvent.getStartelapsed(), 0, 'startElapsed') - - t.equal(pSpanEvent.getServicetype(), 8200, 'serviceType') - - const pAnnotations = pSpanEvent.getAnnotationList() - pAnnotations.forEach(annotation => { - t.equal(annotation.getKey(), 12, 'annotation key') - const pAnnotationValue = annotation.getValue() - t.equal(pAnnotationValue.getStringvalue(), 'redis.GET.end', 'annotation string value') + let dataSender + server.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + const grpcDataSender = beforeSpecificOne(port, DataSource) + const traceRoot = new RemoteTraceRootBuilder(agent.agentInfo, '5').build() + const asyncId = AsyncId.make() + dataSender = makeMockDataSender(agent.config, grpcDataSender) + const spanChunkBuilder = new AsyncSpanChunkBuilder(traceRoot, asyncId) + const repository = new SpanRepository(spanChunkBuilder, dataSender, agent.agentInfo) + const childTraceBuilder = new ChildTraceBuilder(traceRoot, repository, asyncId) + + const spanEventRecorder = childTraceBuilder.traceBlockBegin() + spanEventRecorder.recordServiceType(serviceType.redis) + spanEventRecorder.recordApiDesc('redis.GET.end') + childTraceBuilder.traceBlockEnd(spanEventRecorder) + + agent.completeTraceObject(childTraceBuilder) + + sendSpanMethodOnDataCallback = (actualSpanChunk) => { + t.plan(16) + t.equal(actualSpanChunk.getVersion(), 1, 'version') + + const actualTransactionId = actualSpanChunk.getTransactionid() + t.equal(actualTransactionId.getAgentid(), traceRoot.getAgentId(), 'gRPC agentId') + t.equal(actualTransactionId.getAgentstarttime(), traceRoot.getTraceId().getAgentStartTime(), 'agent start time') + t.equal(actualTransactionId.getSequence(), traceRoot.getTransactionId(), 'sequence') + + t.equal(actualSpanChunk.getSpanid(), traceRoot.getTraceId().getSpanId(), 'span ID') + t.equal(actualSpanChunk.getEndpoint(), '', 'endpoint') + t.equal(actualSpanChunk.getApplicationservicetype(), actualSpanChunk.getApplicationservicetype(), 'application service type') + + const actualLocalAsyncId = actualSpanChunk.getLocalasyncid() + t.equal(actualLocalAsyncId.getAsyncid(), asyncId.getAsyncId(), 'local async id') + t.equal(actualLocalAsyncId.getSequence(), asyncId.getSequence(), 'local async id sequence') + + t.equal(actualSpanChunk.getKeytime(), spanChunkBuilder.keyTime, `keytime ${actualSpanChunk.getKeytime()}`) + const actualSpanEvents = actualSpanChunk.getSpaneventList() + actualSpanEvents.forEach((pSpanEvent, index) => { + if (index == 1) { + t.equal(pSpanEvent.getSequence(), 1, 'sequence') + t.equal(pSpanEvent.getDepth(), 2, 'depth') + + const expectedSpanChunk = repository.dataSender.findSpanChunk(childTraceBuilder.localAsyncId) + const expectedSpanEvent = expectedSpanChunk.spanEventList[0] + t.equal(pSpanEvent.getStartelapsed(), expectedSpanEvent.startElapsedTime, 'startElapsed') + t.equal(pSpanEvent.getServicetype(), 8200, 'serviceType') + + const pAnnotations = pSpanEvent.getAnnotationList() + pAnnotations.forEach(annotation => { + t.equal(annotation.getKey(), 12, 'annotation key') + const pAnnotationValue = annotation.getValue() + t.equal(pAnnotationValue.getStringvalue(), 'redis.GET.end', 'annotation string value') + }) + } }) + afterOne(t) } }) + t.teardown(() => { + dataSender.close() + server.forceShutdown() + }) }) test('sendSpan', (t) => { - let expectedSpanChunk = { - 'traceId': { - 'transactionId': { - 'agentId': 'express-node-sample-id', - 'agentStartTime': 1592872080170, - 'sequence': 0 - }, - 'spanId': 7056897257955935, - 'parentSpanId': -1, - 'flag': 0 - }, - 'agentId': 'express-node-sample-id', - 'applicationName': 'express-node-sample-name', - 'agentStartTime': 1592872080170, - 'serviceType': 1400, - 'spanId': 7056897257955935, - 'parentSpanId': -1, - 'transactionId': { - 'type': 'Buffer', - 'data': [0, 44, 101, 120, 112, 114, 101, 115, 115, 45, 110, 111, 100, 101, 45, 115, 97, 109, 112, 108, 101, 45, 105, 100, 170, 166, 204, 244, 173, 46, 0] - }, - 'startTime': 1592872091536, - 'elapsedTime': 412, - 'rpc': '/', - 'endPoint': 'localhost:3000', - 'remoteAddr': '::1', - 'annotations': [], - 'flag': 0, - 'err': null, - 'spanEventList': [ - Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:3000' - }, 4), { - 'spanId': 7056897257955935, - 'sequence': 4, - 'startTime': 1592872091540, - 'elapsedTime': 1, - 'startElapsed': 4, - 'serviceType': 6600, - 'endPoint': 'localhost:3000', - 'annotations': [Annotations.of(annotationKey.API.getCode(), 'express.middleware.serveStatic')], - 'depth': 5, - 'nextSpanId': -1, - 'destinationId': 'localhost:3000', - 'apiId': 0, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': null, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }), - Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:3000' - }, 3), { - 'spanId': 7056897257955935, - 'sequence': 3, - 'startTime': 1592872091540, - 'elapsedTime': 1, - 'startElapsed': 4, - 'serviceType': 6600, - 'endPoint': 'localhost:3000', - 'annotations': [Annotations.of(annotationKey.API.getCode(), 'express.middleware.cookieParser')], - 'depth': 4, - 'nextSpanId': -1, - 'destinationId': 'localhost:3000', - 'apiId': 0, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': null, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }), - Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:3000' - }, 2), { - 'spanId': 7056897257955935, - 'sequence': 2, - 'startTime': 1592872091540, - 'elapsedTime': 1, - 'startElapsed': 4, - 'serviceType': 6600, - 'endPoint': 'localhost:3000', - 'annotations': [Annotations.of(annotationKey.API.getCode(), 'express.middleware.urlencodedParser')], - 'depth': 3, - 'nextSpanId': -1, - 'destinationId': 'localhost:3000', - 'apiId': 0, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': null, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }), - Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:3000' - }, 1), { - 'spanId': 7056897257955935, - 'sequence': 1, - 'startTime': 1592872091540, - 'elapsedTime': 1, - 'startElapsed': 4, - 'serviceType': 6600, - 'endPoint': 'localhost:3000', - 'annotations': [Annotations.of(annotationKey.API.getCode(), 'express.middleware.jsonParser')], - 'depth': 2, - 'nextSpanId': -1, - 'destinationId': 'localhost:3000', - 'apiId': 0, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': null, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }), - Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:3000' - }, 0), { - 'spanId': 7056897257955935, - 'sequence': 0, - 'startTime': 1592872091539, - 'elapsedTime': 2, - 'startElapsed': 3, - 'serviceType': 6600, - 'endPoint': 'localhost:3000', - 'annotations': [Annotations.of(annotationKey.API.getCode(), 'express.middleware.logger')], - 'depth': 1, - 'nextSpanId': -1, - 'destinationId': 'localhost:3000', - 'apiId': 0, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': null, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }), - Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:3000' - }, 6), { - 'spanId': 7056897257955935, - 'sequence': 6, - 'startTime': 1592872091543, - 'elapsedTime': 0, - 'startElapsed': 7, - 'serviceType': 9057, - 'endPoint': 'localhost:6379', - 'annotations': [Annotations.of(annotationKey.API.getCode(), 'redis.SET.call')], - 'depth': 2, - 'nextSpanId': -1, - 'destinationId': 'Redis', - 'apiId': 0, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': 1, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }), - Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:3000' - }, 7), { - 'spanId': 7056897257955935, - 'sequence': 7, - 'startTime': 1592872091543, - 'elapsedTime': 0, - 'startElapsed': 7, - 'serviceType': 9057, - 'endPoint': 'localhost:6379', - 'annotations': [Annotations.of(annotationKey.API.getCode(), 'redis.GET.call')], - 'depth': 2, - 'nextSpanId': -1, - 'destinationId': 'Redis', - 'apiId': 0, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': 2, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }), - Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:3000' - }, 5), { - 'spanId': 7056897257955935, - 'sequence': 5, - 'startTime': 1592872091542, - 'elapsedTime': 3, - 'startElapsed': 6, - 'serviceType': 6600, - 'endPoint': 'localhost:3000', - 'annotations': [], - 'depth': 1, - 'nextSpanId': -1, - 'destinationId': 'localhost:3000', - 'apiId': 2, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': null, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }), - Object.assign(new SpanEvent({ - spanId: 7056897257955935, - endPoint: 'localhost:3000' - }, 8), { - 'spanId': 7056897257955935, - 'sequence': 8, - 'startTime': 1592872091558, - 'elapsedTime': 0, - 'startElapsed': 22, - 'serviceType': 9057, - 'endPoint': 'localhost:3000', - 'annotations': [Annotations.of(annotationKey.API.getCode(), 'http.request')], - 'depth': 1, - 'nextSpanId': -1, - 'destinationId': 'localhost:3000', - 'apiId': 0, - 'exceptionInfo': null, - 'asyncId': null, - 'nextAsyncId': 3, - 'asyncSequence': null, - 'dummyId': null, - 'nextDummyId': null - }) - ], - 'apiId': 1, - 'exceptionInfo': null, - 'applicationServiceType': 1400, - 'loggingTransactionInfo': null, - 'version': 1 - } + agent.bindHttp() + sendSpanMethodOnDataCallback = null + const server = new grpc.Server() + server.addService(services.SpanService, { + sendSpan: sendSpan + }) - const span = Object.assign(new Span({ - spanId: 2894367178713953, - parentSpanId: -1, - transactionId: { - 'agentId': 'express-node-sample-id', - 'agentStartTime': 1592872080170, - 'sequence': 5 - } - }, { - agentId: 'express-node-sample-id', - applicationName: 'express-node-sample-name', - agentStartTime: 1592872080170 - }), expectedSpanChunk) - grpcDataSender.sendSpan(span) - const actual = grpcDataSender.actualSpan.getSpan() - - t.plan(22) - t.equal(actual.getVersion(), 1, 'version') - - const actualTransactionId = actual.getTransactionid() - t.equal(actualTransactionId.getAgentid(), 'express-node-sample-id', 'gRPC agentId') - t.equal(actualTransactionId.getAgentstarttime(), 1592872080170, 'agent start time') - t.equal(actualTransactionId.getSequence(), 0, 'sequence') - - t.equal(actual.getSpanid(), 7056897257955935, 'span ID') - t.equal(actual.getParentspanid(), -1, 'span.parentspanid') - - t.equal(actual.getStarttime(), 1592872091536, 'span.startTime') - t.equal(actual.getElapsed(), 412, 'span.elapsed') - t.equal(actual.getApiid(), 1, 'span.apiid') - - t.equal(actual.getServicetype(), 1400, 'span.servicetype') - - const actualAcceptEvent = actual.getAcceptevent() - t.equal(actualAcceptEvent.getRpc(), '/', 'rpc') - t.equal(actualAcceptEvent.getEndpoint(), 'localhost:3000', 'endPoint') - t.equal(actualAcceptEvent.getRemoteaddr(), '::1', 'remoteAddr') - - t.equal(actual.getFlag(), 0, 'flag') - t.equal(actual.getErr(), 0, 'Error') - - t.equal(actual.getExceptioninfo(), null, 'span exceptionInfo') - - t.equal(actual.getApplicationservicetype(), 1400, 'applicaiton service type') - t.equal(actual.getLoggingtransactioninfo(), 0, 'logging transaction info') - - const actualSpanEvents = actual.getSpaneventList() - actualSpanEvents.forEach((pSpanEvent, index) => { - if (index == 0) { - t.equal(pSpanEvent.getSequence(), 0, 'sort span events') - t.equal(pSpanEvent.getDepth(), 1, 'depth') - t.equal(pSpanEvent.getStartelapsed(), 3, 'startElapsed') - } - if (pSpanEvent.getSequence() == 6) { - t.equal(pSpanEvent.getAsyncevent(), 1, 'async event') + let dataSender + server.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + const grpcDataSender = beforeSpecificOne(port, DataSource) + const traceRoot = new RemoteTraceRootBuilder(agent.agentInfo, '5').build() + dataSender = makeMockDataSender(agent.config, grpcDataSender) + const spanBuilder = new SpanBuilder(traceRoot) + const spanChunkBuilder = new SpanChunkBuilder(traceRoot) + const repository = new SpanRepository(spanChunkBuilder, dataSender, agent.agentInfo) + const trace = new Trace(spanBuilder, repository) + trace.spanRecorder.recordApi(defaultPredefinedMethodDescriptorRegistry.nodeServerMethodDescriptor) + trace.spanRecorder.recordServiceType(serviceType.node) + trace.spanRecorder.recordRpc('/') + trace.spanRecorder.recordEndPoint('localhost:3000') + trace.spanRecorder.recordRemoteAddress('::1') + + let spanEventRecorder = trace.traceBlockBegin() + spanEventRecorder.spanEventBuilder.startTime = spanBuilder.startTime + 3 + trace.traceBlockEnd(spanEventRecorder) + + spanEventRecorder = trace.traceBlockBegin() + trace.traceBlockEnd(spanEventRecorder) + + spanEventRecorder = trace.traceBlockBegin() + trace.traceBlockEnd(spanEventRecorder) + + spanEventRecorder = trace.traceBlockBegin() + trace.traceBlockEnd(spanEventRecorder) + + spanEventRecorder = trace.traceBlockBegin() + trace.traceBlockEnd(spanEventRecorder) + + spanEventRecorder = trace.traceBlockBegin() + trace.traceBlockEnd(spanEventRecorder) + + spanEventRecorder = trace.traceBlockBegin() + const asyncId = spanEventRecorder.getNextAsyncId() + trace.traceBlockEnd(spanEventRecorder) + + agent.completeTraceObject(trace) + + sendSpanMethodOnDataCallback = (actualSpan) => { + t.plan(22) + t.equal(actualSpan.getVersion(), 1, 'version') + + const actualTransactionId = actualSpan.getTransactionid() + t.equal(actualTransactionId.getAgentid(), traceRoot.getAgentId(), 'gRPC agentId') + t.equal(actualTransactionId.getAgentstarttime(), traceRoot.getTraceId().getAgentStartTime(), 'agent start time') + t.equal(actualTransactionId.getSequence(), traceRoot.getTransactionId(), 'sequence') + + t.equal(actualSpan.getSpanid(), traceRoot.getTraceId().getSpanId(), 'span ID') + t.equal(actualSpan.getParentspanid(), traceRoot.getTraceId().getParentSpanId(), 'span.parentspanid') + + t.equal(actualSpan.getStarttime(), spanBuilder.startTime, 'span.startTime') + t.equal(actualSpan.getElapsed(), spanBuilder.elapsedTime, 'span.elapsed') + t.equal(actualSpan.getApiid(), 1, 'span.apiid') + + t.equal(actualSpan.getServicetype(), 1400, 'span.servicetype') + + const actualAcceptEvent = actualSpan.getAcceptevent() + t.equal(actualAcceptEvent.getRpc(), '/', 'rpc') + t.equal(actualAcceptEvent.getEndpoint(), 'localhost:3000', 'endPoint') + t.equal(actualAcceptEvent.getRemoteaddr(), '::1', 'remoteAddr') + + t.equal(actualSpan.getFlag(), 0, 'flag') + t.equal(actualSpan.getErr(), 0, 'Error') + + t.equal(actualSpan.getExceptioninfo(), undefined, 'span exceptionInfo') + + t.equal(actualSpan.getApplicationservicetype(), 1400, 'applicaiton service type') + t.equal(actualSpan.getLoggingtransactioninfo(), 0, 'logging transaction info') + + const actualSpanEvents = actualSpan.getSpaneventList() + actualSpanEvents.forEach((pSpanEvent, index) => { + if (index == 0) { + t.equal(pSpanEvent.getSequence(), 0, 'sort span events') + t.equal(pSpanEvent.getDepth(), 1, 'depth') + t.equal(pSpanEvent.getStartelapsed(), 3, 'startElapsed') + } + if (pSpanEvent.getSequence() == 6) { + t.equal(pSpanEvent.getAsyncevent(), asyncId.getAsyncId(), 'async event') + } + }) + afterOne(t) } }) + t.teardown(() => { + dataSender.close() + server.forceShutdown() + }) }) test.skip('sendStat', (t) => { diff --git a/test/client/grpc-fixture.js b/test/client/grpc-fixture.js index 9b1d8329..331417cb 100644 --- a/test/client/grpc-fixture.js +++ b/test/client/grpc-fixture.js @@ -102,6 +102,11 @@ class DataSourceCallCountable extends GrpcDataSender { super.sendSpan(span) } + sendSpanChunk(spanChunk) { + increaseCallCount() + super.sendSpanChunk(spanChunk) + } + sendSupportedServicesCommand(callArguments) { increaseCallCount() super.sendSupportedServicesCommand(callArguments) diff --git a/test/client/mock-grpc-data-sender.js b/test/client/mock-grpc-data-sender.js index 6df85a77..7ad8b86d 100644 --- a/test/client/mock-grpc-data-sender.js +++ b/test/client/mock-grpc-data-sender.js @@ -83,11 +83,22 @@ class MockGrpcDataSender extends GrpcDataSender { } initializePingStream() { + let self = this + this.pingStream = { + write: function (pmessage) { + self.actualPingMessage = pmessage + }, + end: function () { + + }, + on: function () { + } + } } initializeAgentInfoScheduler() { - + } sendSupportedServicesCommand() { diff --git a/test/context/callstack.test.js b/test/context/callstack.test.js index c7457e2b..a82cdd75 100644 --- a/test/context/callstack.test.js +++ b/test/context/callstack.test.js @@ -15,28 +15,29 @@ const MethodDescriptorBuilder = require('../../lib/context/method-descriptor-bui const localStorage = require('../../lib/instrumentation/context/local-storage') const http = require('http') const https = require('https') +const semver = require('semver') test(`span and spanEvent call stack`, async (t) => { agent.bindHttp() t.plan(11) - - const trace = agent.createTraceObject() + const traceContext = agent.getTraceContext() + const trace = traceContext.newTraceObject2() localStorage.run(trace, () => { t.equal(trace.callStack.length ?? trace.callStack.stack.length, 0, 'callstack is 0') - t.equal(agent.traceContext.currentTraceObject(), trace, 'current trace is current asyncId trace object') + t.equal(traceContext.currentTraceObject(), trace, 'current trace is current asyncId trace object') axios.get(`https://github.com`, { httpAgent: new http.Agent({ keepAlive: false }) }) .then(function (response) { t.true(response.status == 200) - t.equal(agent.traceContext.currentTraceObject(), trace, 'current trace is current asyncId trace object') - t.equal(agent.dataSender.mockSpanChunks[0].spanEventList.length, 2, 'spanEventList length') - t.equal(agent.dataSender.mockSpanChunks[0].spanEventList[0].annotations[0].key, 12, 'APIDesc key') - t.equal(agent.dataSender.mockSpanChunks[0].spanEventList[0].annotations[0].value, 'GET', 'APIDesc stringValue') - t.equal(agent.dataSender.mockSpanChunks[0].spanEventList[0].annotations[1].key, 40, 'HTTP.URL key') - t.equal(agent.dataSender.mockSpanChunks[0].spanEventList[0].annotations[1].value, 'github.com/', 'HTTP.URL stringValue') - t.equal(agent.dataSender.mockSpanChunks[0].spanEventList[0].annotations[2].key, 46, 'HTTP.status.code') - t.equal(agent.dataSender.mockSpanChunks[0].spanEventList[0].annotations[2].value, 200, 'HTTP.status.code stringValue') + t.equal(traceContext.currentTraceObject(), trace, 'current trace is current asyncId trace object') + t.equal(trace.repository.dataSender.mockSpanChunks[0].spanEventList.length, 2, 'spanEventList length') + t.equal(trace.repository.dataSender.mockSpanChunks[0].spanEventList[1].annotations[0].key, 12, 'APIDesc key') + t.equal(trace.repository.dataSender.mockSpanChunks[0].spanEventList[1].annotations[0].value, 'GET', 'APIDesc stringValue') + t.equal(trace.repository.dataSender.mockSpanChunks[0].spanEventList[1].annotations[1].key, 40, 'HTTP.URL key') + t.equal(trace.repository.dataSender.mockSpanChunks[0].spanEventList[1].annotations[1].value, 'github.com/', 'HTTP.URL stringValue') + t.equal(trace.repository.dataSender.mockSpanChunks[0].spanEventList[1].annotations[2].key, 46, 'HTTP.status.code') + t.equal(trace.repository.dataSender.mockSpanChunks[0].spanEventList[1].annotations[2].value, 200, 'HTTP.status.code stringValue') agent.completeTraceObject(trace) }) }) @@ -71,15 +72,15 @@ test(`fix express call stack depth`, async (t) => { t.ok(result1.status, 200) t.ok(result1.data, 'ok router1') - t.equal(agent.dataSender.mockSpan.spanEventList.length, 4, `span has 6 span events`) - t.equal(agent.dataSender.mockSpan.apiId, defaultPredefinedMethodDescriptorRegistry.nodeServerMethodDescriptor.getApiId(), 'nodeServerMethodDescriptor apiId') + t.equal(agent.getTraces(0).repository.dataSender.mockSpan.spanEventList.length, 4, `span has 6 span events`) + t.equal(agent.getTraces(0).repository.dataSender.mockSpan.apiId, defaultPredefinedMethodDescriptorRegistry.nodeServerMethodDescriptor.getApiId(), 'nodeServerMethodDescriptor apiId') let actualBuilder = new MethodDescriptorBuilder('use') .setClassName('Router') - .setLineNumber(56) + .setLineNumber(57) .setFileName('callstack.test.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = agent.dataSender.mockSpan.spanEventList[0] + let actualSpanEvent = agent.getTraces(0).repository.dataSender.mockSpan.spanEventList[0] t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'use(jsonParser) apiId') t.equal(actualSpanEvent.sequence, 0, 'use(jsonParser) sequence') t.equal(actualSpanEvent.depth, 1, 'use(jsonParser) depth') @@ -87,16 +88,34 @@ test(`fix express call stack depth`, async (t) => { actualBuilder = new MethodDescriptorBuilder('use') .setClassName('Router') - .setLineNumber(57) + .setLineNumber(58) .setFileName('callstack.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = agent.dataSender.mockSpan.spanEventList[1] + actualSpanEvent = agent.getTraces(0).repository.dataSender.mockSpan.spanEventList[1] t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'use(urlencodedParser) apiId') t.equal(actualSpanEvent.sequence, 1, 'use(urlencodedParser) sequence') t.equal(actualSpanEvent.depth, 1, 'use(urlencodedParser) depth') t.equal(actualSpanEvent.serviceType, ServiceTypeCode.express, 'use(urlencodedParser) serviceType') - actualSpanEvent = agent.dataSender.mockSpan.spanEventList[2] + if (semver.satisfies(process.versions.node, '>=17.0')) { + actualBuilder = new MethodDescriptorBuilder('get') + .setClassName('proto') + .setLineNumber(63) + .setFileName('callstack.test.js') + } else { + actualBuilder = new MethodDescriptorBuilder('get') + .setClassName('Function.proto') + .setLineNumber(63) + .setFileName('callstack.test.js') + } + actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) + actualSpanEvent = agent.getTraces(0).repository.dataSender.mockSpan.spanEventList[2] + t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'get(/) apiId') + t.equal(actualSpanEvent.sequence, 2, 'get(/) sequence') + t.equal(actualSpanEvent.depth, 1, 'get(/) depth') + t.equal(actualSpanEvent.serviceType, ServiceTypeCode.express, 'get(/) serviceType') + + actualSpanEvent = agent.getTraces(0).repository.dataSender.mockSpan.spanEventList[3] t.equal(actualSpanEvent.apiId, 0, 'await axios.get(`https://naver.com`) apiId') t.equal(actualSpanEvent.sequence, 3, 'await axios.get(`https://naver.com`) sequence') t.equal(actualSpanEvent.depth, 2, 'await axios.get(`https://naver.com`) depth') @@ -106,11 +125,10 @@ test(`fix express call stack depth`, async (t) => { t.equal(actualAnnotation.key, 12, 'await axios.get(`https://naver.com`) spanevent annotation key') t.equal(actualAnnotation.value, 'http.request', 'await axios.get(`https://naver.com`) spanevent annotation value') - t.equal(agent.dataSender.mockSpanChunks.length, 1, 'await axios.get(`https://naver.com`) spanchunk is 1') - let actualSpanChunk = agent.dataSender.mockSpanChunks[0] - t.equal(actualSpanChunk.agentId, agent.dataSender.mockSpan.agentId, 'await axios.get(`https://naver.com`) spanchunk agentId') - t.equal(actualSpanEvent.nextAsyncId, actualSpanChunk.localAsyncId.asyncId, 'await axios.get(`https://naver.com`) nextAsyncId') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'await axios.get(`https://naver.com`) spanchunk localAsyncId.asyncId') + t.equal(agent.getTraces(0).repository.dataSender.mockSpanChunks.length, 1, 'await axios.get(`https://naver.com`) spanchunk is 1') + let actualSpanChunk = agent.getTraces(0).repository.dataSender.mockSpanChunks[0] + t.equal(actualSpanChunk.agentId, agent.getTraces(0).repository.dataSender.mockSpan.agentId, 'await axios.get(`https://naver.com`) spanchunk agentId') + t.equal(actualSpanEvent.asyncId.asyncId, actualSpanChunk.localAsyncId.asyncId, 'await axios.get(`https://naver.com`) nextAsyncId') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'await axios.get(`https://naver.com`) spanchunk localAsyncId.sequence') t.end() @@ -146,13 +164,13 @@ test('fix express call stack depth without callSite', async (t) => { t.ok(result1.status, 200) t.ok(result1.data, 'ok router1') - t.equal(agent.dataSender.mockSpan.spanEventList.length, 4, `span has 6 span events`) - t.equal(agent.dataSender.mockSpan.apiId, defaultPredefinedMethodDescriptorRegistry.nodeServerMethodDescriptor.getApiId(), 'nodeServerMethodDescriptor apiId') + t.equal(agent.getTraces(0).repository.dataSender.mockSpan.spanEventList.length, 4, `span has 6 span events`) + t.equal(agent.getTraces(0).repository.dataSender.mockSpan.apiId, defaultPredefinedMethodDescriptorRegistry.nodeServerMethodDescriptor.getApiId(), 'nodeServerMethodDescriptor apiId') let actualBuilder = new MethodDescriptorBuilder('use') .setClassName('Router') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = agent.dataSender.mockSpan.spanEventList[0] + let actualSpanEvent = agent.getTraces(0).repository.dataSender.mockSpan.spanEventList[0] t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'use(jsonParser) apiId') t.equal(actualSpanEvent.sequence, 0, 'use(jsonParser) sequence') t.equal(actualSpanEvent.depth, 1, 'use(jsonParser) depth') @@ -161,13 +179,13 @@ test('fix express call stack depth without callSite', async (t) => { actualBuilder = new MethodDescriptorBuilder('use') .setClassName('Router') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = agent.dataSender.mockSpan.spanEventList[1] + actualSpanEvent = agent.getTraces(0).repository.dataSender.mockSpan.spanEventList[1] t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'use(urlencodedParser) apiId') t.equal(actualSpanEvent.sequence, 1, 'use(urlencodedParser) sequence') t.equal(actualSpanEvent.depth, 1, 'use(urlencodedParser) depth') t.equal(actualSpanEvent.serviceType, ServiceTypeCode.express, 'use(urlencodedParser) serviceType') - actualSpanEvent = agent.dataSender.mockSpan.spanEventList[2] + actualSpanEvent = agent.getTraces(0).repository.dataSender.mockSpan.spanEventList[3] t.equal(actualSpanEvent.apiId, 0, 'await axios.get(`https://naver.com`) apiId') t.equal(actualSpanEvent.sequence, 3, 'await axios.get(`https://naver.com`) sequence') t.equal(actualSpanEvent.depth, 2, 'await axios.get(`https://naver.com`) depth') @@ -176,11 +194,11 @@ test('fix express call stack depth without callSite', async (t) => { t.equal(actualAnnotation.key, 12, 'await axios.get(`https://naver.com`) spanevent annotation key') t.equal(actualAnnotation.value, 'http.request', 'await axios.get(`https://naver.com`) spanevent annotation value') - t.equal(agent.dataSender.mockSpanChunks.length, 1, 'await axios.get(`https://naver.com`) spanchunk is 1') - let actualSpanChunk = agent.dataSender.mockSpanChunks[0] - t.equal(actualSpanChunk.agentId, agent.dataSender.mockSpan.agentId, 'await axios.get(`https://naver.com`) spanchunk agentId') - t.equal(actualSpanEvent.nextAsyncId, actualSpanChunk.localAsyncId.asyncId, 'await axios.get(`https://naver.com`) nextAsyncId') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'await axios.get(`https://naver.com`) spanchunk localAsyncId.asyncId') + t.equal(agent.getTraces(0).repository.dataSender.mockSpanChunks.length, 1, 'await axios.get(`https://naver.com`) spanchunk is 1') + let actualSpanChunk = agent.getTraces(0).repository.dataSender.mockSpanChunks[0] + t.equal(actualSpanChunk.agentId, agent.getTraces(0).repository.dataSender.mockSpan.agentId, 'await axios.get(`https://naver.com`) spanchunk agentId') + t.equal(actualSpanEvent.asyncId.asyncId, actualSpanChunk.localAsyncId.asyncId, 'await axios.get(`https://naver.com`) nextAsyncId') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.asyncId.asyncId, 'await axios.get(`https://naver.com`) spanchunk localAsyncId.asyncId') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'await axios.get(`https://naver.com`) spanchunk localAsyncId.sequence') t.end() diff --git a/test/context/trace-context.test.js b/test/context/trace-context.test.js index b716790d..32b95074 100644 --- a/test/context/trace-context.test.js +++ b/test/context/trace-context.test.js @@ -14,23 +14,21 @@ const RequestHeaderUtils = require('../../lib/instrumentation/request-header-uti const defaultPredefinedMethodDescriptorRegistry = require('../../lib/constant/default-predefined-method-descriptor-registry') const localStorage = require('../../lib/instrumentation/context/local-storage') const agent = require('../support/agent-singleton-mock') +const TraceIdBuilder = require('../../lib/context/trace/trace-id-builder') test('Should create continued trace and add span info', function (t) { t.plan(2) - const transactionId = fixture.getTransactionId() - const traceId = fixture.getTraceId(transactionId) - traceId.sampled = true const traceContext = new TraceContext(agent.agentInfo, dataSenderMock(), agent.config) - - const trace = traceContext.continueTraceObject(traceId) + const traceId = new TraceIdBuilder(agent.agentInfo.getAgentId(), agent.agentInfo.getAgentStartTime(), '9').build() + const trace = traceContext.continueTraceObject2(traceId) localStorage.run(trace, () => { - t.equal(traceContext.currentTraceObject().traceId.transactionId.toString(), transactionId.toString()) - + t.equal(traceContext.currentTraceObject().getTraceId(), traceId, `traceId is ${traceId}`) + trace.spanRecorder.recordServiceType(ServiceType.express) trace.spanRecorder.recordApi(defaultPredefinedMethodDescriptorRegistry.nodeServerMethodDescriptor) - - t.equal(traceContext.currentTraceObject().span.serviceType, ServiceType.express) + + t.equal(traceContext.currentTraceObject().spanBuilder.serviceType, ServiceType.express.getCode()) traceContext.completeTraceObject(trace) }) }) @@ -40,45 +38,41 @@ test('Should begin/end trace block asynchronously', async function (t) { // start trace and write span info const traceContext = new TraceContext(agent.agentInfo, dataSenderMock(), agent.config) - const startedTrace = traceContext.newTraceObject(true) + const startedTrace = traceContext.newTraceObject2('/') localStorage.run(startedTrace, () => { const spanRecorder = startedTrace.spanRecorder spanRecorder.recordServiceType(ServiceType.express) - + const currentTrace = traceContext.currentTraceObject() const spanEventRecorder = currentTrace.traceBlockBegin() spanEventRecorder.recordServiceType(ServiceType.express) spanEventRecorder.recordApi(defaultPredefinedMethodDescriptorRegistry.nodeServerMethodDescriptor) - - t.equal(traceContext.currentTraceObject().callStack.length, 1) - + + t.equal(traceContext.currentTraceObject().callStack.stack.length, 1) + const anotherContext = traceContext.currentTraceObject() t.equal(anotherContext.traceId, currentTrace.traceId) - + const spanEventRecorder2 = anotherContext.traceBlockBegin() - t.equal(traceContext.currentTraceObject().callStack.length, 2) - + t.equal(traceContext.currentTraceObject().callStack.stack.length, 2) + anotherContext.traceBlockEnd(spanEventRecorder2) - + currentTrace.traceBlockEnd(spanEventRecorder) - t.equal(traceContext.currentTraceObject().callStack.length, 0, "traceBolckEnd callstack length is zero") + t.equal(traceContext.currentTraceObject().callStack.stack.length, 0, "traceBolckEnd callstack length is zero") }) }) test('Should complete trace ', async function (t) { t.plan(1) - - const transactionId = fixture.getTransactionId() - const traceId = fixture.getTraceId(transactionId) const traceContext = new TraceContext(agent.agentInfo, dataSenderMock(), agent.config) - - const trace = traceContext.newTraceObject(traceId) + const trace = traceContext.newTraceObject2('/') await util.sleep(501) traceContext.completeTraceObject(trace) - t.ok(trace.spanRecorder.span.elapsedTime > 0) + t.ok(trace.spanRecorder.spanBuilder.elapsedTime > 0) }) test('new Trace', (t) => { diff --git a/test/fixture.js b/test/fixture.js index 28624f55..5c15fe8b 100644 --- a/test/fixture.js +++ b/test/fixture.js @@ -7,18 +7,16 @@ const TransactionId = require('../lib/context/transaction-id') const TraceId = require('../lib/context/trace-id') const SpanId = require('../lib/context/span-id') -const shimmer = require('@pinpoint-apm/shimmer') const testConfig= require('./pinpoint-config-test') require('../lib/config').clear() const config = require('../lib/config').getConfig(testConfig) const { namedGroupLocationFileName, namedGroupTypeMethod } = require('../lib/instrumentation/call-stack') -const TraceBuilder = require('../lib/instrumentation/context/trace-builder') const localStorage = require('../lib/instrumentation/context/local-storage') const getTransactionId = () => { const agentId = config.agentId const agentStartTime = Date.now() - return new TransactionId(agentId, agentStartTime.toString(), "99") + return new TransactionId(agentId, agentStartTime.toString(), '99') } const getTraceId = (transactionId) => { @@ -38,25 +36,6 @@ const captureNamedGroup = (callSite) => { , namedGroupTypeMethod([callSite], 0)) } -let actualAsyncTraces = [] -shimmer.wrap(TraceBuilder.prototype, 'buildAsyncTrace', function (original) { - return function () { - const asyncTrace = original.apply(this, arguments) - actualAsyncTraces.push(asyncTrace) - return asyncTrace - } -}) - -function getAsyncTraceByAsyncId(asyncId) { - return actualAsyncTraces.find((trace) => { - return trace.asyncId.asyncId === asyncId - }) -} - -function cleanup() { - actualAsyncTraces = [] -} - function assertSpanChunk(asyncTrace, callback) { const origin = asyncTrace.close asyncTrace.close = function () { @@ -80,8 +59,6 @@ module.exports = { getTraceId, getAgentInfo, captureNamedGroup, - getAsyncTraceByAsyncId, assertSpanChunk, assertTrace, - cleanup } diff --git a/test/fixtures/mock-data-sender.js b/test/fixtures/mock-data-sender.js new file mode 100644 index 00000000..89688894 --- /dev/null +++ b/test/fixtures/mock-data-sender.js @@ -0,0 +1,65 @@ +/** + * Pinpoint Node.js Agent + * Copyright 2020-present NAVER Corp. + * Apache License v2.0 + */ + +'use strict' + +const DataSender = require('../../lib/client/data-sender') +const AgentInfo = require('../../lib/data/dto/agent-info') +const ApiMetaInfo = require('../../lib/data/dto/api-meta-info') +const StringMetaInfo = require('../../lib/data/dto/string-meta-info') +const Span = require('../../lib/context/span') +const SpanChunk = require('../../lib/context/span-chunk') +const SqlMetaData = require('../../lib/client/sql-meta-data') + +class MockDataSender extends DataSender { + constructor(config, dataSender) { + super(config, dataSender) + this.mockAPIMetaInfos = [] + this.mockSpanChunks = [] + this.mockSpans = [] + } + + send(data) { + if (data instanceof AgentInfo) { + this.mockAgentInfo = data + super.send(data) + } else if (data instanceof ApiMetaInfo) { + this.mockAPIMetaInfos.push(data) + super.send(data) + } else if (data instanceof StringMetaInfo) { + this.mockMetaInfo = data + super.send(data) + } else if (data instanceof Span) { + this.mockSpan = data + this.mockSpans.push(data) + super.send(data) + } else if (data instanceof SpanChunk) { + this.mockSpanChunks.push(data) + super.send(data) + } else if (data instanceof SqlMetaData) { + this.mockSqlMetaData = data + super.send(data) + } else if (data?.isAsyncSpanChunk?.()) { + this.mockSpanChunks.push(data) + super.send(data) + } else if (data?.isSpan?.()) { + this.mockSpan = data + this.mockSpans.push(data) + super.send(data) + } + } + + findSpanChunk(asyncId) { + return this.mockSpanChunks.find(spanChunk => spanChunk.localAsyncId.asyncId === (asyncId.asyncId || asyncId)) + } + findSpanEvent(apiId) { + return this.mockSpan.spanEventList.find(event => event.apiId === apiId) + } +} + +const makeMockDataSender = (config, dataSender) => new MockDataSender(config, dataSender) + +module.exports = makeMockDataSender \ No newline at end of file diff --git a/test/instrumentation/context/nested-async-trace.test.js b/test/instrumentation/context/nested-async-trace.test.js index b517074f..9e130b5f 100644 --- a/test/instrumentation/context/nested-async-trace.test.js +++ b/test/instrumentation/context/nested-async-trace.test.js @@ -21,7 +21,7 @@ const mysqlExecuteQueryServiceType = require('../../../lib/instrumentation/modul const defaultPredefinedMethodDescriptorRegistry = require('../../../lib/constant/default-predefined-method-descriptor-registry') const ServiceType = require('../../../lib/context/service-type') const mysql2 = require('mysql2') -const mysql2p = require('mysql2/promise') + test(`nested mysql async query with express`, async (t) => { agent.bindHttpWithCallSite() @@ -72,7 +72,7 @@ test(`nested mysql async query with express`, async (t) => { .setLineNumber(42) .setFileName('nested-async-trace.test.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence === 0) + let actualSpanEvent = trace.repository.dataSender.mockSpan.spanEventList.find( spanEvent => spanEvent.sequence === 0) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId is equal') t.equal(actualMethodDescriptor.apiDescriptor, expected('app.get', 'Function.app.get'), 'apiDescriptor is equal') t.equal(actualMethodDescriptor.className, expected('app', 'Function'), 'className is equal') @@ -85,7 +85,7 @@ test(`nested mysql async query with express`, async (t) => { .setLineNumber(43) .setFileName('nested-async-trace.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence === 1) + actualSpanEvent = trace.repository.dataSender.mockSpan.spanEventList.find( spanEvent => spanEvent.sequence === 1) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId is equal') t.equal(actualSpanEvent.endPoint, 'localhost', 'endPoint is equal') t.equal(actualSpanEvent.destinationId, 'test', 'destinationId is equal') @@ -98,37 +98,37 @@ test(`nested mysql async query with express`, async (t) => { .setLineNumber(52) .setFileName('nested-async-trace.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence === 2) + actualSpanEvent = trace.repository.dataSender.mockSpan.spanEventList.find( spanEvent => spanEvent.sequence === 2) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId is equal') t.equal(actualSpanEvent.sequence, 2, 'sequence is 2') t.equal(actualSpanEvent.depth, 2, 'depth is 3') t.equal(actualSpanEvent.serviceType, mysqlServiceType.getCode(), 'serviceType is mysql') - let actualNextAsyncId = actualSpanEvent.nextAsyncId + let actualNextAsyncId = actualSpanEvent.asyncId - let actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualNextAsyncId) - t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanId is equal') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionIdObject is equal') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'localAsyncId is equal') + let actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualNextAsyncId) + t.equal(actualSpanChunk.traceRoot.getTraceId().getSpanId(), trace.spanBuilder.getTraceRoot().getTraceId().getSpanId(), 'spanId is equal') + t.equal(actualSpanChunk.getTraceRoot(), trace.getTraceRoot(), 'traceRoot is equal') + t.equal(actualSpanChunk.localAsyncId.getAsyncId(), actualSpanEvent.asyncId.getAsyncId(), 'localAsyncId is equal') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId.sequence is equal') t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'apiId is equal') t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'depth is equal') t.equal(actualSpanChunk.spanEventList[0].sequence, 0, 'sequence is equal') t.equal(actualSpanChunk.spanEventList[0].serviceType, ServiceType.async.getCode(), 'serviceType is mysql') - const actualSpanChunkGrpc = agent.dataSender.dataSender.actualSpans[0].getSpanchunk() + const actualSpanChunkGrpc = trace.repository.dataSender.dataSender.actualSpans[0].getSpanchunk() t.equal(actualSpanChunkGrpc.getVersion(), 1, 'PSpanChunk.version is 1') - + const actualTractionId = actualSpanChunkGrpc.getTransactionid() - t.equal(actualTractionId.getAgentid(), trace.traceId.transactionId.agentId, `PSpanChunk.PTransactionId.agentId is ${trace.traceId.transactionId.agentId}`) + t.equal(actualTractionId.getAgentid(), trace.getTraceRoot().getAgentId(), `PSpanChunk.PTransactionId.agentId is ${trace.getTraceRoot().getAgentId()}`) t.equal(typeof actualTractionId.getAgentid(), 'string', 'PSpanChunk.PTransactionId.agentId type is string') - t.equal(actualTractionId.getAgentstarttime(), trace.traceId.transactionId.agentStartTime, `PSpanChunk.PTransactionId.agentStartTime is ${trace.traceId.transactionId.agentStartTime}`) + t.equal(actualTractionId.getAgentstarttime(), trace.getTraceId().getAgentStartTime(), `PSpanChunk.PTransactionId.agentStartTime is ${trace.getTraceId().getAgentStartTime()}`) t.equal(typeof actualTractionId.getAgentstarttime(), 'string', 'PSpanChunk.PTransactionId.agentStartTime type is string') - t.equal(actualTractionId.getSequence(), trace.traceId.transactionId.sequence, `PSpanChunk.PTransactionId.sequence is ${trace.traceId.transactionId.sequence}`) + t.equal(actualTractionId.getSequence(), trace.getTraceRoot().getTransactionId(), `PSpanChunk.PTransactionId.sequence is ${trace.getTraceRoot().getTransactionId()}`) t.equal(typeof actualTractionId.getSequence(), 'string', 'PSpanChunk.PTransactionId.sequence type is string') - t.equal(actualSpanChunkGrpc.getSpanid(), actualSpanChunk.spanId, `PSpanChunk.spanId is ${actualSpanEvent.spanId}`) + t.equal(actualSpanChunkGrpc.getSpanid(), actualSpanChunk.getTraceRoot().getTraceId().getSpanId(), `PSpanChunk.spanId is ${actualSpanChunk.getTraceRoot().getTraceId().getSpanId()}`) t.equal(typeof actualSpanChunkGrpc.getSpanid(), 'string', 'PSpanChunk.spanId type is string') - t.equal(actualSpanChunkGrpc.getEndpoint(), '', `PSpanChunk.endPoint is ${actualSpanChunk.endPoint}`) + t.equal(actualSpanChunkGrpc.getEndpoint(), '', `PSpanChunk.endPoint is '${actualSpanChunkGrpc.getEndpoint()}'`) t.equal(typeof actualSpanChunkGrpc.getEndpoint(), 'string', 'PSpanChunk.endPoint type is string') t.equal(actualSpanChunkGrpc.getApplicationservicetype(), actualSpanChunk.applicationServiceType, `PSpanChunk.applicationServiceType is ${actualSpanChunk.applicationServiceType}`) t.equal(typeof actualSpanChunkGrpc.getApplicationservicetype(), 'number', 'PSpanChunk.applicationServiceType type is number') @@ -146,39 +146,39 @@ test(`nested mysql async query with express`, async (t) => { .setLineNumber(58) .setFileName('nested-async-trace.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence === 3) + actualSpanEvent = trace.spanBuilder.spanEventList.find( spanEvent => spanEvent.sequence === 3) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId is equal') t.equal(actualSpanEvent.sequence, 3, 'sequence is 3') t.equal(actualSpanEvent.depth, 2, 'depth is 2') t.equal(actualSpanEvent.serviceType, mysqlExecuteQueryServiceType.getCode(), 'serviceType is mysql') - actualNextAsyncId = actualSpanEvent.nextAsyncId + actualNextAsyncId = actualSpanEvent.asyncId - actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualNextAsyncId) - t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanId is equal') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionIdObject is equal') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'localAsyncId is equal') + actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualNextAsyncId) + t.equal(actualSpanChunk.getTraceRoot(), trace.spanBuilder.getTraceRoot(), 'traceRoot is equal') + t.equal(actualSpanChunk.getTraceRoot().getTransactionId(), trace.spanBuilder.getTraceRoot().getTransactionId(), 'transactionIdObject is equal') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.asyncId.asyncId, 'localAsyncId is equal') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId.sequence is equal') - t.equal(actualSpanChunk.spanEventList[1].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'apiId is equal') - t.equal(actualSpanChunk.spanEventList[1].depth, 1, 'depth is equal') - t.equal(actualSpanChunk.spanEventList[1].sequence, 0, 'sequence is equal') - t.equal(actualSpanChunk.spanEventList[1].serviceType, ServiceType.async.getCode(), 'serviceType is mysql') + t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'apiId is equal') + t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'depth is equal') + t.equal(actualSpanChunk.spanEventList[0].sequence, 0, 'sequence is equal') + t.equal(actualSpanChunk.spanEventList[0].serviceType, ServiceType.async.getCode(), 'serviceType is mysql') actualBuilder = new MethodDescriptorBuilder('query') .setClassName('Connection') .setLineNumber(64) .setFileName('nested-async-trace.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = actualSpanChunk.spanEventList[0] + actualSpanEvent = actualSpanChunk.spanEventList[1] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId is equal') t.equal(actualSpanEvent.depth, 2, 'depth is 3') t.equal(actualSpanEvent.sequence, 1, 'sequence is 2') t.equal(actualSpanEvent.serviceType, mysqlExecuteQueryServiceType.getCode(), 'serviceType is mysql') - actualNextAsyncId = actualSpanEvent.nextAsyncId + actualNextAsyncId = actualSpanEvent.asyncId - actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualNextAsyncId) + actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualNextAsyncId) t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanId is equal') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionIdObject is equal') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId, 'localAsyncId is equal') + t.equal(actualSpanChunk.getTraceRoot().getTransactionId(), trace.spanBuilder.getTraceRoot().getTransactionId(), 'transactionIdObject is equal') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId.asyncId, 'localAsyncId is equal') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId.sequence is equal') t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'apiId is equal') t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'depth is equal') @@ -232,7 +232,7 @@ test(`nested mysql2 async query with express`, async (t) => { t.equal(results[0].joined.getDate(), new Date('2023-01-18T00:00:00+09:00').getDate(), 'SELECT member joined') connection.query(`SELECT * FROM member WHERE id = ?`, results[0].id, async function (error, results) { - + }) }) @@ -251,7 +251,7 @@ test(`nested mysql2 async query with express`, async (t) => { .setLineNumber(218) .setFileName('nested-async-trace.test.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence === 0) + let actualSpanEvent = trace.spanBuilder.spanEventList.find( spanEvent => spanEvent.sequence === 0) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId is equal') t.equal(actualMethodDescriptor.apiDescriptor, expected('app.get', 'Function.app.get'), 'apiDescriptor is equal') t.equal(actualMethodDescriptor.className, expected('app', 'Function'), 'className is equal') @@ -264,7 +264,7 @@ test(`nested mysql2 async query with express`, async (t) => { .setLineNumber(219) .setFileName('nested-async-trace.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence === 1) + actualSpanEvent = trace.spanBuilder.spanEventList.find( spanEvent => spanEvent.sequence === 1) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId is equal') t.equal(actualSpanEvent.endPoint, 'localhost', 'endPoint is equal') t.equal(actualSpanEvent.destinationId, 'test', 'destinationId is equal') @@ -277,39 +277,39 @@ test(`nested mysql2 async query with express`, async (t) => { .setLineNumber(228) .setFileName('nested-async-trace.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence === 2) + actualSpanEvent = trace.spanBuilder.spanEventList.find( spanEvent => spanEvent.sequence === 2) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId is equal') t.equal(actualSpanEvent.sequence, 2, 'sequence is 2') t.equal(actualSpanEvent.depth, 2, 'depth is 2') t.equal(actualSpanEvent.serviceType, mysqlExecuteQueryServiceType.getCode(), 'serviceType is mysql') - let actualNextAsyncId = actualSpanEvent.nextAsyncId + let actualNextAsyncId = actualSpanEvent.asyncId - let actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualNextAsyncId) + let actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualNextAsyncId) t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanId is equal') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionIdObject is equal') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'localAsyncId is equal') + t.equal(actualSpanChunk.getTraceRoot().getTransactionId(), trace.spanBuilder.getTraceRoot().getTransactionId(), 'transactionIdObject is equal') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.asyncId.asyncId, 'localAsyncId is equal') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId.sequence is equal') - t.equal(actualSpanChunk.spanEventList[1].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'apiId is equal') - t.equal(actualSpanChunk.spanEventList[1].depth, 1, 'depth is equal') - t.equal(actualSpanChunk.spanEventList[1].sequence, 0, 'sequence is equal') - t.equal(actualSpanChunk.spanEventList[1].serviceType, ServiceType.async.getCode(), 'serviceType is mysql') + t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'apiId is equal') + t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'depth is equal') + t.equal(actualSpanChunk.spanEventList[0].sequence, 0, 'sequence is equal') + t.equal(actualSpanChunk.spanEventList[0].serviceType, ServiceType.async.getCode(), 'serviceType is mysql') actualBuilder = new MethodDescriptorBuilder('query') .setClassName('Connection') .setLineNumber(234) .setFileName('nested-async-trace.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = actualSpanChunk.spanEventList[0] + actualSpanEvent = actualSpanChunk.spanEventList[1] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId is equal') t.equal(actualSpanEvent.depth, 2, 'depth is 3') t.equal(actualSpanEvent.sequence, 1, 'sequence is 2') t.equal(actualSpanEvent.serviceType, mysqlExecuteQueryServiceType.getCode(), 'serviceType is mysql') - actualNextAsyncId = actualSpanEvent.nextAsyncId + actualNextAsyncId = actualSpanEvent.asyncId - actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualNextAsyncId) + actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualNextAsyncId) t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanId is equal') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionIdObject is equal') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId, 'localAsyncId is equal') + t.equal(actualSpanChunk.getTraceRoot().getTransactionId(), trace.spanBuilder.getTraceRoot().getTransactionId(), 'transactionIdObject is equal') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId.asyncId, 'localAsyncId is equal') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId.sequence is equal') t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'apiId is equal') t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'depth is equal') @@ -321,17 +321,17 @@ test(`nested mysql2 async query with express`, async (t) => { .setLineNumber(103) .setFileName('promise.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence === 3) + actualSpanEvent = trace.spanBuilder.spanEventList.find( spanEvent => spanEvent.sequence === 3) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId is equal') t.equal(actualSpanEvent.sequence, 3, 'sequence is 3') t.equal(actualSpanEvent.depth, 2, 'depth is 2') t.equal(actualSpanEvent.serviceType, mysqlExecuteQueryServiceType.getCode(), 'serviceType is mysql') - actualNextAsyncId = actualSpanEvent.nextAsyncId + actualNextAsyncId = actualSpanEvent.asyncId - actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualNextAsyncId) + actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualNextAsyncId) t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanId is equal') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionIdObject is equal') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId, 'localAsyncId is equal') + t.equal(actualSpanChunk.getTraceRoot().getTransactionId(), trace.spanBuilder.getTraceRoot().getTransactionId(), 'transactionIdObject is equal') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId.asyncId, 'localAsyncId is equal') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId.sequence is equal') t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'apiId is equal') t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'depth is equal') diff --git a/test/instrumentation/fix-async-call-stack.test.js b/test/instrumentation/fix-async-call-stack.test.js index e28312bb..c176c222 100644 --- a/test/instrumentation/fix-async-call-stack.test.js +++ b/test/instrumentation/fix-async-call-stack.test.js @@ -15,27 +15,26 @@ test(`fix redis call stack depth`, async (t) => { .withWaitStrategy(Wait.forAll([ Wait.forListeningPorts(), Wait.forLogMessage("Ready to accept connections") - ])) + ])) .start() agent.bindHttp() - - t.plan(2) - const trace = agent.createTraceObject() localStorage.run(trace, () => { const redis = require('redis') const client = redis.createClient({ url: container.getConnectionUrl() }) - + + const traceContext = agent.getTraceContext() client.set('key', 'value', async function (error) { t.true(error == null, 'error is null') - - const trace = agent.traceContext.currentTraceObject() - t.equal(trace.callStack.length, 1, 'callStack is 1') - + + const trace = traceContext.currentTraceObject() + t.equal(trace.callStack.stack.length, 1, 'callStack is 1') + client.quit() agent.completeTraceObject(trace) await container.stop() + t.end() }) }) }) \ No newline at end of file diff --git a/test/instrumentation/module/complex.test.js b/test/instrumentation/module/complex.test.js index f2f4b1ac..411ac97a 100644 --- a/test/instrumentation/module/complex.test.js +++ b/test/instrumentation/module/complex.test.js @@ -54,10 +54,10 @@ test.skip(`${testName1} should Record the connections between koa and mongodb an const key = ctx.params.author await mongoose.prepareStorage().then(async () => { - const Book = mongoose.model('book', bookSchema) + const Book = mongoose.model('book', bookSchema) await mongoose.connect('mongodb://127.0.0.1/mongodb_pinpoint', async function(err) { await Book.findOne({author: key}).exec() - await redis.get(key) + await redis.get(key) console.log('Test!?') }) }) @@ -93,12 +93,12 @@ test.skip(`${testName2} should Record the connections between express and redis. var key = req.params.name await mongoose.prepareStorage().then(async () => { - const Book = mongoose.model('book', bookSchema) + const Book = mongoose.model('book', bookSchema) await mongoose.connect('mongodb://127.0.0.1/mongodb_pinpoint', function(err) { Book.findOne({ author: key }, function(err, book) { if (err) return res.status(500).json({ error: err }) if (!book) return res.status(404).json({ error: 'book not found' }) - + console.log('test2?') res.send(book) }) @@ -142,7 +142,7 @@ test.skip(`${testName2} should Record the connections between express and redis. // const rstInsert = await axios.post(getServerUrl(PATH), mongoData) // t.ok(rstInsert.status, 200) - const traceMap = agent.traceContext.getAllTraceObject() + const traceMap = agent.getTraceContext().getAllTraceObject() server.close() t.end() @@ -153,5 +153,5 @@ test.onFinish(() => { // mongoose.helper.reset().then(function() { // mongoose.killMongo().then(function () { // }) - // }) + // }) }) diff --git a/test/instrumentation/module/express.test.js b/test/instrumentation/module/express.test.js index 26f2a608..f83006bd 100644 --- a/test/instrumentation/module/express.test.js +++ b/test/instrumentation/module/express.test.js @@ -15,13 +15,13 @@ const apiMetaService = require('../../../lib/context/api-meta-service') const semver = require('semver') const MethodDescriptorBuilder = require('../../../lib/context/method-descriptor-builder') const DisableTrace = require('../../../lib/context/disable-trace') -const transactionIdGenerator = require('../../../lib/context/sequence-generators').transactionIdGenerator const http = require('http') const https = require('https') +const { getTransactionId, getDisabledId } = require('../../../lib/context/trace/id-generator') + const TEST_ENV = { - host: 'localhost', - port: 5006, + host: 'localhost', port: 5006 } const getServerUrl = (path) => `http://${TEST_ENV.host}:${TEST_ENV.port}${path}` @@ -38,17 +38,17 @@ test(`${testName1} Should record request in basic route`, function (t) { res.send('ok get') agent.callbackTraceClose((trace) => { - t.equal(trace.span.annotations[0].key, annotationKey.HTTP_PARAM.code, 'HTTP param key match') - t.equal(trace.span.annotations[0].value, 'api=test&test1=test', 'HTTP param value match') - t.equal(trace.span.annotations[1].key, annotationKey.HTTP_STATUS_CODE.code, 'HTTP status code') - t.equal(trace.span.annotations[1].value, 200, 'response status is 200') + t.equal(trace.spanBuilder.annotations[0].key, annotationKey.HTTP_PARAM.code, 'HTTP param key match') + t.equal(trace.spanBuilder.annotations[0].value, 'api=test&test1=test', 'HTTP param value match') + t.equal(trace.spanBuilder.annotations[1].key, annotationKey.HTTP_STATUS_CODE.code, 'HTTP status code') + t.equal(trace.spanBuilder.annotations[1].value, 200, 'response status is 200') let actualBuilder = new MethodDescriptorBuilder(expected('get', 'app.get')) .setClassName(expected('app', 'Function')) .setLineNumber(37) .setFileName('express.test.js') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[0] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.true(actualMethodDescriptor.apiDescriptor.startsWith(expected('app.get', 'Function.app.get')), 'apiDescriptor') t.equal(actualMethodDescriptor.className, expected('app', 'Function'), 'className') @@ -63,15 +63,15 @@ test(`${testName1} Should record request in basic route`, function (t) { res.send('ok post') agent.callbackTraceClose((trace) => { - t.equal(trace.span.annotations[0].key, annotationKey.HTTP_STATUS_CODE.code, '/express1 HTTP STATUS CODE in annotation zero') - t.equal(trace.span.annotations[0].value, 200, '/express1 HTTP STATUS CODE value in annotation zero') + t.equal(trace.spanBuilder.annotations[0].key, annotationKey.HTTP_STATUS_CODE.code, '/express1 HTTP STATUS CODE in annotation zero') + t.equal(trace.spanBuilder.annotations[0].value, 200, '/express1 HTTP STATUS CODE value in annotation zero') let actualBuilder = new MethodDescriptorBuilder(expected('post', 'app.post')) .setClassName(expected('app', 'Function')) .setLineNumber(62) .setFileName('express.test.js') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[0] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.true(actualMethodDescriptor.apiDescriptor.startsWith(expected('app.post', 'Function.app.post')), 'apiDescriptor') t.equal(actualMethodDescriptor.className, expected('app', 'Function'), 'className') @@ -90,7 +90,7 @@ test(`${testName1} Should record request in basic route`, function (t) { .setLineNumber(84) .setFileName('express.test.js') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[0] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.true(actualMethodDescriptor.apiDescriptor.startsWith(expected('app.get', 'Function.app.get')), 'apiDescriptor') t.equal(actualMethodDescriptor.className, expected('app', 'Function'), 'className') @@ -164,15 +164,15 @@ test(`${testName1} Should record request in basic route`, function (t) { }) function throwHandleTest(trace, t) { - t.equal(trace.span.annotations[0].key, annotationKey.HTTP_STATUS_CODE.getCode(), '/express3 HTTP_STATUS_CODE annotationKey matching') - t.equal(trace.span.annotations[0].value, 500, '/express3 HTTP_STATUS_CODE value matching') + t.equal(trace.spanBuilder.annotations[0].key, annotationKey.HTTP_STATUS_CODE.getCode(), '/express3 HTTP_STATUS_CODE annotationKey matching') + t.equal(trace.spanBuilder.annotations[0].value, 500, '/express3 HTTP_STATUS_CODE value matching') let actualBuilder = new MethodDescriptorBuilder(expected('get', 'app.get')) .setClassName(expected('app', 'Function')) .setLineNumber(107) .setFileName('express.test.js') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[1] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.true(actualMethodDescriptor.apiDescriptor.startsWith(expected('app.get', 'Function.app.get')), 'apiDescriptor') t.equal(actualMethodDescriptor.className, expected('app', 'Function'), 'className') @@ -187,7 +187,7 @@ function throwHandleTest(trace, t) { .setLineNumber(120) .setFileName('express.test.js') const actualErrorMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - spanEvent = trace.span.spanEventList[0] + spanEvent = trace.spanBuilder.spanEventList[1] t.equal(actualErrorMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.true(actualErrorMethodDescriptor.apiDescriptor.startsWith('Router.use'), 'apiDescriptor') t.equal(actualErrorMethodDescriptor.className, 'Router', 'className') @@ -206,7 +206,7 @@ function nextErrorHandleTest(trace, t) { .setLineNumber(114) .setFileName('express.test.js') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[1] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.true(actualMethodDescriptor.apiDescriptor.startsWith(expected('app.get', 'Function.app.get')), 'apiDescriptor') t.equal(actualMethodDescriptor.className, expected('app', 'Function'), 'className') @@ -221,7 +221,7 @@ function nextErrorHandleTest(trace, t) { .setLineNumber(120) .setFileName('express.test.js') const actualErrorMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - spanEvent = trace.span.spanEventList[0] + spanEvent = trace.spanBuilder.spanEventList[1] t.equal(actualErrorMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.true(actualErrorMethodDescriptor.apiDescriptor.startsWith('Router.use'), 'apiDescriptor') t.equal(actualErrorMethodDescriptor.className, 'Router', 'className') @@ -370,7 +370,7 @@ test(`${testName5} Should record middleware`, function (t) { .setLineNumber(366) .setFileName('express.test.js') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[2] + let spanEvent = trace.spanBuilder.spanEventList[2] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.true(actualMethodDescriptor.apiDescriptor.startsWith(expected('app.get', 'Function.app.get')), 'apiDescriptor') t.equal(actualMethodDescriptor.className, expected('app', 'Function'), 'className') @@ -385,7 +385,7 @@ test(`${testName5} Should record middleware`, function (t) { .setLineNumber(356) .setFileName('express.test.js') const actualMiddleware1MethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - spanEvent = trace.span.spanEventList[1] + spanEvent = trace.spanBuilder.spanEventList[1] t.equal(actualMiddleware1MethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.true(actualMiddleware1MethodDescriptor.apiDescriptor.startsWith('Router.use'), 'apiDescriptor') t.equal(actualMiddleware1MethodDescriptor.className, 'Router', 'className') @@ -400,7 +400,7 @@ test(`${testName5} Should record middleware`, function (t) { .setLineNumber(351) .setFileName('express.test.js') const actualMiddleware2MethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - spanEvent = trace.span.spanEventList[0] + spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMiddleware2MethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.true(actualMiddleware2MethodDescriptor.apiDescriptor.startsWith('Router.use'), 'apiDescriptor') t.equal(actualMiddleware2MethodDescriptor.className, 'Router', 'className') @@ -500,15 +500,15 @@ test('express without callSite', (t) => { res.send('ok get') agent.callbackTraceClose((trace) => { - t.equal(trace.span.annotations[0].key, annotationKey.HTTP_PARAM.code, 'HTTP param key match') - t.equal(trace.span.annotations[0].value, 'api=test&test1=test', 'HTTP param value match') - t.equal(trace.span.annotations[1].key, annotationKey.HTTP_STATUS_CODE.code, 'HTTP status code') - t.equal(trace.span.annotations[1].value, 200, 'response status is 200') + t.equal(trace.spanBuilder.annotations[0].key, annotationKey.HTTP_PARAM.code, 'HTTP param key match') + t.equal(trace.spanBuilder.annotations[0].value, 'api=test&test1=test', 'HTTP param value match') + t.equal(trace.spanBuilder.annotations[1].key, annotationKey.HTTP_STATUS_CODE.code, 'HTTP status code') + t.equal(trace.spanBuilder.annotations[1].value, 200, 'response status is 200') let actualBuilder = new MethodDescriptorBuilder('get') .setClassName('Router') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[0] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.get', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'Router', 'className') @@ -521,13 +521,13 @@ test('express without callSite', (t) => { res.send('ok post') agent.callbackTraceClose((trace) => { - t.equal(trace.span.annotations[0].key, annotationKey.HTTP_STATUS_CODE.code, '/express1 HTTP STATUS CODE in annotation zero') - t.equal(trace.span.annotations[0].value, 200, '/express1 HTTP STATUS CODE value in annotation zero') + t.equal(trace.spanBuilder.annotations[0].key, annotationKey.HTTP_STATUS_CODE.code, '/express1 HTTP STATUS CODE in annotation zero') + t.equal(trace.spanBuilder.annotations[0].value, 200, '/express1 HTTP STATUS CODE value in annotation zero') let actualBuilder = new MethodDescriptorBuilder('post') .setClassName('Router') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[0] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.post', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'Router', 'className') @@ -542,7 +542,7 @@ test('express without callSite', (t) => { let actualBuilder = new MethodDescriptorBuilder('get') .setClassName('Router') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[0] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.get', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'Router', 'className') @@ -614,13 +614,13 @@ test('express without callSite', (t) => { }) function throwHandleTestWithoutCallSite(trace, t) { - t.equal(trace.span.annotations[0].key, annotationKey.HTTP_STATUS_CODE.getCode(), '/express3 HTTP_STATUS_CODE annotationKey matching') - t.equal(trace.span.annotations[0].value, 500, '/express3 HTTP_STATUS_CODE value matching') + t.equal(trace.spanBuilder.annotations[0].key, annotationKey.HTTP_STATUS_CODE.getCode(), '/express3 HTTP_STATUS_CODE annotationKey matching') + t.equal(trace.spanBuilder.annotations[0].value, 500, '/express3 HTTP_STATUS_CODE value matching') let actualBuilder = new MethodDescriptorBuilder('get') .setClassName('Router') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[1] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.get', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'Router', 'className') @@ -631,7 +631,7 @@ function throwHandleTestWithoutCallSite(trace, t) { actualBuilder = new MethodDescriptorBuilder('use') .setClassName('Router') const actualErrorMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - spanEvent = trace.span.spanEventList[0] + spanEvent = trace.spanBuilder.spanEventList[1] t.equal(actualErrorMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.equal(actualErrorMethodDescriptor.apiDescriptor, 'Router.use', 'apiDescriptor') t.equal(actualErrorMethodDescriptor.className, 'Router', 'className') @@ -646,7 +646,7 @@ function nextErrorHandleTestWithoutCallSite(trace, t) { let actualBuilder = new MethodDescriptorBuilder('get') .setClassName('Router') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[1] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.get', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'Router', 'className') @@ -657,7 +657,7 @@ function nextErrorHandleTestWithoutCallSite(trace, t) { actualBuilder = new MethodDescriptorBuilder('use') .setClassName('Router') const actualErrorMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - spanEvent = trace.span.spanEventList[0] + spanEvent = trace.spanBuilder.spanEventList[1] t.equal(actualErrorMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.equal(actualErrorMethodDescriptor.apiDescriptor, 'Router.use', 'apiDescriptor') t.equal(actualErrorMethodDescriptor.className, 'Router', 'className') @@ -670,16 +670,23 @@ function nextErrorHandleTestWithoutCallSite(trace, t) { test('incoming request by Disable Trace requests', (t) => { agent.bindHttp({ 'sampling': { 'rate': 3 } }) - let actualTraceIdSequence = 0 + let actualTraceIdTransactionId = 0 let actualRequestCount = 0 const app = new express() const rootPathTraces = [] app.get('/', async (req, res) => { actualRequestCount++ + const trace = agent.currentTraceObject() + const traceRoot = trace.getTraceRoot() + actualTraceIdTransactionId = traceRoot.transactionId + + if (actualRequestCount == 1 || actualRequestCount == 4) { + t.equal('' + (getTransactionId().sequence - 1), actualTraceIdTransactionId, `traceRoot.transactionId equals transactionIdGenerator.sequence ${traceRoot.transactionId}`) + } const result = await axios.get(getServerUrl('/api'), { - timeout: 3000, + timeout: 10000, httpAgent: new http.Agent({ keepAlive: false }), httpsAgent: new https.Agent({ keepAlive: false }), }) @@ -689,16 +696,13 @@ test('incoming request by Disable Trace requests', (t) => { agent.callbackTraceClose((trace) => { if (actualRequestCount == 1) { - t.equal(actualTraceIdSequence, parseInt(trace.traceId.transactionId.sequence), 'transaction id sequence equals transactionIdGenerator.sequence') - t.equal(actualTraceIdSequence, 0, 'first request transactionIdGenerator.sequence is 0') + t.equal(actualTraceIdTransactionId, trace.getTraceRoot().transactionId, 'transaction id sequence equals transactionIdGenerator.sequence') } else if (actualRequestCount == 4) { - t.equal(actualTraceIdSequence, parseInt(trace.traceId.transactionId.sequence), 'transaction id sequence equals transactionIdGenerator.sequence') - t.equal(actualTraceIdSequence, 1, 'fourth request transactionIdGenerator.sequence is 1') + t.equal(actualTraceIdTransactionId, trace.getTraceRoot().transactionId, 'transaction id sequence equals transactionIdGenerator.sequence') } else { t.true(trace instanceof DisableTrace, `trace is DisableTrace actualRequestCount=${actualRequestCount}`) - t.equal(actualTraceIdSequence, transactionIdGenerator.sequence, 'DisableTrace transaction no updated transactionIdGenerator.sequence') + t.equal(actualTraceIdTransactionId, '' + (getDisabledId().sequence + 5), 'DisableTrace transaction no updated transactionIdGenerator.sequence') } - actualTraceIdSequence = transactionIdGenerator.sequence rootPathTraces.push(trace) }) }) @@ -709,7 +713,7 @@ test('incoming request by Disable Trace requests', (t) => { apiRequests.push(req) const result = await axios.get(getServerUrl('/api2'), { - timeout: 3000, + timeout: 10000, httpAgent: new http.Agent({ keepAlive: false }), httpsAgent: new https.Agent({ keepAlive: false }), }) @@ -719,10 +723,10 @@ test('incoming request by Disable Trace requests', (t) => { agent.callbackTraceClose((trace) => { if (actualRequestCount == 1 || actualRequestCount == 4) { - t.equal(actualTraceIdSequence, parseInt(trace.traceId.transactionId.sequence), 'API transaction id sequence equals transactionIdGenerator.sequence') + t.equal(actualTraceIdTransactionId, trace.getTraceId().transactionId, 'API transaction id sequence equals transactionIdGenerator.sequence') } else { t.true(trace instanceof DisableTrace, `trace is DisableTrace actualRequestCount=${actualRequestCount}`) - t.equal(actualTraceIdSequence, transactionIdGenerator.sequence, 'API DisableTrace transaction no updated transactionIdGenerator.sequence') + t.equal(actualTraceIdTransactionId, '' + (getDisabledId().sequence + 5), 'API DisableTrace transaction no updated transactionIdGenerator.sequence') } apiPathTraces.push(trace) }) @@ -736,10 +740,10 @@ test('incoming request by Disable Trace requests', (t) => { agent.callbackTraceClose((trace) => { if (actualRequestCount == 1 || actualRequestCount == 4) { - t.equal(actualTraceIdSequence, parseInt(trace.traceId.transactionId.sequence), 'API transaction id sequence equals transactionIdGenerator.sequence') + t.equal(actualTraceIdTransactionId, trace.getTraceId().transactionId, 'API transaction id sequence equals transactionIdGenerator.sequence') } else { t.true(trace instanceof DisableTrace, `trace is DisableTrace actualRequestCount=${actualRequestCount}`) - t.equal(actualTraceIdSequence, transactionIdGenerator.sequence, 'API DisableTrace transaction no updated transactionIdGenerator.sequence') + t.equal(actualTraceIdTransactionId, '' + (getDisabledId().sequence + 5), 'API DisableTrace transaction no updated transactionIdGenerator.sequence') } apiPathTraces2.push(trace) }) @@ -747,37 +751,39 @@ test('incoming request by Disable Trace requests', (t) => { const server = app.listen(TEST_ENV.port, async function () { const result1 = await axios.get(getServerUrl('/'), { - timeout: 3000, + timeout: 20000, httpAgent: new http.Agent({ keepAlive: false }), httpsAgent: new https.Agent({ keepAlive: false }), }) t.equal(result1.status, 200, 'first / request status code is 200') let actualTrace = rootPathTraces[0] - t.equal(actualTrace.span.rpc, '/', 'HTTP Request URI') - t.equal(actualTrace.span.annotations[0].key, annotationKey.HTTP_STATUS_CODE.code, 'HTTP status code') - t.equal(actualTrace.span.annotations[0].value, 200, 'response status is 200') + t.equal(actualTrace.spanBuilder.rpc, '/', 'HTTP Request URI') + t.equal(actualTrace.spanBuilder.annotations[0].key, annotationKey.HTTP_STATUS_CODE.code, 'HTTP status code') + t.equal(actualTrace.spanBuilder.annotations[0].value, 200, 'response status is 200') let actualApiTrace = apiPathTraces[0] - t.equal(actualTrace.span.spanId, actualApiTrace.span.parentSpanId, 'parent span id equals to root span id') - t.equal(actualApiTrace.span.rpc, '/api', 'HTTP Request URI') - t.equal(actualApiTrace.span.annotations[0].key, annotationKey.HTTP_STATUS_CODE.code, 'HTTP status code') - t.equal(actualApiTrace.span.annotations[0].value, 200, 'response status is 200') + t.equal(actualTrace.spanBuilder.spanId, actualApiTrace.spanBuilder.parentSpanId, 'parent span id equals to root span id') + t.equal(actualApiTrace.spanBuilder.rpc, '/api', 'HTTP Request URI') + t.equal(actualApiTrace.spanBuilder.annotations[0].key, annotationKey.HTTP_STATUS_CODE.code, 'HTTP status code') + t.equal(actualApiTrace.spanBuilder.annotations[0].value, 200, 'response status is 200') let actualApiRequest = apiRequests[0] t.equal(actualApiRequest.url, '/api', 'api request url is /api') - t.equal(actualApiRequest.headers['pinpoint-host'], actualApiTrace.span.endPoint, 'api request pinpoint-host header is localhost:5006') - t.equal(actualApiRequest.headers['pinpoint-flags'], undefined, 'api request pinpoint-flags header is 0') + t.equal(actualApiRequest.headers['pinpoint-host'], actualApiTrace.spanBuilder.endPoint, 'api request pinpoint-host header is localhost:5006') + t.equal(actualApiRequest.headers['pinpoint-flags'], '0', 'api request pinpoint-flags header is 0') t.equal(actualApiRequest.headers['pinpoint-sampled'], undefined, 'api request pinpoint-sampled header is s0') t.equal(actualApiRequest.headers['pinpoint-pappname'], agent.config.applicationName, 'pinpoint-pappname header is config.applicationName') t.equal(actualApiRequest.headers['pinpoint-papptype'], String(agent.config.serviceType), 'pinpoint-papptype header is config.serviceType') - t.equal(actualApiRequest.headers['pinpoint-pspanid'], actualTrace.span.spanId, 'pinpoint-pspanid header is root span id') - t.equal(actualApiRequest.headers['pinpoint-spanid'], actualApiTrace.span.spanId, 'pinpoint-spanid header is api span id') - t.equal(actualApiRequest.headers['pinpoint-traceid'], actualTrace.traceId.transactionId.toString(), 'pinpoint-traceid header is root transaction id') - t.equal(actualTrace.traceId.transactionId.toString(), actualApiTrace.traceId.transactionId.toString(), 'transaction id equals to root transaction id') + t.equal(actualApiRequest.headers['pinpoint-pspanid'], actualTrace.getTraceId().getSpanId(), 'pinpoint-pspanid header is root span id') + t.equal(actualApiRequest.headers['pinpoint-spanid'], actualApiTrace.getTraceId().getSpanId(), 'pinpoint-spanid header is api span id') + t.equal(actualApiRequest.headers['pinpoint-traceid'], actualTrace.getTraceId().toStringDelimiterFormatted(), 'pinpoint-traceid header is root transaction id') + t.equal(actualTrace.getTraceId().getAgentId(), actualApiTrace.getTraceId().getAgentId(), '1st TraceId.agentId equals 2nd TraceId.agentId') + t.equal(actualTrace.getTraceId().getAgentStartTime(), actualApiTrace.getTraceId().getAgentStartTime(), '1st TraceId.agentStartTime equals 2nd TraceId.agentStartTime') + t.equal(actualTrace.getTraceId().transactionId, actualApiTrace.getTraceId().transactionId, '1st TraceId.transactionSequence equals 2nd TraceId.transactionSequence') const result2 = await axios.get(getServerUrl('/'), { - timeout: 3000, + timeout: 20000, httpAgent: new http.Agent({ keepAlive: false }), httpsAgent: new https.Agent({ keepAlive: false }), }) @@ -791,7 +797,7 @@ test('incoming request by Disable Trace requests', (t) => { t.equal(actualApiRequest.headers['pinpoint-sampled'], 's0', 'DisableTrace api request pinpoint-sampled header is s0') const result3 = await axios.get(getServerUrl('/'), { - timeout: 3000, + timeout: 20000, httpAgent: new http.Agent({ keepAlive: false }), httpsAgent: new https.Agent({ keepAlive: false }), }) diff --git a/test/instrumentation/module/fix-redis.test.js b/test/instrumentation/module/fix-redis.test.js index 32452f72..eab9a0d4 100644 --- a/test/instrumentation/module/fix-redis.test.js +++ b/test/instrumentation/module/fix-redis.test.js @@ -24,34 +24,35 @@ test(`redis destination id`, async (t) => { t.plan(6) const trace = agent.createTraceObject() + const traceContext = agent.getTraceContext() localStorage.run(trace, () => { const redis = require('redis') - + const client = redis.createClient({ url: container.getConnectionUrl() }) - + client.on("error", function (error) { console.error(error) }) - + client.set("key", "value", async function (error) { t.true(error == null, "error is null") - - const trace = agent.traceContext.currentTraceObject() - t.equal(trace.callStack.length, 1, "callStack is 1") + + const trace = traceContext.currentTraceObject() + t.equal(trace.callStack.stack.length, 1, "callStack is 1") }) - t.equal(agent.traceContext.currentTraceObject().callStack.length, 0, "set spanevent callstack") - + t.equal(traceContext.currentTraceObject().callStack.stack.length, 0, "set spanevent callstack") + client.get("key", async function (error, data) { t.equal(data, "value", "redis value validation") - - const trace = agent.traceContext.currentTraceObject() - t.equal(trace.callStack.length, 1, "callStack is 1") - + + const trace = traceContext.currentTraceObject() + t.equal(trace.callStack.stack.length, 1, "callStack is 1") + client.quit() agent.completeTraceObject(trace) await container.stop() }) - t.equal(agent.traceContext.currentTraceObject().callStack.length, 0, "get spanevent callstack") + t.equal(traceContext.currentTraceObject().callStack.stack.length, 0, "get spanevent callstack") }) }) @@ -60,7 +61,7 @@ test("ioredis destination id", async function (t) { .withWaitStrategy(Wait.forAll([ Wait.forListeningPorts(), Wait.forLogMessage("Ready to accept connections") - ])) + ])) .start() agent.bindHttp() @@ -78,20 +79,20 @@ test("ioredis destination id", async function (t) { redis.on("error", function (error) { console.error(error) }) - + const result = await redis.set("key", "value") t.equal(result, "OK", "Success set data") - + redis.get("key", async function (error, data) { t.equal(data, "value", "redis value validation") setImmediate(async () => { t.true(agent.dataSender.mockSpanChunks[0].spanEventList.length > 0, "a spanEventList should has one chunk") - - const spanevent = trace.storage.storage[0] + + const spanevent = trace.repository.buffer[0] t.equal(spanevent.destinationId, "Redis", "Redis destionation ID check") t.true(spanevent.endPoint.endsWith(`:${port}`), `localhost:${port}`) - + redis.quit() agent.completeTraceObject(trace) await container.stop() @@ -132,33 +133,34 @@ test(`Fix app crash without callback function https://github.com/pinpoint-apm/pi const trace = agent.createTraceObject() localStorage.run(trace, () => { const redis = require('redis') - + const client = redis.createClient({ url: container.getConnectionUrl(), db: 3 }) - + const traceContext = agent.getTraceContext() + client.select(2) - + client.on("error", function (error) { console.error(error) }) - + client.set("key", "value", async function (error) { t.true(error == null, "error is null") - - const trace = agent.traceContext.currentTraceObject() - t.equal(trace.callStack.length, 1, "callStack is 1") + + const trace = traceContext.currentTraceObject() + t.equal(trace.callStack.stack.length, 1, "callStack is 1") }) - t.equal(agent.traceContext.currentTraceObject().callStack.length, 0, "set spanevent callstack") - + t.equal(traceContext.currentTraceObject().callStack.stack.length, 0, "set spanevent callstack") + client.get("key", async function (error, data) { t.equal(data, "value", "redis value validation") - - const trace = agent.traceContext.currentTraceObject() - t.equal(trace.callStack.length, 1, "callStack is 1") - + + const trace = traceContext.currentTraceObject() + t.equal(trace.callStack.stack.length, 1, "callStack is 1") + client.quit() agent.completeTraceObject(trace) await container.stop() }) - t.equal(agent.traceContext.currentTraceObject().callStack.length, 0, "get spanevent callstack") + t.equal(traceContext.currentTraceObject().callStack.stack.length, 0, "get spanevent callstack") }) }) diff --git a/test/instrumentation/module/http.test.js b/test/instrumentation/module/http.test.js index d37a9773..38eaf477 100644 --- a/test/instrumentation/module/http.test.js +++ b/test/instrumentation/module/http.test.js @@ -18,14 +18,13 @@ test(`outgoing request URL escape a bug`, async (t) => { const trace = agent.createTraceObject() localStorage.run(trace, () => { t.true(trace) - + axios.get(`https://www.naver.com`, { httpsAgent: new https.Agent({ keepAlive: false }) }) .then(function (response) { t.true(response.status == 200) - - t.true(agent.dataSender.mockSpanChunks[0].spanEventList.length == 2, `spanEventList`) - - const spanEvent = agent.dataSender.mockSpanChunks[0].spanEventList[0] + const spanChunk = trace.repository.dataSender.findSpanChunk(trace.repository.buffer[0].asyncId) + t.true(spanChunk.spanEventList.length == 2, `spanEventList`) + const spanEvent = spanChunk.spanEventList[1] t.equal(spanEvent.annotations[0].value, "GET", "URL") t.equal(spanEvent.annotations[1].value, "www.naver.com/", "URL") agent.completeTraceObject(trace) diff --git a/test/instrumentation/module/koa.test.js b/test/instrumentation/module/koa.test.js index e38c2764..75a81436 100644 --- a/test/instrumentation/module/koa.test.js +++ b/test/instrumentation/module/koa.test.js @@ -35,15 +35,15 @@ test(`${testName1} Should record request in basic route koa.test.js`, function ( ctx.body = 'ok. get' agent.callbackTraceClose((trace) => { - t.equal(trace.span.annotations[0].key, annotationKey.HTTP_STATUS_CODE.getCode(), 'HTTP status code') - t.equal(trace.span.annotations[0].value, 200, 'response status is 200') + t.equal(trace.spanBuilder.annotations[0].key, annotationKey.HTTP_STATUS_CODE.getCode(), 'HTTP status code') + t.equal(trace.spanBuilder.annotations[0].value, 200, 'response status is 200') let actualBuilder = new MethodDescriptorBuilder('get') .setClassName('Router') .setLineNumber(34) .setFileName('koa.test.js') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[0] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.equal(spanEvent.annotations[0].key, -1, 'parameter') t.equal(spanEvent.annotations[0].value, '/koa-router1', 'parameter value matching') @@ -83,13 +83,13 @@ test(`${testName1} Should record request in basic route koa.test.js`, function ( ctx.body = 'ok. get' agent.callbackTraceClose((trace) => { - t.equal(trace.span.annotations[0].key, annotationKey.HTTP_STATUS_CODE.getCode(), 'HTTP status code') - t.equal(trace.span.annotations[0].value, 200, 'response status is 200') + t.equal(trace.spanBuilder.annotations[0].key, annotationKey.HTTP_STATUS_CODE.getCode(), 'HTTP status code') + t.equal(trace.spanBuilder.annotations[0].value, 200, 'response status is 200') let actualBuilder = new MethodDescriptorBuilder('get') .setClassName('Router') const actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let spanEvent = trace.span.spanEventList[0] + let spanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, spanEvent.apiId, 'apiId') t.equal(spanEvent.annotations[0].key, -1, 'parameter') t.equal(spanEvent.annotations[0].value, '/koa-router1', 'parameter value matching') diff --git a/test/instrumentation/module/mysql-uid.test.js b/test/instrumentation/module/mysql-uid.test.js index 925b5771..1c49983f 100644 --- a/test/instrumentation/module/mysql-uid.test.js +++ b/test/instrumentation/module/mysql-uid.test.js @@ -62,7 +62,7 @@ test('mysql uid query', async (t) => { let actualBuilder = new MethodDescriptorBuilder('createConnection') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - const createConnectionSpanEvent = trace.span.spanEventList[0] + const createConnectionSpanEvent = trace.spanBuilder.spanEventList[0] t.equal(createConnectionSpanEvent.endPoint, 'localhost', 'createConnection endPoint is localhost in mysql uid functional test') t.equal(createConnectionSpanEvent.destinationId, 'test', 'createConnection destinationId is test in mysql uid functional test') t.equal(createConnectionSpanEvent.apiId, actualMethodDescriptor.apiId, 'createConnection apiId is same in mysql uid functional test') @@ -70,14 +70,14 @@ test('mysql uid query', async (t) => { actualBuilder = new MethodDescriptorBuilder('connect') .setClassName('Connection') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - const connectionSpanEvent = trace.span.spanEventList[1] + const connectionSpanEvent = trace.spanBuilder.spanEventList[1] t.equal(connectionSpanEvent.depth, 1, 'connection depth is 1 in mysql uid functional test') t.equal(connectionSpanEvent.sequence, 1, 'connection sequence is 1 in mysql uid functional test') actualBuilder = new MethodDescriptorBuilder('query') .setClassName('Connection') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - const querySpanEvent = trace.span.spanEventList[2] + const querySpanEvent = trace.spanBuilder.spanEventList[2] t.equal(querySpanEvent.depth, 1, 'query depth is 1 in mysql uid functional test') t.equal(querySpanEvent.sequence, 2, 'query sequence is 2 in mysql uid functional test') t.equal(querySpanEvent.apiId, actualMethodDescriptor.apiId, 'query apiId is same in mysql uid functional test') @@ -87,7 +87,7 @@ test('mysql uid query', async (t) => { t.equal(actualQueryAnnotation.key, annotationKey.SQL_UID.getCode(), 'query annotation key is sql in mysql uid functional test') t.equal(actualParsingResult.result.sql.normalizedSql, 'SELECT * FROM member', 'query normalizedSql is SELECT * FROM member in mysql uid functional test') - let actualGrpcSpanEvent = trace.storage.dataSender.mockSpan.spanEventList[2] + let actualGrpcSpanEvent = trace.repository.dataSender.mockSpan.spanEventList[2] t.equal(actualQueryAnnotation.key, actualGrpcSpanEvent.annotations[0].key, 'query annotation key is same that grpc in mysql uid functional test') t.equal(actualQueryAnnotation.value, actualGrpcSpanEvent.annotations[0].value, 'query annotation value is same that grpc in mysql uid functional test') diff --git a/test/instrumentation/module/mysql.test.js b/test/instrumentation/module/mysql.test.js index 58de731b..ba31a63e 100644 --- a/test/instrumentation/module/mysql.test.js +++ b/test/instrumentation/module/mysql.test.js @@ -69,7 +69,7 @@ test(`getConnection query hooking`, async (t) => { .setLineNumber(43) .setFileName('mysql.test.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - const createConnectionSpanEvent = trace.span.spanEventList[0] + const createConnectionSpanEvent = trace.spanBuilder.spanEventList[0] t.equal(createConnectionSpanEvent.endPoint, 'localhost', 'the createConnection SpanEvent endPoint') t.equal(createConnectionSpanEvent.destinationId, 'test', 'the createConnection SpanEvent destinationId') t.equal(actualMethodDescriptor.apiId, createConnectionSpanEvent.apiId, 'apiId') @@ -79,7 +79,7 @@ test(`getConnection query hooking`, async (t) => { .setLineNumber(52) .setFileName('mysql.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - const connectionSpanEvent = trace.span.spanEventList[1] + const connectionSpanEvent = trace.spanBuilder.spanEventList[1] t.equal(connectionSpanEvent.depth, 1, 'connection spanEvent depth') t.equal(connectionSpanEvent.sequence, 1, 'connection spanEvent sequence') t.equal(actualMethodDescriptor.apiId, connectionSpanEvent.apiId, 'apiId') @@ -89,7 +89,7 @@ test(`getConnection query hooking`, async (t) => { .setLineNumber(58) .setFileName('mysql.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - const querySpanEvent = trace.span.spanEventList[2] + const querySpanEvent = trace.spanBuilder.spanEventList[2] t.equal(querySpanEvent.depth, 1, 'query spanEvent depth') t.equal(querySpanEvent.sequence, 2, 'query spanEvent sequence') t.equal(actualMethodDescriptor.apiId, querySpanEvent.apiId, 'apiId') @@ -166,7 +166,7 @@ test(`connection with query`, async (t) => { .setLineNumber(119) .setFileName('mysql.test.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - const createConnectionSpanEvent = trace.span.spanEventList[0] + const createConnectionSpanEvent = trace.spanBuilder.spanEventList[0] t.equal(createConnectionSpanEvent.endPoint, 'localhost', 'the createConnection SpanEvent endPoint') t.equal(createConnectionSpanEvent.destinationId, 'test', 'the createConnection SpanEvent destinationId') t.equal(actualMethodDescriptor.apiId, createConnectionSpanEvent.apiId, 'apiId') @@ -176,7 +176,7 @@ test(`connection with query`, async (t) => { .setLineNumber(128) .setFileName('mysql.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - const connectionSpanEvent = trace.span.spanEventList[1] + const connectionSpanEvent = trace.spanBuilder.spanEventList[1] t.equal(connectionSpanEvent.depth, 1, 'connection spanEvent depth') t.equal(connectionSpanEvent.sequence, 1, 'connection spanEvent sequence') t.equal(actualMethodDescriptor.apiId, connectionSpanEvent.apiId, 'apiId') @@ -186,7 +186,7 @@ test(`connection with query`, async (t) => { .setLineNumber(135) .setFileName('mysql.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let querySpanEvent = trace.span.spanEventList[2] + let querySpanEvent = trace.spanBuilder.spanEventList[2] t.equal(querySpanEvent.endPoint, 'localhost', 'the createConnection SpanEvent endPoint') t.equal(querySpanEvent.destinationId, 'test', 'the createConnection SpanEvent destinationId') t.equal(actualMethodDescriptor.apiId, querySpanEvent.apiId, 'apiId') @@ -202,7 +202,7 @@ test(`connection with query`, async (t) => { .setLineNumber(139) .setFileName('mysql.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - querySpanEvent = trace.span.spanEventList[3] + querySpanEvent = trace.spanBuilder.spanEventList[3] t.equal(querySpanEvent.endPoint, 'localhost', 'the createConnection SpanEvent endPoint') t.equal(querySpanEvent.destinationId, 'test', 'the createConnection SpanEvent destinationId') t.equal(actualMethodDescriptor.apiId, querySpanEvent.apiId, 'apiId') @@ -218,7 +218,7 @@ test(`connection with query`, async (t) => { .setLineNumber(143) .setFileName('mysql.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - querySpanEvent = trace.span.spanEventList[4] + querySpanEvent = trace.spanBuilder.spanEventList[4] t.equal(querySpanEvent.endPoint, 'localhost', 'the createConnection SpanEvent endPoint') t.equal(querySpanEvent.destinationId, 'test', 'the createConnection SpanEvent destinationId') t.equal(actualMethodDescriptor.apiId, querySpanEvent.apiId, 'apiId') @@ -236,7 +236,7 @@ test(`connection with query`, async (t) => { .setLineNumber(146) .setFileName('mysql.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - querySpanEvent = trace.span.spanEventList[5] + querySpanEvent = trace.spanBuilder.spanEventList[5] t.equal(querySpanEvent.endPoint, 'localhost', 'the createConnection SpanEvent endPoint') t.equal(querySpanEvent.destinationId, 'test', 'the createConnection SpanEvent destinationId') t.equal(actualMethodDescriptor.apiId, querySpanEvent.apiId, 'apiId') @@ -318,7 +318,7 @@ test(`Connection Pool with query`, async (t) => { .setLineNumber(274) .setFileName('mysql.test.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = trace.span.spanEventList[0] + let actualSpanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId') t.equal(actualSpanEvent.endPoint, 'localhost', 'createPool SpanEvent endPoint') t.equal(actualSpanEvent.destinationId, 'test', 'createPool SpanEvent destinationId') @@ -331,28 +331,28 @@ test(`Connection Pool with query`, async (t) => { .setLineNumber(285) .setFileName('mysql.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList[1] + actualSpanEvent = trace.spanBuilder.spanEventList[1] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'Pool.getConnection spanEvent apiId') t.equal(actualSpanEvent.depth, 1, 'Pool.getConnection spanEvent depth') t.equal(actualSpanEvent.sequence, 1, 'Pool.getConnection spanEvent sequence') t.equal(actualSpanEvent.serviceType, mysqlServiceType.getCode(), 'Pool.getConnection spanEvent serviceType') - let actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualSpanEvent.nextAsyncId) + let actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualSpanEvent.asyncId) t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanChunk spanId') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'spanChunk transactionIdObject') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'spanChunk localAsyncId.asyncId is spanEvent nextAsyncId') + t.equal(actualSpanChunk.traceRoot, trace.spanBuilder.getTraceRoot(), 'spanChunk traceRoot') + t.equal(actualSpanChunk.localAsyncId.getAsyncId(), actualSpanEvent.asyncId.getAsyncId(), 'spanChunk localAsyncId.asyncId is spanEvent nextAsyncId') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'spanChunk localAsyncId.sequence is spanEvent 0') - t.equal(actualSpanChunk.spanEventList[1].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'spanChunk spanEventList[0].apiId must be asyncInvocationDescriptor.apiId') - t.equal(actualSpanChunk.spanEventList[1].depth, 1, 'spanChunk spanEventList[0].depth is 1') - t.equal(actualSpanChunk.spanEventList[1].sequence, 0, 'spanChunk spanEventList[0].sequence is 0') - t.equal(actualSpanChunk.spanEventList[1].serviceType, ServiceType.async.getCode(), 'spanChunk spanEventList[0].serviceType is ServiceTypeCode.async') + t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'spanChunk spanEventList[0].apiId must be asyncInvocationDescriptor.apiId') + t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'spanChunk spanEventList[0].depth is 1') + t.equal(actualSpanChunk.spanEventList[0].sequence, 0, 'spanChunk spanEventList[0].sequence is 0') + t.equal(actualSpanChunk.spanEventList[0].serviceType, ServiceType.async.getCode(), 'spanChunk spanEventList[0].serviceType is ServiceTypeCode.async') actualBuilder = new MethodDescriptorBuilder('query') .setClassName('PoolConnection') .setLineNumber(287) .setFileName('mysql.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = actualSpanChunk.spanEventList[0] + actualSpanEvent = actualSpanChunk.spanEventList[1] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'PoolConnection.query spanEvent apiId on pool.query') t.equal(actualSpanEvent.depth, 2, 'PoolConnection.query spanEvent depth on pool.query') t.equal(actualSpanEvent.sequence, 1, 'PoolConnection.query spanEvent sequence on pool.query') @@ -365,28 +365,28 @@ test(`Connection Pool with query`, async (t) => { .setLineNumber(202) .setFileName('Pool.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList[2] + actualSpanEvent = trace.spanBuilder.spanEventList[2] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'Pool.getConnection spanEvent apiId on pool.query') t.equal(actualSpanEvent.depth, 1, 'Pool.getConnection spanEvent depth on pool.query') t.equal(actualSpanEvent.sequence, 2, 'Pool.getConnection spanEvent sequence on pool.query') t.equal(actualSpanEvent.serviceType, mysqlServiceType.getCode(), 'Pool.getConnection spanEvent serviceType on pool.query') - actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualSpanEvent.nextAsyncId) + actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualSpanEvent.asyncId) t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanChunk spanId on pool.query') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'spanChunk transactionIdObject on pool.query') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'spanChunk localAsyncId.asyncId is spanEvent nextAsyncId on pool.query') + t.equal(actualSpanChunk.traceRoot, trace.spanBuilder.getTraceRoot(), 'spanChunk transactionIdObject on pool.query') + t.equal(actualSpanChunk.localAsyncId.getAsyncId(), actualSpanEvent.asyncId.getAsyncId(), 'spanChunk localAsyncId.asyncId is spanEvent nextAsyncId on pool.query') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'spanChunk localAsyncId.sequence is spanEvent 0 on pool.query') - t.equal(actualSpanChunk.spanEventList[1].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'spanChunk spanEventList[0].apiId must be asyncInvocationDescriptor.apiId on pool.query') - t.equal(actualSpanChunk.spanEventList[1].depth, 1, 'spanChunk spanEventList[0].depth is 1 on pool.query') - t.equal(actualSpanChunk.spanEventList[1].sequence, 0, 'spanChunk spanEventList[0].sequence is 0 on pool.query') - t.equal(actualSpanChunk.spanEventList[1].serviceType, ServiceType.async.getCode(), 'spanChunk spanEventList[0].serviceType is ServiceTypeCode.async on pool.query') + t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'spanChunk spanEventList[0].apiId must be asyncInvocationDescriptor.apiId on pool.query') + t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'spanChunk spanEventList[0].depth is 1 on pool.query') + t.equal(actualSpanChunk.spanEventList[0].sequence, 0, 'spanChunk spanEventList[0].sequence is 0 on pool.query') + t.equal(actualSpanChunk.spanEventList[0].serviceType, ServiceType.async.getCode(), 'spanChunk spanEventList[0].serviceType is ServiceTypeCode.async on pool.query') actualBuilder = new MethodDescriptorBuilder('query') .setClassName('PoolConnection') .setLineNumber(214) .setFileName('Pool.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = actualSpanChunk.spanEventList[0] + actualSpanEvent = actualSpanChunk.spanEventList[1] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'PoolConnection.query spanEvent apiId on pool.query') t.equal(actualSpanEvent.depth, 2, 'PoolConnection.query spanEvent depth on pool.query') t.equal(actualSpanEvent.sequence, 1, 'PoolConnection.query spanEvent sequence on pool.query') @@ -466,7 +466,7 @@ test(`Cluster with query`, async (t) => { .setLineNumber(417) .setFileName('mysql.test.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = trace.span.spanEventList[0] + let actualSpanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId') t.equal(actualSpanEvent.sequence, 0, 'createPoolCluster spanEvent sequence') t.equal(actualSpanEvent.depth, 1, 'createPoolCluster spanEvent depth') @@ -476,7 +476,7 @@ test(`Cluster with query`, async (t) => { .setLineNumber(142) .setFileName('PoolCluster.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList[1] + actualSpanEvent = trace.spanBuilder.spanEventList[1] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'PoolCluster.of spanEvent apiId in poolCluster.getConnection') t.equal(actualSpanEvent.depth, 1, 'PoolCluster.of spanEvent depth in poolCluster.getConnection') t.equal(actualSpanEvent.sequence, 1, 'PoolCluster.of spanEvent sequence in poolCluster.getConnection') @@ -487,28 +487,28 @@ test(`Cluster with query`, async (t) => { .setLineNumber(145) .setFileName('PoolCluster.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList[2] + actualSpanEvent = trace.spanBuilder.spanEventList[2] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'Pool.getConnection spanEvent apiId in poolCluster.getConnection') t.equal(actualSpanEvent.depth, 1, 'Pool.getConnection spanEvent depth in poolCluster.getConnection') t.equal(actualSpanEvent.sequence, 2, 'Pool.getConnection spanEvent sequence in poolCluster.getConnection') t.equal(actualSpanEvent.serviceType, mysqlServiceType.getCode(), 'Pool.getConnection spanEvent serviceType in poolCluster.getConnection') - let actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualSpanEvent.nextAsyncId) + let actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualSpanEvent.asyncId) t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanChunk spanId in poolCluster.getConnection') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'spanChunk transactionIdObject in poolCluster.getConnection') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'spanChunk localAsyncId.asyncId is spanEvent nextAsyncId in poolCluster.getConnection') + t.equal(actualSpanChunk.traceRoot, trace.spanBuilder.getTraceRoot(), 'spanChunk transactionIdObject in poolCluster.getConnection') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.asyncId.getAsyncId(), 'spanChunk localAsyncId.asyncId is spanEvent nextAsyncId in poolCluster.getConnection') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'spanChunk localAsyncId.sequence is spanEvent 0 in poolCluster.getConnection') - t.equal(actualSpanChunk.spanEventList[1].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'spanChunk spanEventList[0].apiId must be asyncInvocationDescriptor.apiId in poolCluster.getConnection') - t.equal(actualSpanChunk.spanEventList[1].depth, 1, 'spanChunk spanEventList[0].depth is 1 in poolCluster.getConnection') - t.equal(actualSpanChunk.spanEventList[1].sequence, 0, 'spanChunk spanEventList[0].sequence is 0 in poolCluster.getConnection') - t.equal(actualSpanChunk.spanEventList[1].serviceType, ServiceType.async.getCode(), 'spanChunk spanEventList[0].serviceType is ServiceTypeCode.async in poolCluster.getConnection') + t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'spanChunk spanEventList[0].apiId must be asyncInvocationDescriptor.apiId in poolCluster.getConnection') + t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'spanChunk spanEventList[0].depth is 1 in poolCluster.getConnection') + t.equal(actualSpanChunk.spanEventList[0].sequence, 0, 'spanChunk spanEventList[0].sequence is 0 in poolCluster.getConnection') + t.equal(actualSpanChunk.spanEventList[0].serviceType, ServiceType.async.getCode(), 'spanChunk spanEventList[0].serviceType is ServiceTypeCode.async in poolCluster.getConnection') actualBuilder = new MethodDescriptorBuilder('query') .setClassName('PoolConnection') .setLineNumber(448) .setFileName('mysql.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = actualSpanChunk.spanEventList[0] + actualSpanEvent = actualSpanChunk.spanEventList[1] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'PoolConnection.query spanEvent apiId in poolCluster.getConnection') t.equal(actualSpanEvent.depth, 2, 'PoolConnection.query spanEvent depth in poolCluster.getConnection') t.equal(actualSpanEvent.sequence, 1, 'PoolConnection.query spanEvent sequence in poolCluster.getConnection') @@ -555,18 +555,18 @@ test('Disable trace', async (t) => { let callCount = 0 app.get('/test1', (req, res) => { connection.query(`SELECT * FROM member`, function (error, results) { - if (error) throw error + if (error) throw error res.send(results) }) callCount++ agent.callbackTraceClose((trace) => { if (callCount == 1) { - t.equal(trace.span.spanEventList.length, 2, 'spanEventList length is 2') + t.equal(trace.spanBuilder.spanEventList.length, 2, 'spanEventList length is 2') let actualBuilder = new MethodDescriptorBuilder('get') .setClassName('Router') let actualMethodDescriptor =apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence == 0) + let actualSpanEvent = trace.spanBuilder.spanEventList.find( spanEvent => spanEvent.sequence == 0) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId in sampled Trace of DisableTrace Functional Tests') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.get', 'apiDescriptor in sampled Trace of DisableTrace Functional Tests') t.equal(actualMethodDescriptor.className, 'Router', 'className in sampled Trace of DisableTrace Functional Tests') @@ -574,14 +574,14 @@ test('Disable trace', async (t) => { t.equal(actualSpanEvent.sequence, 0, 'spanEvent.sequence Router.get in sampled Trace of DisableTrace Functional Tests') t.equal(actualSpanEvent.depth, 1, 'spanEvent.depth Router.get in sampled Trace of DisableTrace Functional Tests') t.equal(actualSpanEvent.serviceType, ServiceType.express.getCode(), 'spanEvent.serviceType Router.get in sampled Trace of DisableTrace Functional Tests') - t.equal(actualSpanEvent.destinationId, 'localhost:5006', 'spanEvent.destinationId Router.get in sampled Trace of DisableTrace Functional Tests') - t.equal(actualSpanEvent.endPoint, 'localhost:5006', 'spanEvent.endPoint Router.get in sampled Trace of DisableTrace Functional Tests') - t.equal(actualSpanEvent.nextSpanId, -1, 'spanEvent.nextSpanId Router.get in sampled Trace of DisableTrace Functional Tests') + // t.equal(actualSpanEvent.destinationId, 'localhost:5006', 'spanEvent.destinationId Router.get in sampled Trace of DisableTrace Functional Tests') + // t.equal(actualSpanEvent.endPoint, 'localhost:5006', 'spanEvent.endPoint Router.get in sampled Trace of DisableTrace Functional Tests') + t.equal(actualSpanEvent.nextSpanId, '-1', 'spanEvent.nextSpanId Router.get in sampled Trace of DisableTrace Functional Tests') actualBuilder = new MethodDescriptorBuilder('query') .setClassName('Connection') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence == 1) + actualSpanEvent = trace.spanBuilder.spanEventList.find( spanEvent => spanEvent.sequence == 1) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId Connection.query in sampled Trace of DisableTrace Functional Tests') t.equal(actualMethodDescriptor.apiDescriptor, 'Connection.query', 'apiDescriptor Connection.query in sampled Trace of DisableTrace Functional Tests') t.equal(actualMethodDescriptor.className, 'Connection', 'className Connection.query in sampled Trace of DisableTrace Functional Tests') @@ -591,19 +591,19 @@ test('Disable trace', async (t) => { t.equal(actualSpanEvent.serviceType, mysqlExecuteQueryServiceType.getCode(), 'spanEvent.serviceType Connection.query in sampled Trace of DisableTrace Functional Tests') t.equal(actualSpanEvent.destinationId, 'test', 'spanEvent.destinationId Connection.query in sampled Trace of DisableTrace Functional Tests') t.equal(actualSpanEvent.endPoint, 'localhost', 'spanEvent.endPoint Connection.query in sampled Trace of DisableTrace Functional Tests') - t.equal(actualSpanEvent.nextSpanId, -1, 'spanEvent.nextSpanId Connection.query in sampled Trace of DisableTrace Functional Tests') - let actualNextAsyncId = actualSpanEvent.nextAsyncId - let actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualNextAsyncId) + t.equal(actualSpanEvent.nextSpanId, '-1', 'spanEvent.nextSpanId Connection.query in sampled Trace of DisableTrace Functional Tests') + let actualNextAsyncId = actualSpanEvent.asyncId + let actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualNextAsyncId) t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanChunk.spanId equals to spanEvent.spanId Connection.query in sampled Trace of DisableTrace Functional Tests') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'spanChunk.transactionIdObject Connection.query in sampled Trace of DisableTrace Functional Tests') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'spanChunk.localAsyncId.asyncId Connection.query in sampled Trace of DisableTrace Functional Tests') + t.equal(actualSpanChunk.traceRoot, trace.spanBuilder.getTraceRoot(), 'spanChunk.transactionIdObject Connection.query in sampled Trace of DisableTrace Functional Tests') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.asyncId.getAsyncId(), 'spanChunk.localAsyncId.asyncId Connection.query in sampled Trace of DisableTrace Functional Tests') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'spanChunk.localAsyncId.sequence Connection.query in sampled Trace of DisableTrace Functional Tests') t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'spanChunk.spanEventList[0].apiId is asyncInvocationDescriptor.apiId Connection.query in sampled Trace of DisableTrace Functional Tests') t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'spanChunk.spanEventList[0].depth is 1 Connection.query in sampled Trace of DisableTrace Functional Tests') t.equal(actualSpanChunk.spanEventList[0].sequence, 0, 'spanChunk.spanEventList[0].sequence is 0 Connection.query in sampled Trace of DisableTrace Functional Tests') t.equal(actualSpanChunk.spanEventList[0].serviceType, ServiceType.async.getCode(), 'spanChunk.spanEventList[0].serviceType is async Connection.query in sampled Trace of DisableTrace Functional Tests') } else if (callCount == 2) { - t.false(trace.span, 'trace.span is undefined') + t.false(trace.spanBuilder, 'trace.span is undefined') } }) }) diff --git a/test/instrumentation/module/mysql2.test.js b/test/instrumentation/module/mysql2.test.js index 1f43c487..4e2e53fb 100644 --- a/test/instrumentation/module/mysql2.test.js +++ b/test/instrumentation/module/mysql2.test.js @@ -47,53 +47,51 @@ test(`getConnection query hooking`, async (t) => { password: container.getUserPassword(), timezone: '+09:00' }) - + connection.query(`SELECT * FROM member WHERE id = ?`, 'a', function(err, results) { if (err) throw err - + t.equal(results[0].id, 'a', 'id in SELECT query hooking') t.equal(results[0].name, 'name1', 'name in SELECT query hooking') t.equal(results[0].joined.toISOString().slice(0, 10), '2023-01-17', 'joined in SELECT query hooking') }) - + connection.query(`INSERT INTO member (id, name, joined) VALUES (?, ?, ?)`, ['c', 'cname', '2023-08-18'], function(err) { if (err) throw err }) - + connection.query(`UPDATE member SET name = ? WHERE id = ?`, ['cname2', 'c'], function(err) { if (err) throw err }) - + connection.query(`DELETE FROM member WHERE id = ?`, 'c', function(err) { if (err) throw err - + setImmediate(() => { trace.close() - connection.end() - container.stop() }) }) - + agent.callbackTraceClose((trace) => { let actualBuilder = new MethodDescriptorBuilder('createConnection') .setLineNumber(42) .setFileName('mysql2.test.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - const createConnectionSpanEvent = trace.span.spanEventList[0] + const createConnectionSpanEvent = trace.spanBuilder.spanEventList[0] t.equal(createConnectionSpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in createConnection spanEvent') t.equal(createConnectionSpanEvent.endPoint, 'localhost', 'endPoint in createConnection spanEvent') t.equal(createConnectionSpanEvent.destinationId, 'test', 'destinationId in createConnection spanEvent') - + actualBuilder = new MethodDescriptorBuilder('query') .setClassName('Connection') .setLineNumber(51) .setFileName('mysql2.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let querySpanEvent = trace.span.spanEventList[1] + let querySpanEvent = trace.spanBuilder.spanEventList[1] t.equal(querySpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in query spanEvent') t.equal(querySpanEvent.endPoint, 'localhost', 'endPoint in query spanEvent') t.equal(querySpanEvent.destinationId, 'test', 'destinationId in query spanEvent') - + let actualParsingResult = sqlMetadataService.cacheSql('SELECT * FROM member WHERE id = ?') let actualQueryAnnotation = querySpanEvent.annotations[0] t.equal(actualQueryAnnotation.key, annotationKey.SQL_ID.getCode(), 'key in query annotation') @@ -101,17 +99,17 @@ test(`getConnection query hooking`, async (t) => { t.equal(actualQueryAnnotation.value.stringValue1, '', 'stringValue1 in query annotation') t.equal(actualQueryAnnotation.value.stringValue2, 'a', 'stringValue2 in query annotation') t.equal(actualParsingResult.result.sql.normalizedSql, 'SELECT * FROM member WHERE id = ?', 'normalizedSql in query annotation') - + actualBuilder = new MethodDescriptorBuilder('query') .setClassName('Connection') .setLineNumber(59) .setFileName('mysql2.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - querySpanEvent = trace.span.spanEventList[2] + querySpanEvent = trace.spanBuilder.spanEventList[2] t.equal(querySpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in query spanEvent') t.equal(querySpanEvent.endPoint, 'localhost', 'endPoint in query spanEvent') t.equal(querySpanEvent.destinationId, 'test', 'destinationId in query spanEvent') - + actualParsingResult = sqlMetadataService.cacheSql('INSERT INTO member (id, name, joined) VALUES (?, ?, ?)') actualQueryAnnotation = querySpanEvent.annotations[0] t.equal(actualQueryAnnotation.key, annotationKey.SQL_ID.getCode(), 'key in query annotation') @@ -119,17 +117,17 @@ test(`getConnection query hooking`, async (t) => { t.equal(actualQueryAnnotation.value.stringValue1, '', 'stringValue1 in query annotation') t.equal(actualQueryAnnotation.value.stringValue2, 'c,cname,2023-08-18', 'stringValue2 in query annotation') t.equal(actualParsingResult.result.sql.normalizedSql, 'INSERT INTO member (id, name, joined) VALUES (?, ?, ?)', 'normalizedSql in query annotation') - + actualBuilder = new MethodDescriptorBuilder('query') .setClassName('Connection') .setLineNumber(63) .setFileName('mysql2.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - querySpanEvent = trace.span.spanEventList[3] + querySpanEvent = trace.spanBuilder.spanEventList[3] t.equal(querySpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in query spanEvent') t.equal(querySpanEvent.endPoint, 'localhost', 'endPoint in query spanEvent') t.equal(querySpanEvent.destinationId, 'test', 'destinationId in query spanEvent') - + actualParsingResult = sqlMetadataService.cacheSql('UPDATE member SET name = ? WHERE id = ?') actualQueryAnnotation = querySpanEvent.annotations[0] t.equal(actualQueryAnnotation.key, annotationKey.SQL_ID.getCode(), 'key in query annotation') @@ -137,17 +135,17 @@ test(`getConnection query hooking`, async (t) => { t.equal(actualQueryAnnotation.value.stringValue1, '', 'stringValue1 in query annotation') t.equal(actualQueryAnnotation.value.stringValue2, 'cname2,c', 'stringValue2 in query annotation') t.equal(actualParsingResult.result.sql.normalizedSql, 'UPDATE member SET name = ? WHERE id = ?', 'normalizedSql in query annotation') - + actualBuilder = new MethodDescriptorBuilder('query') .setClassName('Connection') .setLineNumber(67) .setFileName('mysql2.test.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - querySpanEvent = trace.span.spanEventList[4] + querySpanEvent = trace.spanBuilder.spanEventList[4] t.equal(querySpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in query spanEvent') t.equal(querySpanEvent.endPoint, 'localhost', 'endPoint in query spanEvent') t.equal(querySpanEvent.destinationId, 'test', 'destinationId in query spanEvent') - + actualParsingResult = sqlMetadataService.cacheSql('DELETE FROM member WHERE id = ?') actualQueryAnnotation = querySpanEvent.annotations[0] t.equal(actualQueryAnnotation.key, annotationKey.SQL_ID.getCode(), 'key in query annotation') @@ -155,8 +153,14 @@ test(`getConnection query hooking`, async (t) => { t.equal(actualQueryAnnotation.value.stringValue1, '', 'stringValue1 in query annotation') t.equal(actualQueryAnnotation.value.stringValue2, 'c', 'stringValue2 in query annotation') t.equal(actualParsingResult.result.sql.normalizedSql, 'DELETE FROM member WHERE id = ?', 'normalizedSql in query annotation') + + connection.end() t.end() }) + + t.teardown(async () => { + await container.stop() + }) }) }) @@ -174,7 +178,7 @@ test(`getConnection promise query hooking`, async (t) => { target: '/docker-entrypoint-initdb.d/mysql.sql' }]) .start() - + const trace = agent.createTraceObject() localStorage.run(trace, async () => { const connection = mysql.createConnection({ @@ -185,39 +189,32 @@ test(`getConnection promise query hooking`, async (t) => { password: container.getUserPassword(), timezone: '+09:00' }) - + const [rows] = await connection.promise().query(`SELECT * FROM member WHERE id = ?`, 'a') t.equal(rows[0].id, 'a', 'id in SELECT query hooking') t.equal(rows[0].name, 'name1', 'name in SELECT query hooking') t.equal(rows[0].joined.toISOString().slice(0, 10), '2023-01-17', 'joined in SELECT query hooking') - - setImmediate(() => { - trace.close() - connection.end() - container.stop() - t.end() - }) - + agent.callbackTraceClose((trace) => { let actualBuilder = new MethodDescriptorBuilder('createConnection') - .setLineNumber(180) + .setLineNumber(184) .setFileName('mysql2.test.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - const createConnectionSpanEvent = trace.span.spanEventList[0] + const createConnectionSpanEvent = trace.spanBuilder.spanEventList[0] t.equal(createConnectionSpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in createConnection spanEvent') t.equal(createConnectionSpanEvent.endPoint, 'localhost', 'endPoint in createConnection spanEvent') t.equal(createConnectionSpanEvent.destinationId, 'test', 'destinationId in createConnection spanEvent') - + actualBuilder = new MethodDescriptorBuilder('query') .setClassName('Connection') .setLineNumber(103) .setFileName('promise.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let querySpanEvent = trace.span.spanEventList[1] + let querySpanEvent = trace.spanBuilder.spanEventList[1] t.equal(querySpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in query spanEvent') t.equal(querySpanEvent.endPoint, 'localhost', 'endPoint in query spanEvent') t.equal(querySpanEvent.destinationId, 'test', 'destinationId in query spanEvent') - + let actualParsingResult = sqlMetadataService.cacheSql('SELECT * FROM member WHERE id = ?') let actualQueryAnnotation = querySpanEvent.annotations[0] t.equal(actualQueryAnnotation.key, annotationKey.SQL_ID.getCode(), 'key in query annotation') @@ -226,6 +223,16 @@ test(`getConnection promise query hooking`, async (t) => { t.equal(actualQueryAnnotation.value.stringValue2, 'a', 'stringValue2 in query annotation') t.equal(actualParsingResult.result.sql.normalizedSql, 'SELECT * FROM member WHERE id = ?', 'normalizedSql in query annotation') }) + + setImmediate(() => { + trace.close() + connection.end() + t.end() + }) + }) + + t.teardown(async () => { + await container.stop() }) }) @@ -243,7 +250,7 @@ test(`Connection Pool with query hooking`, async (t) => { target: '/docker-entrypoint-initdb.d/mysql.sql' }]) .start() - + const trace = agent.createTraceObject() localStorage.run(trace, async () => { const pool = mysql.createPool({ @@ -255,66 +262,71 @@ test(`Connection Pool with query hooking`, async (t) => { timezone: '+09:00' }) const promisePool = pool.promise() - + const [rows] = await promisePool.query(`SELECT * FROM member WHERE id = ?`, 'a') t.equal(rows[0].id, 'a', 'id in SELECT query hooking') t.equal(rows[0].name, 'name1', 'name in SELECT query hooking') t.equal(rows[0].joined.toISOString().slice(0, 10), '2023-01-17', 'joined in SELECT query hooking') - - setTimeout(() => { - trace.close() - pool.end() - container.stop() - t.end() - }, 1000) - + agent.callbackTraceClose((trace) => { let actualBuilder = new MethodDescriptorBuilder('createPool') - .setLineNumber(249) + .setLineNumber(256) .setFileName('mysql2.test.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence == 0) + let actualSpanEvent = trace.spanBuilder.spanEventList.find( spanEvent => spanEvent.sequence == 0) t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in createPool spanEvent') t.equal(actualSpanEvent.endPoint, 'localhost', 'endPoint in createPool spanEvent') t.equal(actualSpanEvent.destinationId, 'test', 'destinationId in createPool spanEvent') t.equal(actualSpanEvent.sequence, 0, 'sequence in createPool spanEvent') t.equal(actualSpanEvent.depth, 1, 'depth in createPool spanEvent') t.equal(actualSpanEvent.serviceType, mysqlServiceType.getCode(), 'serviceType in createPool spanEvent') - + actualBuilder = new MethodDescriptorBuilder('getConnection') .setClassName('Pool') .setLineNumber(144) .setFileName('pool.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find( spanEvent => spanEvent.sequence == 1) + actualSpanEvent = trace.spanBuilder.spanEventList.find( spanEvent => spanEvent.sequence == 1) t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in Pool.getConnection() spanEvent') t.equal(actualSpanEvent.endPoint, 'localhost', 'endPoint in Pool.getConnection() spanEvent') t.equal(actualSpanEvent.destinationId, 'test', 'destinationId in Pool.getConnection() spanEvent') t.equal(actualSpanEvent.sequence, 1, 'sequence in Pool.getConnection() spanEvent') t.equal(actualSpanEvent.depth, 1, 'depth in Pool.getConnection() spanEvent') t.equal(actualSpanEvent.serviceType, mysqlServiceType.getCode(), 'serviceType in Pool.getConnection() spanEvent') - - let actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualSpanEvent.nextAsyncId) - t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanId in spanChunk in Pool.getConnection()') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionIdObject in spanChunk in Pool.getConnection()') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'localAsyncId asyncId in spanChunk in Pool.getConnection()') + + let actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualSpanEvent.asyncId) + t.equal(actualSpanChunk.traceRoot.getTraceId().getSpanId(), trace.spanBuilder.getTraceRoot().getTraceId().getSpanId(), 'spanId in spanChunk in Pool.getConnection()') + t.equal(actualSpanChunk.getTraceRoot(), trace.getTraceRoot(), 'transactionIdObject in spanChunk in Pool.getConnection()') + t.equal(actualSpanChunk.localAsyncId.getAsyncId(), actualSpanEvent.asyncId.getAsyncId(), 'localAsyncId asyncId in spanChunk in Pool.getConnection()') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId sequence in spanChunk in Pool.getConnection()') - t.equal(actualSpanChunk.spanEventList[1].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationMethodDescriptor.apiId, 'apiId in spanChunk in Pool.getConnection()') - t.equal(actualSpanChunk.spanEventList[1].sequence, 0, 'sequence in spanChunk in Pool.getConnection()') - t.equal(actualSpanChunk.spanEventList[1].depth, 1, 'depth in spanChunk in Pool.getConnection()') - t.equal(actualSpanChunk.spanEventList[1].serviceType, ServiceType.async.getCode(), 'serviceType in spanChunk in Pool.getConnection()') + t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationMethodDescriptor.apiId, 'apiId in spanChunk in Pool.getConnection()') + t.equal(actualSpanChunk.spanEventList[0].sequence, 0, 'sequence in spanChunk in Pool.getConnection()') + t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'depth in spanChunk in Pool.getConnection()') + t.equal(actualSpanChunk.spanEventList[0].serviceType, ServiceType.async.getCode(), 'serviceType in spanChunk in Pool.getConnection()') actualBuilder = new MethodDescriptorBuilder('query') .setClassName('PoolConnection') .setLineNumber(154) .setFileName('pool.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = actualSpanChunk.spanEventList[0] + actualSpanEvent = actualSpanChunk.spanEventList[1] t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in PoolConnection.query() spanEvent') t.equal(actualSpanEvent.depth, 2, 'depth in PoolConnection.query() spanEvent') t.equal(actualSpanEvent.sequence, 1, 'sequence in PoolConnection.query() spanEvent') t.equal(actualSpanEvent.serviceType, mysqlExecuteQueryServiceType.getCode(), 'serviceType in PoolConnection.query() spanEvent') + }) + + setImmediate(() => { + trace.close() + pool.end(() => { + t.end() + }) + }) + }) + + t.teardown(async () => { + await container.stop() }) }) @@ -361,81 +373,83 @@ test(`Cluster with query`, async (t) => { timezone: '+09:00' }) const connection = await poolCluster.getConnection() - + const [results] = await connection.query(`SELECT * FROM member WHERE id = ?`, 'a') t.equal(results[0].id, 'a', 'id in SELECT query hooking') t.equal(results[0].name, 'name1', 'name in SELECT query hooking') t.equal(results[0].joined.toISOString().slice(0, 10), '2023-01-17', 'joined in SELECT query hooking') - + agent.callbackTraceClose((trace) => { let actualBuilder = new MethodDescriptorBuilder('createPoolCluster') .setLineNumber(545) .setFileName('promise.js') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = trace.span.spanEventList[0] + let actualSpanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in createPoolCluster spanEvent') t.equal(actualSpanEvent.sequence, 0, 'sequence in createPoolCluster spanEvent') t.equal(actualSpanEvent.depth, 1, 'depth in createPoolCluster spanEvent') t.equal(actualSpanEvent.serviceType, mysqlServiceType.getCode(), 'serviceType in createPoolCluster spanEvent') - + actualBuilder = new MethodDescriptorBuilder('of') .setLineNumber(169) .setFileName('pool_cluster.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList[1] + actualSpanEvent = trace.spanBuilder.spanEventList[1] t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in PoolCluster.of() spanEvent') t.equal(actualSpanEvent.sequence, 1, 'sequence in PoolCluster.of() spanEvent') t.equal(actualSpanEvent.depth, 1, 'depth in PoolCluster.of() spanEvent') t.equal(actualSpanEvent.serviceType, mysqlServiceType.getCode(), 'serviceType in PoolCluster.of() spanEvent') - + actualBuilder = new MethodDescriptorBuilder('getConnection') .setClassName('Pool') .setLineNumber(177) .setFileName('pool_cluster.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList[2] + actualSpanEvent = trace.spanBuilder.spanEventList[2] t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in Pool.getConnection() spanEvent') t.equal(actualSpanEvent.sequence, 2, 'sequence in Pool.getConnection() spanEvent') t.equal(actualSpanEvent.depth, 1, 'depth in Pool.getConnection() spanEvent') t.equal(actualSpanEvent.serviceType, mysqlServiceType.getCode(), 'serviceType in Pool.getConnection() spanEvent') - - let actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualSpanEvent.nextAsyncId) - t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanId in spanChunk in PoolCluster.getConnection()') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionIdObject in spanChunk in PoolCluster.getConnection()') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'localAsyncId asyncId in spanChunk in PoolCluster.getConnection()') + + let actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualSpanEvent.asyncId) + t.equal(actualSpanChunk.getTraceRoot(), trace.spanBuilder.getTraceRoot(), 'spanId in spanChunk in PoolCluster.getConnection()') + t.equal(actualSpanChunk.getTraceRoot().getTransactionId(), trace.spanBuilder.getTraceRoot().getTransactionId(), 'transactionIdObject in spanChunk in PoolCluster.getConnection()') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.asyncId.asyncId, 'localAsyncId asyncId in spanChunk in PoolCluster.getConnection()') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId sequence in spanChunk in PoolCluster.getConnection()') t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationMethodDescriptor.apiId, 'apiId in spanChunk in PoolCluster.getConnection()') t.equal(actualSpanChunk.spanEventList[0].sequence, 0, 'sequence in spanChunk in PoolCluster.getConnection()') t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'depth in spanChunk in PoolCluster.getConnection()') t.equal(actualSpanChunk.spanEventList[0].serviceType, ServiceType.async.getCode(), 'serviceType in spanChunk in PoolCluster.getConnection()') - + actualBuilder = new MethodDescriptorBuilder('query') .setClassName('PoolConnection') .setLineNumber(103) .setFileName('promise.js') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList[3] + actualSpanEvent = trace.spanBuilder.spanEventList[3] t.equal(actualSpanEvent.apiId, actualMethodDescriptor.apiId, 'apiId in PoolConnection.query() spanEvent') t.equal(actualSpanEvent.sequence, 3, 'sequence in PoolConnection.query() spanEvent') t.equal(actualSpanEvent.depth, 1, 'depth in PoolConnection.query() spanEvent') t.equal(actualSpanEvent.serviceType, mysqlExecuteQueryServiceType.getCode(), 'serviceType in PoolConnection.query() spanEvent') - - actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualSpanEvent.nextAsyncId) - t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'spanId in spanChunk in PoolConnection.query()') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionIdObject in spanChunk in PoolConnection.query()') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.nextAsyncId, 'localAsyncId asyncId in spanChunk in PoolConnection.query()') + + actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualSpanEvent.asyncId) + t.equal(actualSpanChunk.getTraceRoot(), trace.spanBuilder.getTraceRoot(), 'spanId in spanChunk in PoolConnection.query()') + t.equal(actualSpanChunk.getTraceRoot().getTransactionId(), trace.spanBuilder.getTraceRoot().getTransactionId(), 'transactionIdObject in spanChunk in PoolConnection.query()') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualSpanEvent.asyncId.asyncId, 'localAsyncId asyncId in spanChunk in PoolConnection.query()') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId sequence in spanChunk in PoolConnection.query()') t.equal(actualSpanChunk.spanEventList[0].apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationMethodDescriptor.apiId, 'apiId in spanChunk in PoolConnection.query()') t.equal(actualSpanChunk.spanEventList[0].sequence, 0, 'sequence in spanChunk in PoolConnection.query()') t.equal(actualSpanChunk.spanEventList[0].depth, 1, 'depth in spanChunk in PoolConnection.query()') t.equal(actualSpanChunk.spanEventList[0].serviceType, ServiceType.async.getCode(), 'serviceType in spanChunk in PoolConnection.query()') + t.end() }) - + setImmediate(() => { trace.close() connection.release() - container.stop() - t.end() }) }) + t.teardown(async () => { + await container.stop() + }) }) \ No newline at end of file diff --git a/test/instrumentation/module/redis.test.js b/test/instrumentation/module/redis.test.js index 0cc37353..ea24e679 100644 --- a/test/instrumentation/module/redis.test.js +++ b/test/instrumentation/module/redis.test.js @@ -21,7 +21,7 @@ const defaultPredefinedMethodDescriptorRegistry = require('../../../lib/constant const ServiceType = require('../../../lib/context/service-type') const annotationKey = require('../../../lib/constant/annotation-key') const localStorage = require('../../../lib/instrumentation/context/local-storage') -const { getAsyncTraceByAsyncId, assertSpanChunk, assertTrace } = require('../../fixture') +const { assertTrace } = require('../../fixture') const https = require('https') const TEST_ENV = { @@ -74,10 +74,10 @@ test(`${testName1} should Record the connections between express and redis.`, as axios.get(`https://www.naver.com`, { httpsAgent: new https.Agent({ keepAlive: false }) }) .then(function (response) { const actualHttpCallbackNextAsyncId = actualNextAsyncId - const actualHttpCallbackSpanChunk = trace.storage.dataSender.findSpanChunk(actualHttpCallbackNextAsyncId) - t.equal(actualHttpCallbackSpanChunk.spanId, actualSpanId, 'HTTP request callback spanId') - t.equal(actualHttpCallbackSpanChunk.transactionIdObject, trace.traceId.transactionId, 'HTTP request callback transactionId') - t.equal(actualHttpCallbackSpanChunk.localAsyncId.asyncId, actualHttpCallbackNextAsyncId, 'HTTP request callback localAsyncId.asyncId') + const actualHttpCallbackSpanChunk = trace.repository.dataSender.findSpanChunk(actualHttpCallbackNextAsyncId) + t.equal(actualHttpCallbackSpanChunk.traceRoot.getTraceId().getSpanId(), trace.traceRoot.getTraceId().getSpanId(), 'HTTP request callback spanId') + t.equal(actualHttpCallbackSpanChunk.getTraceRoot(), trace.getTraceRoot(), 'HTTP request callback transactionId') + t.equal(actualHttpCallbackSpanChunk.localAsyncId.asyncId, actualHttpCallbackNextAsyncId.asyncId, 'HTTP request callback localAsyncId.asyncId') t.equal(actualHttpCallbackSpanChunk.localAsyncId.sequence, 1, 'HTTP request callback localAsyncId.sequence') let actualSpanEvent = actualHttpCallbackSpanChunk.spanEventList.find(spanEvent => spanEvent.sequence === 0) @@ -105,10 +105,10 @@ test(`${testName1} should Record the connections between express and redis.`, as req.cache.expire(key, 10) assertTrace(trace => { - let actualSpanChunk = trace.storage.dataSender.mockSpanChunks[0] - t.equal(actualSpanChunk.spanId, actualSpanId, 'spanId') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionId') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId, 'localAsyncId.asyncId') + let actualSpanChunk = trace.repository.dataSender.mockSpanChunks[0] + t.equal(actualSpanChunk.traceRoot.getTraceId().getSpanId(), trace.traceRoot.getTraceId().getSpanId(), 'spanId') + t.equal(actualSpanChunk.getTraceRoot(), trace.getTraceRoot(), 'transactionId') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId.asyncId, 'localAsyncId.asyncId') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId.sequence') let actualSpanEvent = actualSpanChunk.spanEventList.find(spanEvent => spanEvent.sequence === 0) @@ -125,7 +125,7 @@ test(`${testName1} should Record the connections between express and redis.`, as let actualAnnotation = actualSpanEvent.annotations.find(annotation => annotation.key === annotationKey.API.getCode()) t.equal(actualAnnotation.value, 'http.request', 'HTTP request annotation value') - actualNextAsyncId = actualSpanEvent.nextAsyncId + actualNextAsyncId = actualSpanEvent.asyncId actualSpanEvent = actualSpanChunk.spanEventList.find(spanEvent => spanEvent.sequence === 2) let actualBuilder = new MethodDescriptorBuilder('expire') @@ -147,7 +147,7 @@ test(`${testName1} should Record the connections between express and redis.`, as let actualBuilder = new MethodDescriptorBuilder('use') .setClassName('Router') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = trace.span.spanEventList[0] + let actualSpanEvent = trace.spanBuilder.spanEventList[0] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.use', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'Router', 'className') @@ -159,7 +159,7 @@ test(`${testName1} should Record the connections between express and redis.`, as actualBuilder = new MethodDescriptorBuilder('use') .setClassName('Router') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList[1] + actualSpanEvent = trace.spanBuilder.spanEventList[1] t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.use', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'Router', 'className') @@ -171,7 +171,7 @@ test(`${testName1} should Record the connections between express and redis.`, as actualBuilder = new MethodDescriptorBuilder('post') .setClassName('Router') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find(spanEvent => spanEvent.sequence === 2) + actualSpanEvent = trace.spanBuilder.spanEventList.find(spanEvent => spanEvent.sequence === 2) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.post', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'Router', 'className') @@ -183,7 +183,7 @@ test(`${testName1} should Record the connections between express and redis.`, as actualBuilder = new MethodDescriptorBuilder('set') .setClassName('RedisClient') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find(spanEvent => spanEvent.sequence === 3) + actualSpanEvent = trace.spanBuilder.spanEventList.find(spanEvent => spanEvent.sequence === 3) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'RedisClient.set', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'RedisClient', 'className') @@ -193,8 +193,8 @@ test(`${testName1} should Record the connections between express and redis.`, as t.equal(actualSpanEvent.serviceType, 8200, 'serviceType') t.equal(actualSpanEvent.destinationId, 'Redis', 'destinationId') t.equal(actualSpanEvent.endPoint, `localhost:${container.getMappedPort(6379)}`, 'endPoint') - actualNextAsyncId = actualSpanEvent.nextAsyncId - actualSpanId = actualSpanEvent.spanId + actualNextAsyncId = actualSpanEvent.asyncId + actualSpanId = trace.spanBuilder.traceRoot.getTraceId().getSpanId() }) res.json(value) }) @@ -236,7 +236,7 @@ test(`${testName1} redis callback nested asyncTrace with await HTTP get`, async .withWaitStrategy(Wait.forAll([ Wait.forListeningPorts(), Wait.forLogMessage("Ready to accept connections") - ])) + ])) .start() const testName = testName1 @@ -264,7 +264,7 @@ test(`${testName1} redis callback nested asyncTrace with await HTTP get`, async let actualBuilder = new MethodDescriptorBuilder('post') .setClassName('Router') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = trace.span.spanEventList.find(spanEvent => spanEvent.sequence === 0) + let actualSpanEvent = trace.spanBuilder.spanEventList.find(spanEvent => spanEvent.sequence === 0) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.post', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'Router', 'className') @@ -276,7 +276,7 @@ test(`${testName1} redis callback nested asyncTrace with await HTTP get`, async actualBuilder = new MethodDescriptorBuilder('set') .setClassName('RedisClient') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find(spanEvent => spanEvent.sequence === 1) + actualSpanEvent = trace.spanBuilder.spanEventList.find(spanEvent => spanEvent.sequence === 1) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'RedisClient.set', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'RedisClient', 'className') @@ -286,12 +286,12 @@ test(`${testName1} redis callback nested asyncTrace with await HTTP get`, async t.equal(actualSpanEvent.serviceType, 8200, 'serviceType') t.equal(actualSpanEvent.destinationId, 'Redis', 'destinationId') t.equal(actualSpanEvent.endPoint, `localhost:${container.getMappedPort(6379)}`, 'endPoint') - let actualNextAsyncId = actualSpanEvent.nextAsyncId + let actualNextAsyncId = actualSpanEvent.asyncId - let actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualNextAsyncId) - t.equal(actualSpanChunk.spanId, actualSpanEvent.spanId, 'RedisClient.set spanChunk.spanId') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'RedisClient.set spanChunk.agentId') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId, 'RedisClient.set spanChunk.localAsyncId.asyncId') + let actualSpanChunk = trace.repository.dataSender.findSpanChunk(actualNextAsyncId) + t.equal(actualSpanChunk.traceRoot.getTraceId().getSpanId(), trace.spanBuilder.traceRoot.getTraceId().getSpanId(), 'RedisClient.set spanChunk.spanId') + t.equal(actualSpanChunk.getTraceRoot(), trace.getTraceRoot(), 'RedisClient.set spanChunk.agentId') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId.asyncId, 'RedisClient.set spanChunk.localAsyncId.asyncId') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'RedisClient.set spanChunk.localAsyncId.sequence') actualSpanEvent = actualSpanChunk.spanEventList.find(spanEvent => spanEvent.sequence === 0) @@ -329,7 +329,7 @@ test(`${testName2} should Record the connections between express and ioredis.`, .withWaitStrategy(Wait.forAll([ Wait.forListeningPorts(), Wait.forLogMessage("Ready to accept connections") - ])) + ])) .start() const testName = testName2 @@ -392,7 +392,7 @@ test(`${testName3} should Record the connections between koa and redis.`, async .withWaitStrategy(Wait.forAll([ Wait.forListeningPorts(), Wait.forLogMessage("Ready to accept connections") - ])) + ])) .start() const testName = testName3 @@ -450,7 +450,7 @@ test(`${testName4} should Record the connections between koa and ioredis.`, asyn .withWaitStrategy(Wait.forAll([ Wait.forListeningPorts(), Wait.forLogMessage("Ready to accept connections") - ])) + ])) .start() const testName = testName4 @@ -527,7 +527,7 @@ test(`${testName1} await connections between express and redis.`, async function .withWaitStrategy(Wait.forAll([ Wait.forListeningPorts(), Wait.forLogMessage("Ready to accept connections") - ])) + ])) .start() const testName = testName1 @@ -536,17 +536,21 @@ test(`${testName1} await connections between express and redis.`, async function const PATH = `/${testName}` app.post(PATH, function (req, res, next) { + const trace = agent.currentTraceObject() + let traceRoot = trace.getTraceRoot() + let actualHttpCallbackNextAsyncId client.set('key', 'value', async function (err, data) { if (err) { console.log(err) res.send("error " + err) return } - assertTrace(async trace => { - let actualSpanChunk = trace.storage.dataSender.findSpanChunk(actualNextAsyncId) - t.equal(actualSpanChunk.spanId, actualSpanId, 'spanId') - t.equal(actualSpanChunk.transactionIdObject, trace.traceId.transactionId, 'transactionId') - t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId, 'localAsyncId.asyncId') + assertTrace(async childTrace => { + let actualSpanChunk = childTrace.repository.dataSender.mockSpanChunks[0] + let actualNextAsyncId = trace.repository.buffer.find(spanEvent => spanEvent.sequence === 1).asyncId + t.equal(actualSpanChunk.traceRoot.getTraceId().getSpanId(), traceRoot.getTraceId().getSpanId(), 'spanId') + t.equal(actualSpanChunk.getTraceRoot(), trace.getTraceRoot(), 'transactionId') + t.equal(actualSpanChunk.localAsyncId.asyncId, actualNextAsyncId.asyncId, 'localAsyncId.asyncId') t.equal(actualSpanChunk.localAsyncId.sequence, 1, 'localAsyncId.sequence') let actualSpanEvent = actualSpanChunk.spanEventList.find(spanEvent => spanEvent.sequence === 0) @@ -568,7 +572,7 @@ test(`${testName1} await connections between express and redis.`, async function t.equal(actualSpanEvent.serviceType, 8200, 'RedisClient.expire actualSpanEvent.serviceType') t.equal(actualSpanEvent.destinationId, 'Redis', 'RedisClient.expire actualSpanEvent.destinationId') t.equal(actualSpanEvent.endPoint, `localhost:${container.getMappedPort(6379)}`, 'RedisClient.expire actualSpanEvent.endPoint') - actualNextAsyncId = actualSpanEvent.nextAsyncId + actualNextAsyncId = actualSpanEvent.asyncId actualSpanEvent = actualSpanChunk.spanEventList.find(spanEvent => spanEvent.sequence === 2) t.equal(actualSpanEvent.apiId, 0, 'HTTP request apiId') @@ -579,52 +583,53 @@ test(`${testName1} await connections between express and redis.`, async function let actualAnnotation = actualSpanEvent.annotations.find(annotation => annotation.key === annotationKey.API.getCode()) t.equal(actualAnnotation.value, 'http.request', 'HTTP request annotation value') - const actualHttpCallbackNextAsyncId = actualSpanEvent.nextAsyncId - let asyncTrace = getAsyncTraceByAsyncId(actualHttpCallbackNextAsyncId) - assertSpanChunk(asyncTrace, actualHttpCallbackSpanChunk => { - t.equal(actualHttpCallbackSpanChunk.spanId, actualSpanEvent.spanId, 'HTTP request callback spanId') - t.equal(actualHttpCallbackSpanChunk.transactionIdObject, asyncTrace.traceId.transactionId, 'HTTP request callback transactionId') - t.equal(actualHttpCallbackSpanChunk.localAsyncId.asyncId, actualHttpCallbackNextAsyncId, 'HTTP request callback localAsyncId.asyncId') - t.equal(actualHttpCallbackSpanChunk.localAsyncId.sequence, 1, 'HTTP request callback localAsyncId.sequence') - - actualSpanEvent = actualHttpCallbackSpanChunk.spanEventList.find(spanEvent => spanEvent.sequence === 0) - t.equal(actualSpanEvent.apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'HTTP request callback asyncInvocationDescriptor.spanEvent.apiId') - t.equal(actualSpanEvent.depth, 1, 'HTTP request callback asyncInvocationDescriptor.spanEvent.depth') - t.equal(actualSpanEvent.sequence, 0, 'HTTP request callback asyncInvocationDescriptor.spanEvent.sequence') - t.equal(actualSpanEvent.serviceType, ServiceType.async.getCode(), 'HTTP request callback asyncInvocationDescriptor.spanEvent.serviceType') - - actualSpanEvent = actualHttpCallbackSpanChunk.spanEventList.find(spanEvent => spanEvent.sequence === 1) - t.equal(actualSpanEvent.apiId, 0, 'HTTP request callback spanEvent.apiId') - t.equal(actualSpanEvent.depth, 2, 'HTTP request callback spanEvent.depth') - t.equal(actualSpanEvent.sequence, 1, 'HTTP request callback spanEvent.sequence') - t.equal(actualSpanEvent.serviceType, ServiceType.asyncHttpClient.getCode(), 'HTTP request callback spanEvent.serviceType') + actualHttpCallbackNextAsyncId = actualSpanEvent.asyncId + t.equal(actualSpanChunk.spanEventList.length, 3, 'spanEventList.length') - actualAnnotation = actualSpanEvent.annotations[0] - t.equal(actualAnnotation.key, annotationKey.API.getCode(), 'HTTP request callback spanEvent.annotation[0].key') - t.equal(actualAnnotation.value, 'GET', 'HTTP request callback spanEvent.annotation[0].value') - actualAnnotation = actualSpanEvent.annotations[1] - t.equal(actualAnnotation.key, annotationKey.HTTP_URL.getCode(), 'HTTP request callback spanEvent.annotation[1].key annotationKey.HTTP_URL') - t.equal(actualAnnotation.value, 'www.naver.com/', 'HTTP request callback spanEvent.annotation[1].value annotationKey.HTTP_URL') - actualAnnotation = actualSpanEvent.annotations[2] - t.equal(actualAnnotation.key, annotationKey.HTTP_STATUS_CODE.getCode(), 'HTTP request callback spanEvent.annotation[2].key annotationKey.HTTP_STATUS_CODE') - t.equal(actualAnnotation.value, 200, 'HTTP request callback spanEvent.annotation[2].value annotationKey.HTTP_STATUS_CODE') - }) - t.equal(actualSpanChunk.spanEventList.length, 3, 'spanEventList.length') }) client.expire('key', 10) await axios.get(`https://www.naver.com`, { httpsAgent: new https.Agent({ keepAlive: false }) }) + + const actualOutgoingChildTrace = agent.getTraces(2) + const asyncSpanChunk = actualOutgoingChildTrace.repository.dataSender.findSpanChunk(actualOutgoingChildTrace.localAsyncId) + t.equal(asyncSpanChunk.getTraceRoot().getTraceId().getSpanId(), traceRoot.getTraceId().getSpanId(), 'HTTP request callback spanId') + t.equal(asyncSpanChunk.getTraceRoot(), traceRoot, 'HTTP request callback transactionId') + t.equal(asyncSpanChunk.localAsyncId.asyncId, actualHttpCallbackNextAsyncId.asyncId, 'HTTP request callback localAsyncId.asyncId') + t.equal(asyncSpanChunk.localAsyncId.sequence, 1, 'HTTP request callback localAsyncId.sequence') + + let actualSpanEvent = asyncSpanChunk.spanEventList.find(spanEvent => spanEvent.sequence === 0) + t.equal(actualSpanEvent.apiId, defaultPredefinedMethodDescriptorRegistry.asyncInvocationDescriptor.apiId, 'HTTP request callback asyncInvocationDescriptor.spanEvent.apiId') + t.equal(actualSpanEvent.depth, 1, 'HTTP request callback asyncInvocationDescriptor.spanEvent.depth') + t.equal(actualSpanEvent.sequence, 0, 'HTTP request callback asyncInvocationDescriptor.spanEvent.sequence') + t.equal(actualSpanEvent.serviceType, ServiceType.async.getCode(), 'HTTP request callback asyncInvocationDescriptor.spanEvent.serviceType') + + actualSpanEvent = asyncSpanChunk.spanEventList.find(spanEvent => spanEvent.sequence === 1) + t.equal(actualSpanEvent.apiId, 0, 'HTTP request callback spanEvent.apiId') + t.equal(actualSpanEvent.depth, 2, 'HTTP request callback spanEvent.depth') + t.equal(actualSpanEvent.sequence, 1, 'HTTP request callback spanEvent.sequence') + t.equal(actualSpanEvent.serviceType, ServiceType.asyncHttpClient.getCode(), 'HTTP request callback spanEvent.serviceType') + + let actualAnnotation = actualSpanEvent.annotations[0] + t.equal(actualAnnotation.key, annotationKey.API.getCode(), 'HTTP request callback spanEvent.annotation[0].key') + t.equal(actualAnnotation.value, 'GET', 'HTTP request callback spanEvent.annotation[0].value') + actualAnnotation = actualSpanEvent.annotations[1] + t.equal(actualAnnotation.key, annotationKey.HTTP_URL.getCode(), 'HTTP request callback spanEvent.annotation[1].key annotationKey.HTTP_URL') + t.equal(actualAnnotation.value, 'www.naver.com/', 'HTTP request callback spanEvent.annotation[1].value annotationKey.HTTP_URL') + actualAnnotation = actualSpanEvent.annotations[2] + t.equal(actualAnnotation.key, annotationKey.HTTP_STATUS_CODE.getCode(), 'HTTP request callback spanEvent.annotation[2].key annotationKey.HTTP_STATUS_CODE') + t.equal(actualAnnotation.value, 200, 'HTTP request callback spanEvent.annotation[2].value annotationKey.HTTP_STATUS_CODE') + client.quit() await container.stop() + res.json('ok') }) - let actualNextAsyncId - let actualSpanId assertTrace(trace => { let actualBuilder = new MethodDescriptorBuilder('post') .setClassName('Router') let actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - let actualSpanEvent = trace.span.spanEventList.find(spanEvent => spanEvent.sequence === 0) + let actualSpanEvent = trace.spanBuilder.spanEventList.find(spanEvent => spanEvent.sequence === 0) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'Router.post', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'Router', 'className') @@ -636,7 +641,7 @@ test(`${testName1} await connections between express and redis.`, async function actualBuilder = new MethodDescriptorBuilder('set') .setClassName('RedisClient') actualMethodDescriptor = apiMetaService.cacheApiWithBuilder(actualBuilder) - actualSpanEvent = trace.span.spanEventList.find(spanEvent => spanEvent.sequence === 1) + actualSpanEvent = trace.spanBuilder.spanEventList.find(spanEvent => spanEvent.sequence === 1) t.equal(actualMethodDescriptor.apiId, actualSpanEvent.apiId, 'apiId') t.equal(actualMethodDescriptor.apiDescriptor, 'RedisClient.set', 'apiDescriptor') t.equal(actualMethodDescriptor.className, 'RedisClient', 'className') @@ -646,11 +651,7 @@ test(`${testName1} await connections between express and redis.`, async function t.equal(actualSpanEvent.serviceType, 8200, 'serviceType') t.equal(actualSpanEvent.destinationId, 'Redis', 'destinationId') t.equal(actualSpanEvent.endPoint, `localhost:${container.getMappedPort(6379)}`, 'endPoint') - actualNextAsyncId = actualSpanEvent.nextAsyncId - actualSpanId = actualSpanEvent.spanId }) - - res.json('ok') }) const server = app.listen(TEST_ENV.port, async function () { diff --git a/test/instrumentation/pinpoint-http-header.test.js b/test/instrumentation/pinpoint-http-header.test.js index b13d69ee..22787ada 100644 --- a/test/instrumentation/pinpoint-http-header.test.js +++ b/test/instrumentation/pinpoint-http-header.test.js @@ -22,15 +22,11 @@ test('outgoing request when canSample true', (t) => { }) function outgoingRequest(t, sampling) { - agent.bindHttp() - - const isSamplingFunction = agent.traceContext.isSampling if (sampling) { - agent.traceContext.isSampling = () => { return true } + agent.bindHttp({ 'sampling': { 'enable': true } }) } else { - agent.traceContext.isSampling = () => { return false } + agent.bindHttp({ 'sampling': { 'enable': false } }) } - const PATH = '/request' const app = new express() @@ -59,14 +55,14 @@ function outgoingRequest(t, sampling) { app.get(OUTGOING_PATH, async (req, res) => { const headers = req.headers if (sampling) { - t.equal(actualTrace.traceId.transactionId.toString(), headers['pinpoint-traceid']) - t.equal(actualTrace.traceId.spanId, headers['pinpoint-pspanid']) - t.equal(agent.config.applicationName, headers['pinpoint-pappname']) - t.equal(agent.config.serviceType, Number(headers['pinpoint-papptype'])) - t.equal(actualTrace.traceId.flag, headers['pinpoint-flags']) + t.equal(actualTrace.getTraceId().toStringDelimiterFormatted(), headers['pinpoint-traceid'], `traceId Header equals ${actualTrace.getTraceId().toStringDelimiterFormatted()}`) + t.equal(actualTrace.getTraceId().getSpanId(), headers['pinpoint-pspanid'], `spanId Header equals ${actualTrace.getTraceId().getSpanId()}`) + t.equal(agent.config.applicationName, headers['pinpoint-pappname'], `applicationName Header equals ${agent.config.applicationName}`) + t.equal(agent.config.serviceType, Number(headers['pinpoint-papptype']), `serviceType Header equals ${agent.config.serviceType}`) + t.equal(actualTrace.getTraceId().getFlags(), headers['pinpoint-flags'], `flags Header equals ${actualTrace.getTraceId().getFlags()}`) } else { // ClientCallStartInterceptor.java requestTraceWriter.write(metadata); - t.equal('s0', headers['pinpoint-sampled']) + t.equal('s0', headers['pinpoint-sampled'], `sampled Header equals ${headers['pinpoint-sampled']}`) } res.send('ok get') }) @@ -80,8 +76,6 @@ function outgoingRequest(t, sampling) { t.ok(result1.status, 200) server.close() - - agent.traceContext.isSampling = isSamplingFunction t.end() }) } @@ -126,18 +120,12 @@ function incomingRequest(t, sampled) { const trace = agent.currentTraceObject() const headers = config.headers - if (trace.traceId) { - expectedTransactionId = trace.traceId.transactionId.toString() - expectedSpanId = trace.traceId.spanId - t.equal(expectedTransactionId, headers['pinpoint-traceid']) - t.equal(expectedSpanId, headers['pinpoint-spanid']) - t.equal(trace.traceId.parentSpanId, headers['pinpoint-pspanid']) - } - if (sampled == undefined) { - t.equal(trace.sampling, true) - } else if (trace.traceId) { - t.equal(trace.canSampled(), sampled) - } + expectedTransactionId = trace.getTraceRoot().getTraceId().toStringDelimiterFormatted() + expectedSpanId = trace.getTraceRoot().getTraceId().getSpanId() + t.equal(expectedTransactionId, headers['pinpoint-traceid'], `traceId Header equals ${expectedTransactionId}`) + t.equal(expectedSpanId, headers['pinpoint-spanid'], `spanId Header equals ${expectedSpanId}`) + t.equal(trace.getTraceRoot().getTraceId().getParentSpanId(), headers['pinpoint-pspanid'], `parentSpanId Header equals ${trace.getTraceRoot().getTraceId().getParentSpanId()}`) + t.equal(trace.canSampled(), sampled, `sampled equals ${trace.canSampled()}`) const result1 = await axios.get(getServerUrl(OUTGOING_PATH), { timeout: 1000, @@ -182,24 +170,16 @@ function incomingRequest(t, sampled) { const result1 = await axios.get(getServerUrl(PATH), config) t.ok(result1.status, 200) if (sampled) { - t.equal(typeof agent.dataSender.mockSpan.spanId, "string") - t.equal(typeof agent.dataSender.mockSpan.parentSpanId, "string") - t.equal(typeof agent.dataSender.mockSpan.traceId.transactionId.agentStartTime, "string") - t.equal(typeof agent.dataSender.mockSpan.traceId.transactionId.sequence, "string") + t.equal(typeof agent.dataSender.mockSpan.traceRoot.getTraceId().getSpanId(), 'string') + t.equal(typeof agent.dataSender.mockSpan.traceRoot.getTraceId().getParentSpanId(), 'string') + t.equal(typeof agent.dataSender.mockSpan.traceRoot.getTraceId().getAgentStartTime(), 'string') + t.equal(typeof agent.dataSender.mockSpan.traceRoot.getTraceId().getTransactionId(), 'string') } server.close() t.end() }) } -test('incomming request agent sampled false', (t) => { - const config = require('../pinpoint-config-test') - config.sampling.enable = false - agent.bindHttp(config) - incomingRequest(t, false) - config.sampling.enable = true -}) - test('incomming request by User', (t) => { agent.bindHttp() @@ -210,14 +190,14 @@ test('incomming request by User', (t) => { app.get(PATH, async (req, res) => { const trace = agent.currentTraceObject() - expectedTransactionId = trace.traceId.transactionId.toString() - expectedSpanId = trace.traceId.spanId - t.equal(typeof expectedTransactionId, "string") - t.equal(typeof expectedSpanId, "string") - t.equal(trace.traceId.parentSpanId, "-1") + expectedTransactionId = trace.getTraceId().toStringDelimiterFormatted() + expectedSpanId = trace.getTraceId().spanId + t.equal(typeof expectedTransactionId, 'string') + t.equal(typeof expectedSpanId, 'string') + t.equal(trace.getTraceId().parentSpanId, "-1") t.equal(trace.canSampled(), true) - t.equal(typeof trace.traceId.transactionId.agentStartTime, "string") - t.equal(typeof trace.traceId.transactionId.sequence, "string") + t.equal(typeof trace.getTraceId().agentStartTime, 'string') + t.equal(typeof trace.getTraceId().getTransactionId(), 'string') const result1 = await axios.get(getServerUrl(OUTGOING_PATH)) t.equal(result1.data, 'ok get', 'result equals') @@ -252,10 +232,10 @@ test('incomming request by User', (t) => { const server = app.listen(TEST_ENV.port, async () => { const result1 = await axios.get(getServerUrl(PATH)) t.ok(result1.status, 200) - t.equal(typeof agent.dataSender.mockSpan.spanId, "string") - t.equal(typeof agent.dataSender.mockSpan.parentSpanId, "string") - t.equal(typeof agent.dataSender.mockSpan.traceId.transactionId.agentStartTime, "string") - t.equal(typeof agent.dataSender.mockSpan.traceId.transactionId.sequence, "string") + t.equal(typeof agent.dataSender.mockSpan.traceRoot.getTraceId().getSpanId(), 'string') + t.equal(typeof agent.dataSender.mockSpan.traceRoot.getTraceId().getParentSpanId(), 'string') + t.equal(typeof agent.dataSender.mockSpan.traceRoot.getTraceId().agentStartTime, 'string') + t.equal(typeof agent.dataSender.mockSpan.traceRoot.getTraceId().getTransactionId(), 'string') server.close() t.end() }) diff --git a/test/instrumentation/request-header-utils.test.js b/test/instrumentation/request-header-utils.test.js index e1067b75..920c9cab 100644 --- a/test/instrumentation/request-header-utils.test.js +++ b/test/instrumentation/request-header-utils.test.js @@ -9,12 +9,14 @@ const axios = require('axios') const http = require('http') const https = require('https') const { fixture } = require('../test-helper') -const RequestHeaderUtils = require('../../lib/instrumentation/request-header-utils') const agent = require('../support/agent-singleton-mock') agent.bindHttp() -const PinpointHeader = require('../../lib/constant/http-header').PinpointHeader const localStorage = require('../../lib/instrumentation/context/local-storage') const express = require('express') +const HttpOutgoingRequestHeader = require('../../lib/instrumentation/http/http-outgoing-request-header') +const HttpRequestTraceBuilder = require('../../lib/instrumentation/http/http-request-trace-builder') +const TraceHeaderBuilder = require('../../lib/instrumentation/http/trace-header-builder') +const Header = require('../../lib/instrumentation/http/pinpoint-header') const headers = { 'Pinpoint-TraceID': fixture.getTraceId().transactionId.toString(), @@ -30,10 +32,12 @@ test('Should read pinpoint header', async function (t) { res.end('hello') }) .on('request', (req, res) => { - const requestData = RequestHeaderUtils.read(req) - t.equal(requestData.endPoint, endPoint) - t.equal(requestData.rpcName, rpcName) - t.ok(requestData.transactionId) + const requestTraceBuilder = new HttpRequestTraceBuilder(agent.getTraceContext(), req) + const requestTrace = requestTraceBuilder.build() + const traceHeader = new TraceHeaderBuilder(requestTraceBuilder.request).build() + t.equal(requestTraceBuilder.request.request.headers['host'], endPoint) + t.equal(requestTrace.rpcName, rpcName) + t.ok(traceHeader.getTraceId()) }) .listen(5005, async function () { await axios.get(`http://${endPoint}${rpcName}?q=1`, { headers }) @@ -50,8 +54,17 @@ test('Should write pinpoint header', async function (t) { .on('request', (req, res) => { const trace = agent.createTraceObject() localStorage.run(trace, () => { - const writtenReq = RequestHeaderUtils.write(req, agent) - t.equal(writtenReq.headers[PinpointHeader.HTTP_TRACE_ID], trace.traceId.transactionId.toString(), "trace ID new ID was added in Header") + const requestHeader = new HttpOutgoingRequestHeader(agent.getAgentInfo(), req) + const request = requestHeader.request.request + requestHeader.request.getHeader = (name) => { + return request.headers[name] + } + requestHeader.request.setHeader = (name, value) => { + request.headers[name] = value + } + const nextTraceId = trace.getTraceId().getNextTraceId() + requestHeader.write(nextTraceId) + t.equal(request.headers[Header.traceId], trace.spanBuilder.traceRoot.getTraceId().toStringDelimiterFormatted(), "trace ID new ID was added in Header") }) }) .listen(5005, async function () { @@ -74,25 +87,13 @@ test('nested request HTTP', async function (t) { await axios.get(`http://localhost:5006/test`) res.send('ok') agent.callbackTraceClose((trace) => { - const actualRequestData = RequestHeaderUtils.read(req) - t.equal(actualRequestData.endPoint, 'localhost:5005', 'http://localhost:5005/test endPoint') - t.equal(actualRequestData.flags, undefined, 'http://localhost:5005/test flags') - t.equal(actualRequestData.host, null, 'http://localhost:5005/test host') - t.equal(actualRequestData.isRoot, true, 'http://localhost:5005/test isRoot') - t.equal(actualRequestData.parentApplicationName, null, 'http://localhost:5005/test parentApplicationName') - t.equal(actualRequestData.parentApplicationType, null, 'http://localhost:5005/test parentApplicationType') - t.equal(actualRequestData.parentSpanId, null, 'http://localhost:5005/test parentSpanId') - // t.equal(actualRequestData.remoteAddress, '127.0.0.1', 'http://localhost:5005/test remoteAddress') - t.equal(actualRequestData.rpcName, '/test', 'http://localhost:5005/test rpcName') - t.equal(actualRequestData.sampled, null, 'http://localhost:5005/test sampled') - t.equal(actualRequestData.spanId, null, 'http://localhost:5005/test spanId') - t.equal(actualRequestData.transactionId, null, 'http://localhost:5005/test transactionId') + t.equal(req.headers['host'], 'localhost:5005', 'http://localhost:5005/test endPoint') const actualTraceOn5005 = localStorage.getStore() if (actualTransactionIdSequence === undefined) { - actualTransactionIdSequence = trace.traceId.transactionId.sequence + actualTransactionIdSequence = trace.spanBuilder.traceRoot.getTraceId().transactionId } - t.equal(actualTransactionIdSequence, trace.traceId.transactionId.sequence, `http://localhost:5005/test transactionId sequence is ${actualTransactionIdSequence}`) + t.equal(actualTransactionIdSequence, trace.spanBuilder.traceRoot.getTraceId().transactionId, `http://localhost:5005/test transactionId sequence is ${actualTransactionIdSequence}`) actualAssertsOn5006(actualTraceOn5005) @@ -106,30 +107,32 @@ test('nested request HTTP', async function (t) { const actualTraceOn5006 = localStorage.getStore() actualAssertsOn5006 = (actualTraceOn5005) => { - const actualRequestData = RequestHeaderUtils.read(req) - t.equal(actualRequestData.endPoint, 'localhost:5006', 'http://localhost:5006/test endPoint') - t.equal(actualRequestData.flags, undefined, 'http://localhost:5006/test flags') - t.equal(actualRequestData.host, 'localhost:5006', 'http://localhost:5006/test host') - t.equal(actualRequestData.isRoot, false, 'http://localhost:5006/test isRoot') - t.equal(actualRequestData.parentApplicationName, 'node.test.app', 'http://localhost:5006/test parentApplicationName') - t.equal(actualRequestData.parentApplicationType, 1400, 'http://localhost:5006/test parentApplicationType') - t.equal(actualRequestData.parentSpanId, actualTraceOn5005.traceId.spanId, 'http://localhost:5006/test parentSpanId') + const requestTraceBuilder = new HttpRequestTraceBuilder(agent.getTraceContext(), req) + const requestTrace = requestTraceBuilder.build() + const traceHeader = new TraceHeaderBuilder(requestTraceBuilder.request).build() + const traceId = traceHeader.getTraceId() + t.equal(req.headers['host'], 'localhost:5006', 'http://localhost:5006/test endPoint') + t.equal(traceId.flags, 0, 'http://localhost:5006/test flags') + t.equal(traceHeader.host, 'localhost:5006', 'http://localhost:5006/test host') + t.equal(traceHeader.parentApplicationName, 'node.test.app', 'http://localhost:5006/test parentApplicationName') + t.equal(traceHeader.parentApplicationType, 1400, 'http://localhost:5006/test parentApplicationType') + t.equal(traceId.parentSpanId, actualTraceOn5005.spanBuilder.traceRoot.getTraceId().spanId, 'http://localhost:5006/test parentSpanId') // t.equal(actualRequestData.remoteAddress, '127.0.0.1', 'http://localhost:5006/test remoteAddress') - t.equal(actualRequestData.rpcName, '/test', 'http://localhost:5006/test rpcName') - t.equal(actualRequestData.sampled, null, 'http://localhost:5006/test header sampled') - t.equal(actualRequestData.spanId, actualTraceOn5006.traceId.spanId, 'http://localhost:5006/test spanId') - t.equal(actualRequestData.transactionId.toString(), actualTraceOn5006.traceId.transactionId.toString(), 'http://localhost:5006/test transactionId') - t.equal(actualTraceOn5006.traceId.transactionId.sequence, actualTransactionIdSequence, `http://localhost:5006/test transactionId sequence is ${actualTransactionIdSequence}`) + t.equal(requestTrace.rpcName, '/test', 'http://localhost:5006/test rpcName') + t.equal(traceHeader.sampled, undefined, 'http://localhost:5006/test header sampled') + t.equal(traceId.spanId, actualTraceOn5006.getTraceId().spanId, 'http://localhost:5006/test spanId') + t.deepEqual(traceId, actualTraceOn5006.getTraceId(), 'http://localhost:5006/test transactionId') + t.equal(actualTraceOn5006.getTraceId().getTransactionId(), actualTransactionIdSequence, `http://localhost:5006/test transactionId sequence is ${actualTransactionIdSequence}`) } }) const serverGraphQL = appGraphQL.listen(5006, () => { const server = app.listen(5005, async function () { - await axios.get(`http://localhost:5005/test`, { httpAgent: new http.Agent({ keepAlive: false })}) - await axios.get(`http://localhost:5005/test`, { httpAgent: new http.Agent({ keepAlive: false })}) - await axios.get(`http://localhost:5005/test`, { httpAgent: new http.Agent({ keepAlive: false })}) - await axios.get(`http://localhost:5005/test`, { httpAgent: new http.Agent({ keepAlive: false })}) - await axios.get(`http://localhost:5005/test`, { httpAgent: new http.Agent({ keepAlive: false })}) + await axios.get(`http://localhost:5005/test`, { httpAgent: new http.Agent({ keepAlive: false }) }) + await axios.get(`http://localhost:5005/test`, { httpAgent: new http.Agent({ keepAlive: false }) }) + await axios.get(`http://localhost:5005/test`, { httpAgent: new http.Agent({ keepAlive: false }) }) + await axios.get(`http://localhost:5005/test`, { httpAgent: new http.Agent({ keepAlive: false }) }) + await axios.get(`http://localhost:5005/test`, { httpAgent: new http.Agent({ keepAlive: false }) }) t.end() serverGraphQL.close() server.close() diff --git a/test/stats/active-trace.test.js b/test/stats/active-trace.test.js index 19a75185..2e02c69b 100644 --- a/test/stats/active-trace.test.js +++ b/test/stats/active-trace.test.js @@ -42,8 +42,8 @@ test(`Should record active trace in multiple call`, function (t) { axios.get(getServerUrl(LASTONE_PATH), { httpAgent: new http.Agent({ keepAlive: false })}), ]).then((result) => { t.equal(activeTrace.getAllTraces().length, 0) - t.equal(agent.mockAgentStartTime, agent.agentInfo.startTimestamp, "startTimestamp equals") - + t.equal('' + agent.mockAgentStartTime, agent.agentInfo.startTimestamp, "startTimestamp equals") + server.close() t.end() }).catch(() => { diff --git a/test/support/agent-singleton-mock.js b/test/support/agent-singleton-mock.js index 74f14be9..caaaaf64 100644 --- a/test/support/agent-singleton-mock.js +++ b/test/support/agent-singleton-mock.js @@ -13,18 +13,25 @@ const Agent = require('../../lib/agent') const dataSenderMock = require('./data-sender-mock') const shimmer = require('@pinpoint-apm/shimmer') const httpShared = require('../../lib/instrumentation/http-shared') -const TraceContext = require('../../lib/context/trace-context') const activeTrace = require('../../lib/metric/active-trace') -const apiMetaService = require('../../lib/context/api-meta-service') -const { setDataSender } = require('../../lib/client/data-sender-factory') const localStorage = require('../../lib/instrumentation/context/local-storage') -const { cleanup } = require('../fixture') const sqlMetaDataService = require('../../lib/instrumentation/sql/sql-metadata-service') const SimpleCache = require('../../lib/utils/simple-cache') const sampler = require('../../lib/sampler/sampler') +const TraceSampler = require('../../lib/context/trace/trace-sampler') const transactionIdGenerator = require('../../lib/context/sequence-generators').transactionIdGenerator const closedTraceWrapped = Symbol('closedTraceWrapped') +let traces = [] + +const resetTraces = () => { + traces = [] +} + +const getTraces = () => { + return traces +} + class MockAgent extends Agent { startSchedule(agentId, agentStartTime) { this.mockAgentId = agentId @@ -38,7 +45,7 @@ class MockAgent extends Agent { bindHttp(json) { this.cleanHttp() - apiMetaService.init(dataSenderMock()) + this.dataSender.clear() if (!json) { json = require('../pinpoint-config-test') @@ -59,10 +66,10 @@ class MockAgent extends Agent { httpShared.clearPathMatcher() const http = require('http') log.debug('shimming http.Server.prototype.emit function') - shimmer.wrap(http && http.Server && http.Server.prototype, 'emit', httpShared.instrumentRequest(agent, 'http')) + shimmer.wrap(http && http.Server && http.Server.prototype, 'emit', httpShared.instrumentRequest2(agent, 'http')) log.debug('shimming http.request function') - shimmer.wrap(http, 'request', httpShared.traceOutgoingRequest(agent, 'http')) + shimmer.wrap(http, 'request', httpShared.traceOutgoingRequest2(agent, 'http')) localStorage.disable() @@ -71,15 +78,32 @@ class MockAgent extends Agent { activeTrace.remove(value) }) - this.dataSender = dataSenderMock() - setDataSender(this.dataSender) - this.traceContext = new TraceContext(this.agentInfo, this.dataSender, this.config) + this.traceContext.traceSampler = new TraceSampler(this.agentInfo, config) + this.traceContext.config = config - this.closedTraces = [] + const dataSender = dataSenderMock() + this.traceContext.dataSender = dataSender + this.dataSender = dataSender + + resetTraces() + shimmer.wrap(this.traceContext, 'newTrace', function (origin) { + return function () { + const returned = origin.apply(this, arguments) + getTraces().push(returned) + return returned + } + }) + + shimmer.wrap(this.traceContext, 'continueAsyncContextTraceObject', function (origin) { + return function () { + const returned = origin.apply(this, arguments) + getTraces().push(returned) + return returned + } + }) } cleanHttp() { - cleanup() const http = require('http') shimmer.unwrap(http && http.Server && http.Server.prototype, 'emit') shimmer.unwrap(http, 'request') @@ -87,12 +111,6 @@ class MockAgent extends Agent { callbackTraceClose(callback) { const trace = this.traceContext.currentTraceObject() - const closedTrace = this.closedTraces.find((closedTrace) => trace === closedTrace) - if (closedTrace) { - callback(closedTrace) - return - } - const origin = trace.close trace.close = function () { origin.apply(trace, arguments) @@ -107,9 +125,13 @@ class MockAgent extends Agent { completeTraceObject(trace) { super.completeTraceObject(trace) - if (!trace[closedTraceWrapped]) { - this.closedTraces.push(trace) - } + // if (!trace[closedTraceWrapped]) { + // this.traces.push(trace) + // } + } + + getTraces(index) { + return getTraces()[index] } } diff --git a/test/support/data-sender-mock.js b/test/support/data-sender-mock.js index a57a9367..8150f1f7 100644 --- a/test/support/data-sender-mock.js +++ b/test/support/data-sender-mock.js @@ -24,25 +24,32 @@ class MockDataSender extends DataSender { } send(data) { - super.send(data) if (data instanceof AgentInfo) { this.mockAgentInfo = data + super.send(data) } else if (data instanceof ApiMetaInfo) { this.mockAPIMetaInfos.push(data) + super.send(data) } else if (data instanceof StringMetaInfo) { this.mockMetaInfo = data + super.send(data) } else if (data instanceof Span) { this.mockSpan = data this.mockSpans.push(data) + super.send(data) } else if (data instanceof SpanChunk) { this.mockSpanChunks.push(data) + super.send(data) } else if (data instanceof SqlMetaData) { this.mockSqlMetaData = data + super.send(data) } else if (data?.isAsyncSpanChunk?.()) { this.mockSpanChunks.push(data) + super.send(data) } else if (data?.isSpan?.()) { this.mockSpan = data this.mockSpans.push(data) + super.send(data) } } @@ -52,6 +59,12 @@ class MockDataSender extends DataSender { findSpanEvent(apiId) { return this.mockSpan.spanEventList.find(event => event.apiId === apiId) } + + clear() { + this.mockAPIMetaInfos = [] + this.mockSpanChunks = [] + this.mockSpans = [] + } } const dataSender = () => { diff --git a/test/utils/ant-path-matcher.test.js b/test/utils/ant-path-matcher.test.js index 4506bad4..7df073f7 100644 --- a/test/utils/ant-path-matcher.test.js +++ b/test/utils/ant-path-matcher.test.js @@ -224,11 +224,11 @@ async function outgoingRequest(t, path, expectedSampling, expectUnits) { app.get(OUTGOING_PATH, async (req, res) => { const headers = req.headers if (sampling) { - t.equal(actualTrace.traceId.transactionId.toString(), headers['pinpoint-traceid']) - t.equal(actualTrace.traceId.spanId, headers['pinpoint-pspanid']) + t.equal(actualTrace.spanBuilder.getTraceRoot().getTraceId().toStringDelimiterFormatted(), headers['pinpoint-traceid']) + t.equal(actualTrace.spanBuilder.getTraceRoot().getTraceId().getSpanId(), headers['pinpoint-pspanid']) t.equal(agent.config.applicationName, headers['pinpoint-pappname']) t.equal(agent.config.serviceType, Number(headers['pinpoint-papptype'])) - t.equal(actualTrace.traceId.flag, headers['pinpoint-flags']) + t.equal(actualTrace.spanBuilder.getTraceRoot().getTraceId().flags, headers['pinpoint-flags']) } else { // ClientCallStartInterceptor.java requestTraceWriter.write(metadata); // TODO: Think about for outgoing request pinpoint-sampled