From e8ace400fe30de18dfa0830980000ea4454492c8 Mon Sep 17 00:00:00 2001 From: Victor Moura Cortez Date: Mon, 8 Dec 2025 10:22:03 -0300 Subject: [PATCH 1/2] add graphql operation name to trace --- src/HttpClient/GraphQLClient.ts | 64 +++-- src/HttpClient/middlewares/tracing.ts | 99 +++++++- src/HttpClient/typings.ts | 9 +- src/HttpClient/utils/graphqlOperation.test.ts | 225 ++++++++++++++++++ src/HttpClient/utils/graphqlOperation.ts | 87 +++++++ .../metrics/instruments/hostMetrics.ts | 17 +- src/service/telemetry/client.ts | 16 +- src/service/worker/runtime/graphql/index.ts | 2 + .../graphql/middlewares/graphqlSpanTags.ts | 75 ++++++ src/tracing/Tags.ts | 8 + src/tracing/UserLandTracer.ts | 18 ++ src/tracing/index.ts | 2 +- 12 files changed, 597 insertions(+), 25 deletions(-) create mode 100644 src/HttpClient/utils/graphqlOperation.test.ts create mode 100644 src/HttpClient/utils/graphqlOperation.ts create mode 100644 src/service/worker/runtime/graphql/middlewares/graphqlSpanTags.ts diff --git a/src/HttpClient/GraphQLClient.ts b/src/HttpClient/GraphQLClient.ts index bbd9fcba0..1b9d0cd15 100644 --- a/src/HttpClient/GraphQLClient.ts +++ b/src/HttpClient/GraphQLClient.ts @@ -4,6 +4,7 @@ import CustomGraphQLError from '../errors/customGraphQLError' import { HttpClient } from './HttpClient' import { inflightUrlWithQuery } from './middlewares/inflight' import { RequestConfig } from './typings' +import { extractGraphQLOperationInfoSync, GraphQLOperationInfo } from './utils/graphqlOperation' interface QueryOptions { query: string @@ -34,6 +35,30 @@ const throwOnGraphQLErrors = (message: string, response: return response } +/** + * Enriches the request config with GraphQL operation info for tracing and logging. + * If the caller already provided a requestSpanNameSuffix, it takes precedence. + */ +const enrichConfigWithOperationInfo = ( + config: RequestConfig, + operationInfo: GraphQLOperationInfo +): RequestConfig => { + const { operationName, operationType } = operationInfo + + console.log('[GraphQL Debug] Extracted operation info:', { operationName, operationType }) + + return { + ...config, + graphqlOperationName: operationName, + graphqlOperationType: operationType, + tracing: { + ...config.tracing, + // Only set requestSpanNameSuffix if not already provided by the caller + requestSpanNameSuffix: config.tracing?.requestSpanNameSuffix ?? `${operationType}:${operationName}`, + }, + } +} + export class GraphQLClient { constructor( private http: HttpClient @@ -42,29 +67,38 @@ export class GraphQLClient { public query = ( { query, variables, inflight, extensions, throwOnError }: QueryOptions, config: RequestConfig = {} - ): Promise> => this.http.getWithBody>( - config.url || '', - { query, variables, extensions }, - { - inflightKey: inflight !== false ? inflightUrlWithQuery : undefined, - ...config, - }) - .then(graphqlResponse => throwOnError === false - ? graphqlResponse - : throwOnGraphQLErrors(this.http.name, graphqlResponse) - ) + ): Promise> => { + const operationInfo = extractGraphQLOperationInfoSync(query) + const enrichedConfig = enrichConfigWithOperationInfo(config, operationInfo) + + return this.http.getWithBody>( + enrichedConfig.url || '', + { query, variables, extensions }, + { + inflightKey: inflight !== false ? inflightUrlWithQuery : undefined, + ...enrichedConfig, + }) + .then(graphqlResponse => throwOnError === false + ? graphqlResponse + : throwOnGraphQLErrors(this.http.name, graphqlResponse) + ) + } public mutate = ( { mutate, variables, throwOnError }: MutateOptions, config: RequestConfig = {} - ) => - this.http.post>( - config.url || '', + ) => { + const operationInfo = extractGraphQLOperationInfoSync(mutate) + const enrichedConfig = enrichConfigWithOperationInfo(config, operationInfo) + + return this.http.post>( + enrichedConfig.url || '', { query: mutate, variables }, - config + enrichedConfig ) .then(graphqlResponse => throwOnError === false ? graphqlResponse : throwOnGraphQLErrors(this.http.name, graphqlResponse) ) + } } diff --git a/src/HttpClient/middlewares/tracing.ts b/src/HttpClient/middlewares/tracing.ts index c156e86a4..2eb14e523 100644 --- a/src/HttpClient/middlewares/tracing.ts +++ b/src/HttpClient/middlewares/tracing.ts @@ -1,8 +1,9 @@ import { MiddlewaresTracingContext, RequestConfig } from '..' import { IOContext } from '../../service/worker/runtime/typings' import { ErrorReport, getTraceInfo } from '../../tracing' -import { CustomHttpTags, OpentracingTags } from '../../tracing/Tags' +import { CustomHttpTags, GraphQLTags, OpentracingTags } from '../../tracing/Tags' import { MiddlewareContext } from '../typings' +import { extractGraphQLOperationInfoSync } from '../utils/graphqlOperation' import { CacheType, isLocallyCacheable } from './cache' interface HttpClientTracingMiddlewareConfig { @@ -17,6 +18,22 @@ export interface TraceableRequestConfig extends RequestConfig { tracing: MiddlewaresTracingContext } +/** + * Detects if a request is a GraphQL request by checking the request body. + * Returns the operation info if it's a GraphQL request, undefined otherwise. + */ +const detectGraphQLFromBody = (config: RequestConfig): { operationName: string; operationType: string } | undefined => { + const { data } = config + + // Check if data looks like a GraphQL request (has a 'query' field with a string value) + if (data && typeof data === 'object' && typeof data.query === 'string') { + const operationInfo = extractGraphQLOperationInfoSync(data.query) + return operationInfo + } + + return undefined +} + export const createHttpClientTracingMiddleware = ({ tracer, logger, @@ -25,8 +42,37 @@ export const createHttpClientTracingMiddleware = ({ hasDiskCacheMiddleware, }: HttpClientTracingMiddlewareConfig) => { return async function tracingMiddleware(ctx: MiddlewareContext, next: () => Promise) { + // First check if GraphQL info was explicitly set (from GraphQLClient) + let graphqlOperationName: string | undefined = ctx.config.graphqlOperationName + let graphqlOperationType: string | undefined = ctx.config.graphqlOperationType + + // If not explicitly set, try to detect from request body + if (!graphqlOperationName) { + const detectedInfo = detectGraphQLFromBody(ctx.config) + if (detectedInfo) { + graphqlOperationName = detectedInfo.operationName + graphqlOperationType = detectedInfo.operationType + } + } + + const isGraphQLRequest = !!graphqlOperationName + + console.log('[GraphQL Debug] Request:', { + url: ctx.config.url, + method: ctx.config.method || 'GET', + isGraphQLRequest, + graphqlOperationName, + graphqlOperationType, + }) + if(!tracer.isTraceSampled){ await next() + + // Log GraphQL operations even when trace is not sampled + if (isGraphQLRequest) { + logGraphQLOperation(logger, clientName, graphqlOperationName, graphqlOperationType, ctx.response?.status) + } + return } @@ -58,12 +104,31 @@ export const createHttpClientTracingMiddleware = ({ [CustomHttpTags.HTTP_CLIENT_NAME]: clientName, }) + // Add GraphQL-specific tags when this is a GraphQL request + if (isGraphQLRequest) { + span?.addTags({ + [GraphQLTags.GRAPHQL_OPERATION_NAME]: graphqlOperationName, + [GraphQLTags.GRAPHQL_OPERATION_TYPE]: graphqlOperationType, + }) + const debugInfo = { + 'graphql.operation.name': graphqlOperationName, + 'graphql.operation.type': graphqlOperationType, + } + console.log('[GraphQL Debug] Added tags to span:', debugInfo) + logger.info({ + message: '[GraphQL Debug] Added tags to span', + ...debugInfo, + }) + } + let response + let errorStatus: number | undefined try { await next() response = ctx.response } catch (err: any) { response = err.response + errorStatus = err.response?.status if(ctx.tracing?.isSampled) { ErrorReport.create({ originalError: err }).injectOnSpan(span, logger) } @@ -76,7 +141,39 @@ export const createHttpClientTracingMiddleware = ({ span?.setTag(CustomHttpTags.HTTP_NO_RESPONSE, true) } + // Log GraphQL operations + if (isGraphQLRequest) { + logGraphQLOperation(logger, clientName, graphqlOperationName, graphqlOperationType, response?.status ?? errorStatus) + } + span?.finish() } } } + +/** + * Logs GraphQL operation details for observability. + * Always logs to ensure visibility into GraphQL operations volume and errors. + */ +const logGraphQLOperation = ( + logger: IOContext['logger'], + clientName: string, + operationName: string | undefined, + operationType: string | undefined, + statusCode: number | undefined +) => { + const logData = { + message: 'GraphQL operation', + graphqlClient: clientName, + graphqlOperationName: operationName, + graphqlOperationType: operationType, + statusCode, + } + + // Log as info for successful requests, warn for errors + if (statusCode && statusCode >= 400) { + logger.warn(logData) + } else { + logger.info(logData) + } +} diff --git a/src/HttpClient/typings.ts b/src/HttpClient/typings.ts index 275452203..0f28f022d 100644 --- a/src/HttpClient/typings.ts +++ b/src/HttpClient/typings.ts @@ -21,7 +21,14 @@ export interface RequestTracingConfig { tracing?: RequestTracingUserConfig } -export interface RequestConfig extends AxiosRequestConfig, RequestTracingConfig { +export interface GraphQLOperationConfig { + /** The GraphQL operation name extracted from the query (e.g. 'GetProduct', 'CreateOrder') */ + graphqlOperationName?: string + /** The GraphQL operation type: 'query', 'mutation', or 'subscription' */ + graphqlOperationType?: 'query' | 'mutation' | 'subscription' +} + +export interface RequestConfig extends AxiosRequestConfig, RequestTracingConfig, GraphQLOperationConfig { retries?: number exponentialTimeoutCoefficient?: number initialBackoffDelay?: number diff --git a/src/HttpClient/utils/graphqlOperation.test.ts b/src/HttpClient/utils/graphqlOperation.test.ts new file mode 100644 index 000000000..69427d5d1 --- /dev/null +++ b/src/HttpClient/utils/graphqlOperation.test.ts @@ -0,0 +1,225 @@ +import { extractGraphQLOperationInfoSync } from './graphqlOperation' + +describe('extractGraphQLOperationInfoSync', () => { + describe('queries', () => { + it('should extract operation name from a named query', () => { + const query = ` + query GetProduct($id: ID!) { + product(id: $id) { + id + name + } + } + ` + + const result = extractGraphQLOperationInfoSync(query) + + expect(result.operationName).toBe('GetProduct') + expect(result.operationType).toBe('query') + }) + + it('should extract operation name from a query with shorthand syntax', () => { + const query = ` + query Translate($args: TranslateArgs!) { + translate(args: $args) + } + ` + + const result = extractGraphQLOperationInfoSync(query) + + expect(result.operationName).toBe('Translate') + expect(result.operationType).toBe('query') + }) + + it('should return unknown-operation for anonymous queries', () => { + const query = ` + { + product(id: "123") { + id + name + } + } + ` + + const result = extractGraphQLOperationInfoSync(query) + + expect(result.operationName).toBe('unknown-operation') + expect(result.operationType).toBe('query') + }) + + it('should handle query keyword without name', () => { + const query = ` + query { + products { + id + } + } + ` + + const result = extractGraphQLOperationInfoSync(query) + + expect(result.operationName).toBe('unknown-operation') + expect(result.operationType).toBe('query') + }) + }) + + describe('mutations', () => { + it('should extract operation name from a named mutation', () => { + const mutation = ` + mutation CreateOrder($input: OrderInput!) { + createOrder(input: $input) { + id + status + } + } + ` + + const result = extractGraphQLOperationInfoSync(mutation) + + expect(result.operationName).toBe('CreateOrder') + expect(result.operationType).toBe('mutation') + }) + + it('should extract operation name from SaveV2 mutation', () => { + const mutation = ` + mutation SaveV2($args: SaveArgsV2!) { + saveV2(args: $args) + } + ` + + const result = extractGraphQLOperationInfoSync(mutation) + + expect(result.operationName).toBe('SaveV2') + expect(result.operationType).toBe('mutation') + }) + + it('should return unknown-operation for anonymous mutations', () => { + const mutation = ` + mutation { + deleteProduct(id: "123") + } + ` + + const result = extractGraphQLOperationInfoSync(mutation) + + expect(result.operationName).toBe('unknown-operation') + expect(result.operationType).toBe('mutation') + }) + }) + + describe('subscriptions', () => { + it('should extract operation name from a named subscription', () => { + const subscription = ` + subscription OnOrderCreated($storeId: ID!) { + orderCreated(storeId: $storeId) { + id + status + } + } + ` + + const result = extractGraphQLOperationInfoSync(subscription) + + expect(result.operationName).toBe('OnOrderCreated') + expect(result.operationType).toBe('subscription') + }) + }) + + describe('error handling', () => { + it('should return default values for invalid GraphQL', () => { + const invalidQuery = 'this is not valid graphql' + + const result = extractGraphQLOperationInfoSync(invalidQuery) + + expect(result.operationName).toBe('unknown-operation') + expect(result.operationType).toBe('query') + }) + + it('should return default values for empty string', () => { + const result = extractGraphQLOperationInfoSync('') + + expect(result.operationName).toBe('unknown-operation') + expect(result.operationType).toBe('query') + }) + + it('should handle fragment-only documents', () => { + const fragmentOnly = ` + fragment ProductFields on Product { + id + name + } + ` + + const result = extractGraphQLOperationInfoSync(fragmentOnly) + + expect(result.operationName).toBe('unknown-operation') + expect(result.operationType).toBe('query') + }) + }) + + describe('caching', () => { + it('should return consistent results for the same query', () => { + const query = ` + query TestCaching { + test + } + ` + + const result1 = extractGraphQLOperationInfoSync(query) + const result2 = extractGraphQLOperationInfoSync(query) + + expect(result1).toEqual(result2) + expect(result1.operationName).toBe('TestCaching') + }) + }) + + describe('real-world queries from MessagesGraphQL', () => { + it('should extract Translate from messages query', () => { + const query = ` + query Translate($args: TranslateArgs!) { + translate(args: $args) + } + ` + + const result = extractGraphQLOperationInfoSync(query) + + expect(result.operationName).toBe('Translate') + expect(result.operationType).toBe('query') + }) + + it('should extract TranslateWithDeps from messages query', () => { + const query = ` + query TranslateWithDeps($args: TranslateWithDependenciesArgs!) { + translateWithDependencies(args: $args) + } + ` + + const result = extractGraphQLOperationInfoSync(query) + + expect(result.operationName).toBe('TranslateWithDeps') + expect(result.operationType).toBe('query') + }) + + it('should extract UserTranslations from messages query', () => { + const query = ` + query UserTranslations($args: IndexedMessages!){ + userTranslations(args: $args) { + srcLang + groupContext + context + translations { + lang + translation + } + } + } + ` + + const result = extractGraphQLOperationInfoSync(query) + + expect(result.operationName).toBe('UserTranslations') + expect(result.operationType).toBe('query') + }) + }) +}) + diff --git a/src/HttpClient/utils/graphqlOperation.ts b/src/HttpClient/utils/graphqlOperation.ts new file mode 100644 index 000000000..35d798640 --- /dev/null +++ b/src/HttpClient/utils/graphqlOperation.ts @@ -0,0 +1,87 @@ +import { DocumentNode, OperationDefinitionNode, parse as gqlParse } from 'graphql' + +import { LRUCache } from '../../caches/LRUCache' + +export interface GraphQLOperationInfo { + operationName: string + operationType: 'query' | 'mutation' | 'subscription' +} + +const UNKNOWN_OPERATION = 'unknown-operation' +const DEFAULT_OPERATION_INFO: GraphQLOperationInfo = { + operationName: UNKNOWN_OPERATION, + operationType: 'query', +} + +/** + * LRU cache for parsed GraphQL operation info. + * Using the query string as key to avoid re-parsing the same query. + */ +const operationInfoCache = new LRUCache({ + max: 500, +}) + +/** + * Extracts operation name and type from a GraphQL query string. + * Results are cached to avoid re-parsing the same query. + * + * @param query - The GraphQL query string + * @returns The operation info with name and type + */ +export const extractGraphQLOperationInfo = async (query: string): Promise => { + const cached = await operationInfoCache.getOrSet(query, async () => ({ + value: parseGraphQLOperationInfo(query), + })) + + return cached ?? DEFAULT_OPERATION_INFO +} + +/** + * Synchronous version of extractGraphQLOperationInfo. + * Checks cache first, parses if not found. + * + * @param query - The GraphQL query string + * @returns The operation info with name and type + */ +export const extractGraphQLOperationInfoSync = (query: string): GraphQLOperationInfo => { + const cached = operationInfoCache.get(query) + if (cached) { + return cached + } + + const info = parseGraphQLOperationInfo(query) + // Set in cache (sync operation) + operationInfoCache.set(query, info) + return info +} + +/** + * Parses a GraphQL query string and extracts operation info. + * + * @param query - The GraphQL query string + * @returns The operation info with name and type + */ +const parseGraphQLOperationInfo = (query: string): GraphQLOperationInfo => { + try { + const document: DocumentNode = gqlParse(query) + + const operationDefinition = document.definitions.find( + (def): def is OperationDefinitionNode => def.kind === 'OperationDefinition' + ) + + if (!operationDefinition) { + return DEFAULT_OPERATION_INFO + } + + const operationType = operationDefinition.operation as GraphQLOperationInfo['operationType'] + const operationName = operationDefinition.name?.value ?? UNKNOWN_OPERATION + + return { + operationName, + operationType, + } + } catch { + // If parsing fails, return default info + return DEFAULT_OPERATION_INFO + } +} diff --git a/src/service/metrics/instruments/hostMetrics.ts b/src/service/metrics/instruments/hostMetrics.ts index 0851c1096..6d744a038 100644 --- a/src/service/metrics/instruments/hostMetrics.ts +++ b/src/service/metrics/instruments/hostMetrics.ts @@ -1,6 +1,14 @@ import { InstrumentationBase, InstrumentationConfig } from "@opentelemetry/instrumentation"; import { MeterProvider } from '@opentelemetry/api'; -import { HostMetrics } from "@opentelemetry/host-metrics"; + +// Optional dependency - may not be available in all environments +let HostMetrics: any; +try { + // eslint-disable-next-line @typescript-eslint/no-require-imports + HostMetrics = require("@opentelemetry/host-metrics").HostMetrics; +} catch { + // Module not available - will be handled in enable() +} interface HostMetricsInstrumentationConfig extends InstrumentationConfig { name?: string; @@ -8,7 +16,7 @@ interface HostMetricsInstrumentationConfig extends InstrumentationConfig { } export class HostMetricsInstrumentation extends InstrumentationBase { - private hostMetrics?: HostMetrics; + private hostMetrics?: any; constructor(config: HostMetricsInstrumentationConfig = {}) { const instrumentation_name = config.name || 'host-metrics-instrumentation'; @@ -19,6 +27,11 @@ export class HostMetricsInstrumentation extends InstrumentationBase(clientsConfig, pipeline, serviceRoute, routeId, globalLimiter) diff --git a/src/service/worker/runtime/graphql/middlewares/graphqlSpanTags.ts b/src/service/worker/runtime/graphql/middlewares/graphqlSpanTags.ts new file mode 100644 index 000000000..b0f54f23f --- /dev/null +++ b/src/service/worker/runtime/graphql/middlewares/graphqlSpanTags.ts @@ -0,0 +1,75 @@ +import { OperationDefinitionNode } from 'graphql' +import { GraphQLTags } from '../../../../../tracing/Tags' +import { GraphQLServiceContext } from '../typings' + +/** + * Middleware that adds GraphQL operation info to the current span. + * Must run AFTER extractQuery middleware which parses the query. + * + * Note: ctx.tracing is set to undefined by traceUserLandRemainingPipelineMiddleware, + * so we use ctx.vtex.tracer to access the span instead. + */ +export const graphqlSpanTags = () => + async function addGraphQLSpanTags(ctx: GraphQLServiceContext, next: () => Promise) { + const { graphql, vtex } = ctx + const query = graphql?.query + const tracer = vtex?.tracer + + // Debug: Log what we have available + console.log('[GraphQL Debug] graphqlSpanTags middleware:', { + hasQuery: !!query, + hasQueryDocument: !!query?.document, + hasTracer: !!tracer, + isTraceSampled: tracer?.isTraceSampled, + queryOperationName: query?.operationName, + }) + + // Get operation name - either from explicit operationName field or from the parsed document + let operationName = query?.operationName + let operationType: string | undefined + + if (query?.document) { + const operationDefinition = query.document.definitions.find( + (def): def is OperationDefinitionNode => def.kind === 'OperationDefinition' + ) + + if (operationDefinition) { + operationType = operationDefinition.operation + // If operationName wasn't explicitly provided, get it from the document + if (!operationName && operationDefinition.name?.value) { + operationName = operationDefinition.name.value + } + } + } + + console.log('[GraphQL Debug] Extracted operation info:', { + operationName, + operationType, + }) + + // Add tags to the span via tracer (ctx.tracing is undefined at this point) + if (tracer?.isTraceSampled) { + if (operationName) { + tracer.setFallbackSpanTag(GraphQLTags.GRAPHQL_OPERATION_NAME, operationName) + console.log('[GraphQL Debug] Set tag graphql.operation.name =', operationName) + } + if (operationType) { + tracer.setFallbackSpanTag(GraphQLTags.GRAPHQL_OPERATION_TYPE, operationType) + console.log('[GraphQL Debug] Set tag graphql.operation.type =', operationType) + } + + // Update span operation name to include the GraphQL operation + if (operationName) { + const currentOpName = ctx.requestHandlerName || 'graphql-handler:__graphql' + const newOpName = `${currentOpName}:${operationName}` + tracer.setFallbackSpanOperationName(newOpName) + ctx.requestHandlerName = newOpName + console.log('[GraphQL Debug] Updated span name to:', newOpName) + } + } else { + console.log('[GraphQL Debug] Tracing not sampled, skipping tags') + } + + await next() + } + diff --git a/src/tracing/Tags.ts b/src/tracing/Tags.ts index 35b606399..f6f1dd038 100644 --- a/src/tracing/Tags.ts +++ b/src/tracing/Tags.ts @@ -74,6 +74,14 @@ export const enum CustomHttpTags { HTTP_RETRY_COUNT = 'http.retry.count', } +export const enum GraphQLTags { + /** The GraphQL operation name extracted from the query (e.g. 'GetProduct', 'CreateOrder') */ + GRAPHQL_OPERATION_NAME = 'graphql.operation.name', + + /** The GraphQL operation type: 'query', 'mutation', or 'subscription' */ + GRAPHQL_OPERATION_TYPE = 'graphql.operation.type', +} + export const UserlandTags = { ...OpentracingTags, } diff --git a/src/tracing/UserLandTracer.ts b/src/tracing/UserLandTracer.ts index 4f8454656..e9d2a94f0 100644 --- a/src/tracing/UserLandTracer.ts +++ b/src/tracing/UserLandTracer.ts @@ -8,6 +8,8 @@ export interface IUserLandTracer { startSpan: Tracer['startSpan'] inject: Tracer['inject'] fallbackSpanContext: () => SpanContext | undefined + setFallbackSpanTag: (key: string, value: any) => void + setFallbackSpanOperationName: (name: string) => void } export const createTracingContextFromCarrier = ( @@ -81,4 +83,20 @@ export class UserLandTracer implements IUserLandTracer { public fallbackSpanContext(): SpanContext | undefined { return this.fallbackSpan?.context() } + + /** + * Sets a tag on the fallback span (the main request span). + * This allows middlewares to add tags to the request span. + */ + public setFallbackSpanTag(key: string, value: any): void { + this.fallbackSpan?.setTag(key, value) + } + + /** + * Updates the operation name of the fallback span. + * This allows middlewares to add context to the span name. + */ + public setFallbackSpanOperationName(name: string): void { + this.fallbackSpan?.setOperationName(name) + } } 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 } From 3832fa0bccb5dfc464869734d0d68c77e296e9ec Mon Sep 17 00:00:00 2001 From: Victor Moura Cortez Date: Mon, 8 Dec 2025 14:30:42 -0300 Subject: [PATCH 2/2] remove console.log statements --- src/HttpClient/GraphQLClient.ts | 2 -- src/HttpClient/middlewares/tracing.ts | 16 ++-------------- .../graphql/middlewares/graphqlSpanTags.ts | 19 ------------------- 3 files changed, 2 insertions(+), 35 deletions(-) diff --git a/src/HttpClient/GraphQLClient.ts b/src/HttpClient/GraphQLClient.ts index 1b9d0cd15..a61624a63 100644 --- a/src/HttpClient/GraphQLClient.ts +++ b/src/HttpClient/GraphQLClient.ts @@ -45,8 +45,6 @@ const enrichConfigWithOperationInfo = ( ): RequestConfig => { const { operationName, operationType } = operationInfo - console.log('[GraphQL Debug] Extracted operation info:', { operationName, operationType }) - return { ...config, graphqlOperationName: operationName, diff --git a/src/HttpClient/middlewares/tracing.ts b/src/HttpClient/middlewares/tracing.ts index 2eb14e523..c7c5af7cf 100644 --- a/src/HttpClient/middlewares/tracing.ts +++ b/src/HttpClient/middlewares/tracing.ts @@ -57,14 +57,6 @@ export const createHttpClientTracingMiddleware = ({ const isGraphQLRequest = !!graphqlOperationName - console.log('[GraphQL Debug] Request:', { - url: ctx.config.url, - method: ctx.config.method || 'GET', - isGraphQLRequest, - graphqlOperationName, - graphqlOperationType, - }) - if(!tracer.isTraceSampled){ await next() @@ -110,14 +102,10 @@ export const createHttpClientTracingMiddleware = ({ [GraphQLTags.GRAPHQL_OPERATION_NAME]: graphqlOperationName, [GraphQLTags.GRAPHQL_OPERATION_TYPE]: graphqlOperationType, }) - const debugInfo = { - 'graphql.operation.name': graphqlOperationName, - 'graphql.operation.type': graphqlOperationType, - } - console.log('[GraphQL Debug] Added tags to span:', debugInfo) logger.info({ message: '[GraphQL Debug] Added tags to span', - ...debugInfo, + 'graphql.operation.name': graphqlOperationName, + 'graphql.operation.type': graphqlOperationType, }) } diff --git a/src/service/worker/runtime/graphql/middlewares/graphqlSpanTags.ts b/src/service/worker/runtime/graphql/middlewares/graphqlSpanTags.ts index b0f54f23f..654e3ac34 100644 --- a/src/service/worker/runtime/graphql/middlewares/graphqlSpanTags.ts +++ b/src/service/worker/runtime/graphql/middlewares/graphqlSpanTags.ts @@ -15,15 +15,6 @@ export const graphqlSpanTags = () => const query = graphql?.query const tracer = vtex?.tracer - // Debug: Log what we have available - console.log('[GraphQL Debug] graphqlSpanTags middleware:', { - hasQuery: !!query, - hasQueryDocument: !!query?.document, - hasTracer: !!tracer, - isTraceSampled: tracer?.isTraceSampled, - queryOperationName: query?.operationName, - }) - // Get operation name - either from explicit operationName field or from the parsed document let operationName = query?.operationName let operationType: string | undefined @@ -42,20 +33,13 @@ export const graphqlSpanTags = () => } } - console.log('[GraphQL Debug] Extracted operation info:', { - operationName, - operationType, - }) - // Add tags to the span via tracer (ctx.tracing is undefined at this point) if (tracer?.isTraceSampled) { if (operationName) { tracer.setFallbackSpanTag(GraphQLTags.GRAPHQL_OPERATION_NAME, operationName) - console.log('[GraphQL Debug] Set tag graphql.operation.name =', operationName) } if (operationType) { tracer.setFallbackSpanTag(GraphQLTags.GRAPHQL_OPERATION_TYPE, operationType) - console.log('[GraphQL Debug] Set tag graphql.operation.type =', operationType) } // Update span operation name to include the GraphQL operation @@ -64,10 +48,7 @@ export const graphqlSpanTags = () => const newOpName = `${currentOpName}:${operationName}` tracer.setFallbackSpanOperationName(newOpName) ctx.requestHandlerName = newOpName - console.log('[GraphQL Debug] Updated span name to:', newOpName) } - } else { - console.log('[GraphQL Debug] Tracing not sampled, skipping tags') } await next()