Access function args in @Span decorator
First of all ,thanks for the great library! Its been a joy to work with so far
One pattern that I have noticed myself duplicating almost everywhere is this
@Span('DocumentsService.create')
async create(userId: string, orgId: string, dto: CreateDocumentDto) {
this.traceService.getSpan().setAttributes({
orgId,
userId,
dto: JSON.stringify(dto),
});
// --- snip
Where I annotate a function with Span, and then immediately set the function args into the span attributes.
Question
Is it possible with reflect-metadata to roll that code into @Span , maybe something like this
@Span('DocumentsService.create', ['userId', 'orgId', 'dto'])
Where users have to explicitly set the fields they want to attach to attributes
I am used to this in rust, but I'm not sure if the TS compiler is capable of something like that
Hey! this is a reasonable ask, PRs are welcome but it will be quite hard if you want to customize the attribute names. You might need to think about a more customizable interface
This issue was marked stale. It will be closed in 30 days without additional activity.
Typescript/Javascript cannot reflect function parameter names, so we can only really use the order of the params
I am proposing this API:
@Span(
'DocumentsService.create',
(_, userId, orgId, dto) => ({ attributes: { userId, orgId, dto: JSON.stringify(dto) } })
)
async create(ignored: string, userId: string, orgId: string, dto: CreateDocumentDto) {
// business logic
}
It extends the original one by allowing the second parameter to be SpanOptions, or (...args) => SpanOptions
This allows us to implement any extension in the userland:
const SpanWithAttrs(name: string, attrs: Record<string, number>) =>
Span(name, (...args) => ({
attributes: Object.fromEntries(
Object.entries(attrs).map(([key, index]) => [key, args[index]])
)
}))
@SpanWithAttrs('DocumentsService.create', { userId: 1, orgId: 2, dto: 3 })
async create(ignored: string, userId: string, orgId: string, dto: CreateDocumentDto) {
// business logic
}
Or possibly:
const SpanWithAttrs(name: string, attrs: Array<string | null> =>
Span(name, (...args) => ({
attributes: Object.fromEntries(
attrs.map(key, index) => key && [key, args[index]]).filter(Boolean)
)
}))
@SpanWithAttrs('DocumentsService.create', [null, 'userId', 'orgId', 'dto' })
async create(ignored: string, userId: string, orgId: string, dto: CreateDocumentDto) {
// business logic
}
Which is pretty close to the original proposal.