Skip to content

Commit ba26cc6

Browse files
committed
feat(otel): add properties of DecoratorTraceData for TraceLog()
- before/after callback of TraceLog() support return traceContext to update traceContext and span - endParentSpan to end current and parent span
1 parent fa00c3b commit ba26cc6

File tree

6 files changed

+110
-28
lines changed

6 files changed

+110
-28
lines changed

packages/otel/src/lib/decorator.helper.async.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ import type {
99
DecoratorTraceDataResp,
1010
TraceDecoratorOptions,
1111
} from './trace.service/index.trace.service.js'
12-
import { isSpanEnded } from './util.js'
12+
import { getSpan, isSpanEnded } from './util.js'
1313

1414
// #region processDecoratorBeforeAfterAsync
1515

16+
/**
17+
* @description options.{traceContext|span} may be modified with `traceContext` returned by `before()` or `after()`
18+
*/
1619
export async function processDecoratorBeforeAfterAsync(
1720
type: 'before' | 'after' | 'afterThrow',
1821
options: DecoratorExecutorParam<TraceDecoratorOptions>,
@@ -59,17 +62,24 @@ export async function processDecoratorBeforeAfterAsync(
5962
data = await func2(options.methodArgs, options.error, decoratorContext)
6063
}
6164

62-
if (data) {
65+
if (data && Object.keys(data).length) {
6366
const eventName = type
6467
if (data.events && ! data.events['event']) {
6568
data.events['event'] = eventName
6669
}
6770

71+
if (data.traceContext) {
72+
options.traceContext = data.traceContext
73+
options.span = getSpan(options.traceContext)
74+
}
75+
assert(options.span, `processDecoratorBeforeAfterAsync(): span is required with new traceContext returned by "${type}()"`)
76+
6877
assert(options.traceScope, 'processDecoratorBeforeAfterAsync(): traceScope is required')
69-
processDecoratorSpanData(options.traceScope, traceService, span, data)
78+
processDecoratorSpanData(options.traceScope, traceService, options.span, data)
79+
return data
7080
}
7181

72-
return data
82+
return null
7383
}
7484
}
7585

packages/otel/src/lib/decorator.helper.sync.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type {
1111
TraceDecoratorOptions,
1212
} from './trace.service/index.trace.service.js'
1313
import { AttrNames } from './types.js'
14-
import { isSpanEnded } from './util.js'
14+
import { getSpan, isSpanEnded } from './util.js'
1515

1616

1717
// #region processDecoratorBeforeAfterSync
@@ -62,7 +62,7 @@ export function processDecoratorBeforeAfterSync(
6262
data = func2(options.methodArgs, options.error, decoratorContext)
6363
}
6464

65-
if (data) {
65+
if (data && Object.keys(data).length) {
6666
if (isPromise(data)) {
6767
const err = new Error(`processDecoratorBeforeAfterSync() decorator ${type}() return value is a promise,
6868
class: ${options.callerAttr[AttrNames.CallerClass]}, method: ${options.callerAttr[AttrNames.CallerMethod]}`)
@@ -75,11 +75,18 @@ export function processDecoratorBeforeAfterSync(
7575
data.events['event'] = eventName
7676
}
7777

78+
if (data.traceContext) {
79+
options.traceContext = data.traceContext
80+
options.span = getSpan(options.traceContext)
81+
}
82+
assert(options.span, `processDecoratorBeforeAfterSync(): span is required with new traceContext returned by "${type}()"`)
83+
7884
assert(options.traceScope, 'processDecoratorBeforeAfterSync(): traceScope is required')
79-
processDecoratorSpanData(options.traceScope, traceService, span, data)
85+
processDecoratorSpanData(options.traceScope, traceService, options.span, data)
86+
return data
8087
}
8188

82-
return data
89+
return null
8390
}
8491

8592
}

packages/otel/src/lib/decorator.trace-log/trace-log.helper.async.ts

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import assert from 'node:assert'
22

33
import { processDecoratorBeforeAfterAsync } from '../decorator.helper.async.js'
44
import { genTraceScopeFrom } from '../decorator.helper.base.js'
5+
import { endTraceSpan } from '../trace.helper.js'
56
import type { DecoratorExecutorParam, DecoratorTraceDataResp } from '../trace.service/index.trace.service.js'
67
import { ConfigKey } from '../types.js'
78

@@ -16,16 +17,29 @@ export async function beforeAsync(options: DecoratorExecutorParam): Promise<void
1617
}
1718

1819
if (! options.span) {
19-
options.span = traceService.getActiveSpan(options.traceScope)
20+
const info = traceService.getActiveTraceInfo(options.traceScope)
21+
if (info) {
22+
options.span = info.span
23+
options.traceContext = info.traceContext
24+
}
2025
}
26+
2127
const res: DecoratorTraceDataResp = await processDecoratorBeforeAfterAsync(type, options)
2228
if (res?.endSpanAfterTraceLog) {
2329
assert(options.span, 'span is required')
24-
if (res.spanStatusOptions) {
25-
traceService.endSpan({ span: options.span, spanStatusOptions: res.spanStatusOptions })
30+
endTraceSpan(traceService, options.span, res.spanStatusOptions)
31+
}
32+
33+
if (res?.endParentSpan) {
34+
assert(options.span, 'span is required')
35+
36+
if (! res.endSpanAfterTraceLog) {
37+
endTraceSpan(traceService, options.span, res.spanStatusOptions)
2638
}
27-
else {
28-
traceService.endSpan({ span: options.span })
39+
40+
const parentSpan = traceService.retrieveParentTraceInfoBySpan(options.span, options.traceScope)?.span
41+
if (parentSpan) {
42+
endTraceSpan(traceService, parentSpan, res.spanStatusOptions)
2943
}
3044
}
3145
}
@@ -42,13 +56,20 @@ export async function afterReturnAsync(options: DecoratorExecutorParam): Promise
4256

4357
const res: DecoratorTraceDataResp = await processDecoratorBeforeAfterAsync('after', options)
4458
if (res?.endSpanAfterTraceLog) {
45-
if (res.spanStatusOptions) {
46-
traceService.endSpan({ span, spanStatusOptions: res.spanStatusOptions })
59+
endTraceSpan(traceService, span, res.spanStatusOptions)
60+
}
61+
62+
if (res?.endParentSpan) {
63+
if (! res.endSpanAfterTraceLog) {
64+
endTraceSpan(traceService, span, res.spanStatusOptions)
4765
}
48-
else {
49-
traceService.endSpan({ span })
66+
67+
const parentSpan = traceService.retrieveParentTraceInfoBySpan(span, options.traceScope)?.span
68+
if (parentSpan) {
69+
endTraceSpan(traceService, parentSpan, res.spanStatusOptions)
5070
}
5171
}
72+
5273
return options.methodResult
5374
}
5475

packages/otel/src/lib/decorator.trace-log/trace-log.helper.sync.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ConfigKey } from '@mwcp/share'
55

66
import { genTraceScopeFrom } from '../decorator.helper.base.js'
77
import { processDecoratorBeforeAfterSync } from '../decorator.helper.sync.js'
8+
import { endTraceSpan } from '../trace.helper.js'
89
import type { DecoratorExecutorParam, DecoratorTraceDataResp } from '../trace.service/index.trace.service.js'
910
import { AttrNames } from '../types.js'
1011

@@ -27,16 +28,29 @@ export function beforeSync(options: DecoratorExecutorParam): void {
2728
}
2829

2930
if (! options.span) {
30-
options.span = traceService.getActiveSpan(options.traceScope)
31+
const info = traceService.getActiveTraceInfo(options.traceScope)
32+
if (info) {
33+
options.span = info.span
34+
options.traceContext = info.traceContext
35+
}
3136
}
37+
3238
const res: DecoratorTraceDataResp = processDecoratorBeforeAfterSync(type, options)
3339
if (res?.endSpanAfterTraceLog) {
3440
assert(options.span, 'span is required')
35-
if (res.spanStatusOptions) {
36-
traceService.endSpan({ span: options.span, spanStatusOptions: res.spanStatusOptions })
41+
endTraceSpan(traceService, options.span, res.spanStatusOptions)
42+
}
43+
44+
if (res?.endParentSpan) {
45+
assert(options.span, 'span is required')
46+
47+
if (! res.endSpanAfterTraceLog) {
48+
endTraceSpan(traceService, options.span, res.spanStatusOptions)
3749
}
38-
else {
39-
traceService.endSpan({ span: options.span })
50+
51+
const parentSpan = traceService.retrieveParentTraceInfoBySpan(options.span, options.traceScope)?.span
52+
if (parentSpan) {
53+
endTraceSpan(traceService, parentSpan, res.spanStatusOptions)
4054
}
4155
}
4256
}
@@ -54,14 +68,19 @@ export function afterReturnSync(options: DecoratorExecutorParam): unknown {
5468

5569
const res: DecoratorTraceDataResp = processDecoratorBeforeAfterSync('after', options)
5670
if (res?.endSpanAfterTraceLog) {
57-
if (res.spanStatusOptions) {
58-
traceService.endSpan({ span, spanStatusOptions: res.spanStatusOptions })
71+
endTraceSpan(traceService, span, res.spanStatusOptions)
72+
}
73+
74+
if (res?.endParentSpan) {
75+
if (! res.endSpanAfterTraceLog) {
76+
endTraceSpan(traceService, span, res.spanStatusOptions)
5977
}
60-
else {
61-
traceService.endSpan({ span })
78+
79+
const parentSpan = traceService.retrieveParentTraceInfoBySpan(span, options.traceScope)?.span
80+
if (parentSpan) {
81+
endTraceSpan(traceService, parentSpan, res.spanStatusOptions)
6282
}
6383
}
64-
6584
return options.methodResult
6685
}
6786

packages/otel/src/lib/trace.helper.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ import assert from 'node:assert'
44
import type { DecoratorExecutorParamBase } from '@mwcp/share'
55
import { isArrowFunction } from '@waiting/shared-core'
66

7+
import type { Span, SpanStatusOptions } from '##/index.js'
8+
79
import type {
810
DecoratorContext,
911
DecoratorExecutorParam,
1012
GenDecoratorExecutorOptions,
1113
KeyGenerator,
1214
TraceDecoratorOptions,
1315
} from './trace.service/index.trace.service.js'
16+
import type { TraceServiceSpan } from './trace.service/trace.service.span.js'
1417
import { AttrNames, ConfigKey } from './types.js'
1518

1619

@@ -213,3 +216,13 @@ export function genDecoratorExecutorOptions(
213216

214217
return ret
215218
}
219+
220+
221+
export function endTraceSpan(traceService: TraceServiceSpan, span: Span, spanStatusOptions: SpanStatusOptions | undefined): void {
222+
if (spanStatusOptions) {
223+
traceService.endSpan({ span, spanStatusOptions })
224+
}
225+
else {
226+
traceService.endSpan({ span })
227+
}
228+
}

packages/otel/src/lib/trace.service/trace.service.types.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,27 @@ export interface DecoratorTraceData {
3737
rootEvents?: Attributes
3838

3939
/**
40-
* End then span after method `before()` or `after()` called
40+
* End the span after method `before()` or `after()` called
4141
* used by TraceLog decorator, ignored by TraceInit/Trace decorator
42+
* @description Current span also will be ended if endParentSpan:true, regardless of this value
4243
* @default false
4344
*/
4445
endSpanAfterTraceLog?: boolean
46+
/**
47+
* End the parent span after method `before()` or `after()` called
48+
* used by TraceLog decorator, ignored by TraceInit/Trace decorator
49+
* @description Current span also will be ended if endParentSpan:true, regardless of endSpanAfterTraceLog
50+
* @default false
51+
*/
52+
endParentSpan?: boolean
4553
/**
4654
* Used by TraceLog decorator and endSpanAfterTraceLog:true, ignored by TraceInit/Trace decorator
4755
*/
4856
spanStatusOptions?: SpanStatusOptions
57+
/**
58+
* options.traceContext will be overwritten by this value, and options.span also will be updated
59+
*/
60+
traceContext?: TraceContext
4961
}
5062
export type DecoratorTraceDataResp = DecoratorTraceData | undefined | null
5163
export type DecoratorTraceDataRespAsync = Promise<DecoratorTraceData | undefined | null>

0 commit comments

Comments
 (0)