diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b1424a45..73c885c80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +## [7.5.0] - 2026-07-28 +### Added +- Add a generic `IUserLandTracer.setFallbackSpanTag` API and exported GraphQL operation tag constants. + ## [7.4.0] - 2026-06-22 ### Changed - Renamed the base `IOClients` Janus Catalog getter from `catalogSystem` to diff --git a/package.json b/package.json index 829761a1e..1542f2b45 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vtex/api", - "version": "7.4.0", + "version": "7.5.0", "description": "VTEX I/O API client", "main": "lib/index.js", "typings": "lib/index.d.ts", diff --git a/src/HttpClient/middlewares/request/setupAxios/__tests__/TestTracer.ts b/src/HttpClient/middlewares/request/setupAxios/__tests__/TestTracer.ts index dbf79fa5e..3c951dc23 100644 --- a/src/HttpClient/middlewares/request/setupAxios/__tests__/TestTracer.ts +++ b/src/HttpClient/middlewares/request/setupAxios/__tests__/TestTracer.ts @@ -30,4 +30,8 @@ export class TestTracer implements IUserLandTracer { public fallbackSpanContext() { return this.fallbackSpan.context() } + + public setFallbackSpanTag(key: string, value: unknown): void { + this.fallbackSpan.setTag(key, value) + } } diff --git a/src/tracing/Tags.ts b/src/tracing/Tags.ts index 35b606399..4d392ea13 100644 --- a/src/tracing/Tags.ts +++ b/src/tracing/Tags.ts @@ -74,6 +74,11 @@ export const enum CustomHttpTags { HTTP_RETRY_COUNT = 'http.retry.count', } +export const enum GraphQLTags { + GRAPHQL_OPERATION_NAME = 'graphql.operation.name', + GRAPHQL_OPERATION_TYPE = 'graphql.operation.type', +} + export const UserlandTags = { ...OpentracingTags, } diff --git a/src/tracing/UserLandTracer.test.ts b/src/tracing/UserLandTracer.test.ts new file mode 100644 index 000000000..e04f2c61f --- /dev/null +++ b/src/tracing/UserLandTracer.test.ts @@ -0,0 +1,63 @@ +import { MockSpan, MockTracer } from '@tiagonapoli/opentracing-alternate-mock' + +import { GraphQLTags } from './Tags' +import { UserLandTracer } from './UserLandTracer' + +describe('UserLandTracer.setFallbackSpanTag', () => { + test('writes a tag only to the fallback span', () => { + const tracer = new MockTracer() + const fallback = tracer.startSpan('incoming-request') as MockSpan + const userLandTracer = new UserLandTracer(tracer, fallback) + + userLandTracer.setFallbackSpanTag( + GraphQLTags.GRAPHQL_OPERATION_NAME, + 'GetProduct' + ) + const child = userLandTracer.startSpan('child') as MockSpan + + expect(fallback.tags()).toHaveProperty( + [GraphQLTags.GRAPHQL_OPERATION_NAME], + 'GetProduct' + ) + expect(child.tags()).not.toHaveProperty( + [GraphQLTags.GRAPHQL_OPERATION_NAME] + ) + }) + + test('is a no-op when there is no fallback span', () => { + const userLandTracer = new UserLandTracer(new MockTracer()) + + expect(() => { + userLandTracer.setFallbackSpanTag( + GraphQLTags.GRAPHQL_OPERATION_TYPE, + 'query' + ) + }).not.toThrow() + }) + + test('can write after the fallback span is locked', () => { + const tracer = new MockTracer() + const fallback = tracer.startSpan('incoming-request') as MockSpan + const replacement = tracer.startSpan('replacement') as MockSpan + const userLandTracer = new UserLandTracer(tracer, fallback) + + userLandTracer.lockFallbackSpan() + + expect(() => userLandTracer.setFallbackSpan(replacement)).toThrow( + "FallbackSpan is locked, can't change it" + ) + expect(() => { + userLandTracer.setFallbackSpanTag( + GraphQLTags.GRAPHQL_OPERATION_TYPE, + 'query' + ) + }).not.toThrow() + expect(fallback.tags()).toHaveProperty( + [GraphQLTags.GRAPHQL_OPERATION_TYPE], + 'query' + ) + expect(replacement.tags()).not.toHaveProperty( + [GraphQLTags.GRAPHQL_OPERATION_TYPE] + ) + }) +}) diff --git a/src/tracing/UserLandTracer.ts b/src/tracing/UserLandTracer.ts index 4f8454656..b2cdef6f1 100644 --- a/src/tracing/UserLandTracer.ts +++ b/src/tracing/UserLandTracer.ts @@ -8,6 +8,7 @@ export interface IUserLandTracer { startSpan: Tracer['startSpan'] inject: Tracer['inject'] fallbackSpanContext: () => SpanContext | undefined + setFallbackSpanTag: (key: string, value: unknown) => void } export const createTracingContextFromCarrier = ( @@ -81,4 +82,8 @@ export class UserLandTracer implements IUserLandTracer { public fallbackSpanContext(): SpanContext | undefined { return this.fallbackSpan?.context() } + + public setFallbackSpanTag(key: string, value: unknown): void { + this.fallbackSpan?.setTag(key, value) + } } diff --git a/src/tracing/index.ts b/src/tracing/index.ts index f3ab23e62..903800779 100644 --- a/src/tracing/index.ts +++ b/src/tracing/index.ts @@ -4,7 +4,7 @@ export { ErrorKindsBase as ErrorKinds } from '@vtex/node-error-report' export { ErrorReport } from './errorReporting/ErrorReport' export { createSpanReference } from './spanReference/createSpanReference' export { SpanReferenceTypes } from './spanReference/SpanReferenceTypes' -export { UserlandTags as TracingTags } from './Tags' +export { UserlandTags as TracingTags, GraphQLTags } from './Tags' export { createTracingContextFromCarrier, IUserLandTracer } from './UserLandTracer' export { getTraceInfo, TraceInfo } from './utils' export { Span, FORMAT_HTTP_HEADERS }