Skip to content

Commit

Permalink
[#258] ActiveTrace with TransactionId
Browse files Browse the repository at this point in the history
  • Loading branch information
feelform committed Feb 4, 2025
1 parent 16c7e29 commit cf42f1c
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 33 deletions.
5 changes: 1 addition & 4 deletions lib/client/grpc-data-sender.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,10 @@ class GrpcDataSender {
this.agentInfoDailyScheduler = new Scheduler(this.agentInfoRefreshInterval())
}

initializeProfilerClients(collectorIp, collectorTcpPort, config) {
initializeProfilerClients(collectorIp, collectorTcpPort) {
const profilerBuilder = new OptionsBuilder()
.addInterceptor(makeAgentInformationMetadataInterceptor(this.agentInfo))

if (config && config.grpcServiceConfig && typeof config.grpcServiceConfig.getProfiler === 'function') {
profilerBuilder.setGrpcServiceConfig(config.grpcServiceConfig.getProfiler())
}
this.profilerClient = new services.ProfilerCommandServiceClient(collectorIp + ":" + collectorTcpPort, grpc.credentials.createInsecure(), profilerBuilder.build())
}

Expand Down
7 changes: 5 additions & 2 deletions lib/context/trace-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const log = require('../utils/logger')
const sampler = require('../sampler/sampler')
const DisableTrace = require('./disable-trace')
const localStorage = require('../instrumentation/context/local-storage')
const activeRequestRepository = require('./trace/active-request-repository')
const TraceSampler = require('./trace/trace-sampler')
const SpanBuilder = require('./span-builder')
const SpanChunkBuilder = require('./span-chunk-builder')
Expand All @@ -24,6 +23,7 @@ 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')
const ActiveTraceRepository = require('../metric/active-trace-repository')

class TraceContext {
constructor(agentInfo, dataSender, config) {
Expand All @@ -35,6 +35,7 @@ class TraceContext {
this.enableSampling = config.sampling
}
this.traceSampler = new TraceSampler(agentInfo, config)
this.activeRequestRepository = new ActiveTraceRepository()
}

getAgentInfo() {
Expand Down Expand Up @@ -82,6 +83,7 @@ class TraceContext {
}
try {
trace.close()
this.activeRequestRepository.remove(trace.getTraceRoot())
// activeTrace.remove(trace)
} catch (e) {
log.error('Fail to complete trace object', e)
Expand Down Expand Up @@ -116,7 +118,7 @@ class TraceContext {
}

newLocalTrace(traceRoot) {
activeRequestRepository.registry(traceRoot)
this.activeRequestRepository.register(traceRoot)
return new DisableTrace(traceRoot)
}

Expand All @@ -135,6 +137,7 @@ class TraceContext {
const spanBuilder = new SpanBuilder(traceRoot)
const spanChunkBuilder = new SpanChunkBuilder(traceRoot)
const repository = new SpanRepository(spanChunkBuilder, this.dataSender, this.agentInfo)
this.activeRequestRepository.register(traceRoot)
return new Trace2(spanBuilder, repository)
}

Expand Down
23 changes: 0 additions & 23 deletions lib/context/trace/active-request-repository.js

This file was deleted.

1 change: 0 additions & 1 deletion lib/context/trace/child-trace-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

'use strict'

const SpanEventRecorder = require('./span-event-recorder2')
const TraceRootSpanRecorder = require('./trace-root-span-recorder')
const StackId = require('./stack-id')
const CallStack = require('./call-stack')
Expand Down
32 changes: 32 additions & 0 deletions lib/metric/active-trace-repository.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Pinpoint Node.js Agent
* Copyright 2020-present NAVER Corp.
* Apache License v2.0
*/

'use strict'

const SimpleCache = require('../utils/simple-cache')

// DefaultActiveTraceRepository.java
class ActiveTraceRepository {
constructor() {
this.activeTraceCache = new SimpleCache()
}

register(localTraceRoot) {
const id = localTraceRoot.getTransactionId()
if (typeof id !== 'string' || id.length < 1) {
return
}

this.activeTraceCache.put(id, localTraceRoot)
}

remove(localTraceRoot) {
const id = localTraceRoot.getTransactionId()
this.activeTraceCache.delete(id)
}
}

module.exports = ActiveTraceRepository
48 changes: 45 additions & 3 deletions test/stats/active-trace.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const activeTrace = require('../../lib/metric/active-trace')
const agent = require('../support/agent-singleton-mock')
const express = require('express')
const http = require('http')
const grpc = require('@grpc/grpc-js')
const services = require('../../lib/data/v1/Service_grpc_pb')
const spanMessages = require('../../lib/data/v1/Span_pb')

const TEST_ENV = {
host: 'localhost',
Expand All @@ -37,9 +40,9 @@ test(`Should record active trace in multiple call`, function (t) {

const server = app.listen(TEST_ENV.port, async function () {
Promise.all([
axios.get(getServerUrl(PATH), { httpAgent: new http.Agent({ keepAlive: false })}),
axios.get(getServerUrl(PATH), { httpAgent: new http.Agent({ keepAlive: false })}),
axios.get(getServerUrl(LASTONE_PATH), { httpAgent: new http.Agent({ keepAlive: false })}),
axios.get(getServerUrl(PATH), { httpAgent: new http.Agent({ keepAlive: false }) }),
axios.get(getServerUrl(PATH), { httpAgent: new http.Agent({ keepAlive: false }) }),
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")
Expand All @@ -54,4 +57,43 @@ test(`Should record active trace in multiple call`, function (t) {

t.equal(agent.mockAgentId, fixture.config.agentId, "Agent ID equals")
t.equal(agent.agentInfo, agent.pinpointClient.agentInfo, "AgentInfo equals")
})

test(`Active trace should be recorded with HTTP call`, function (t) {
const collectorServer = new grpc.Server()
collectorServer.addService(services.MetadataService, {
requestApiMetaData: (call, callback) => {
const result = new spanMessages.PResult()
callback(null, result)
}
})
collectorServer.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (err, port) => {
agent.bindHttpWithCallSite(port)

const app = new express()
app.get('/active-trace', async (req, res) => {
agent.callbackTraceClose((trace) => {
const actualCached = agent.getTraceContext().activeRequestRepository.activeTraceCache.get(trace.getTraceRoot().getTransactionId())
t.equal(actualCached, trace.getTraceRoot(), 'active trace traceRoot is cached')
})
setTimeout(() => {
res.send('ok get')
}, 1000)
})

const server = app.listen(TEST_ENV.port, async () => {
const result = await axios.get(getServerUrl('/active-trace'), { httpAgent: new http.Agent({ keepAlive: false }) })
t.equal(result.status, 200, 'status code is 200')
server.close(() => {
const cacheSize = agent.getTraceContext().activeRequestRepository.activeTraceCache.cache.size
t.equal(cacheSize, 0, 'active trace cache is empty')
t.end()
})
})
})
t.teardown(() => {
collectorServer.tryShutdown(() => {

})
})
})
1 change: 1 addition & 0 deletions test/support/agent-singleton-mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class MockAgent extends Agent {
if (sampler.getSamplingCountGenerator()) {
sampler.getSamplingCountGenerator().reset()
}
this.traceContext.activeRequestRepository.activeTraceCache.cache.clear()
transactionIdGenerator.reset()

httpShared.clearPathMatcher()
Expand Down

0 comments on commit cf42f1c

Please sign in to comment.