From 7546806e82c7090b41083f30763bdb51c4d95c7e Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Mon, 28 Apr 2025 18:04:29 -0300 Subject: [PATCH 01/16] Add diagnostics-semconv to standardize some attributes and headers --- package.json | 1 + src/HttpClient/HttpClient.ts | 33 +++---- src/HttpClient/middlewares/cache.ts | 10 +-- .../interceptors/tracing/spanSetup.ts | 7 +- src/clients/janus/Segment.ts | 5 +- src/constants.ts | 88 +++++++++++++------ src/service/logger/logger.ts | 15 ++-- src/service/tracing/tracingMiddlewares.ts | 10 +-- .../worker/runtime/builtIn/middlewares.ts | 5 +- .../runtime/events/middlewares/context.ts | 13 ++- src/service/worker/runtime/events/router.ts | 4 +- .../runtime/graphql/middlewares/response.ts | 25 ++---- .../graphql/middlewares/updateSchema.ts | 10 +-- .../runtime/http/middlewares/authTokens.ts | 1 - .../runtime/http/middlewares/context.ts | 9 +- .../worker/runtime/http/middlewares/vary.ts | 30 +++---- src/service/worker/runtime/http/router.ts | 5 +- src/service/worker/runtime/utils/context.ts | 44 ++++------ src/service/worker/runtime/utils/recorder.ts | 5 +- 19 files changed, 154 insertions(+), 166 deletions(-) diff --git a/package.json b/package.json index 1ef535ea4..3757777f2 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@types/koa": "^2.11.0", "@types/koa-compose": "^3.2.3", "@vtex/diagnostics-nodejs": "0.1.0-beta.8", + "@vtex/diagnostics-semconv": "0.1.0-beta.8", "@vtex/node-error-report": "^0.0.3", "@wry/equality": "^0.1.9", "agentkeepalive": "^4.0.2", diff --git a/src/HttpClient/HttpClient.ts b/src/HttpClient/HttpClient.ts index fd4399826..6e5d19b45 100644 --- a/src/HttpClient/HttpClient.ts +++ b/src/HttpClient/HttpClient.ts @@ -3,16 +3,9 @@ import { createHash } from 'crypto' import { IncomingMessage } from 'http' import compose from 'koa-compose' import pLimit from 'p-limit' - import { - BINDING_HEADER, + HeaderKeys, BODY_HASH, - FORWARDED_HOST_HEADER, - LOCALE_HEADER, - PRODUCT_HEADER, - SEGMENT_HEADER, - SESSION_HEADER, - TENANT_HEADER, } from '../constants' import { Logger } from '../service/logger' import { IOContext } from '../service/worker/runtime/typings' @@ -89,14 +82,14 @@ export class HttpClient { ...defaultHeaders, 'Accept-Encoding': 'gzip', 'User-Agent': userAgent, - ...host ? { [FORWARDED_HOST_HEADER]: host } : null, - ...tenant ? { [TENANT_HEADER]: formatTenantHeaderValue(tenant) } : null, - ...binding ? { [BINDING_HEADER]: formatBindingHeaderValue(binding) } : null, - ...locale ? { [LOCALE_HEADER]: locale } : null, - ...operationId ? { 'x-vtex-operation-id': operationId } : null, - ...product ? { [PRODUCT_HEADER]: product } : null, - ...segmentToken ? { [SEGMENT_HEADER]: segmentToken } : null, - ...sessionToken ? { [SESSION_HEADER]: sessionToken } : null, + ...host ? { [HeaderKeys.FORWARDED_HOST]: host } : null, + ...tenant ? { [HeaderKeys.TENANT]: formatTenantHeaderValue(tenant) } : null, + ...binding ? { [HeaderKeys.BINDING]: formatBindingHeaderValue(binding) } : null, + ...locale ? { [HeaderKeys.LOCALE]: locale } : null, + ...operationId ? { [HeaderKeys.OPERATION_ID]: operationId } : null, + ...product ? { [HeaderKeys.PRODUCT]: product } : null, + ...segmentToken ? { [HeaderKeys.SEGMENT]: segmentToken } : null, + ...sessionToken ? { [HeaderKeys.SESSION]: sessionToken } : null, } if (authType && authToken) { @@ -139,16 +132,16 @@ export class HttpClient { return typeof v !== 'object' || v === null || Array.isArray(v) ? v : Object.fromEntries(Object.entries(v).sort(([ka], [kb]) => ka < kb ? -1 : ka > kb ? 1 : 0)) - } - catch(error) { + } + catch(error) { // I don't believe this will ever happen, but just in case // Also, I didn't include error as I am unsure if it would have sensitive information this.logger.warn({message: 'Error while sorting object for cache key'}) return v } } - - + + const bodyHash = createHash('md5').update(JSON.stringify(data, deterministicReplacer)).digest('hex') const cacheableConfig = this.getConfig(url, { ...config, diff --git a/src/HttpClient/middlewares/cache.ts b/src/HttpClient/middlewares/cache.ts index 8134d15b5..673831b54 100644 --- a/src/HttpClient/middlewares/cache.ts +++ b/src/HttpClient/middlewares/cache.ts @@ -2,7 +2,7 @@ import { AxiosRequestConfig, AxiosResponse } from 'axios' import { Span } from 'opentracing' import { CacheLayer } from '../../caches/CacheLayer' -import { LOCALE_HEADER, SEGMENT_HEADER, SESSION_HEADER } from '../../constants' +import { HeaderKeys } from '../../constants' import { IOContext } from '../../service/worker/runtime/typings' import { ErrorReport } from '../../tracing' import { HttpLogEvents } from '../../tracing/LogEvents' @@ -15,7 +15,7 @@ const cacheableStatusCodes = [200, 203, 204, 206, 300, 301, 404, 405, 410, 414, export const cacheKey = (config: AxiosRequestConfig) => { const {baseURL = '', url = '', params, headers} = config - const locale = headers?.[LOCALE_HEADER] + const locale = headers?.[HeaderKeys.LOCALE] const encodedBaseURL = baseURL.replace(/\//g, '\\') const encodedURL = url.replace(/\//g, '\\') @@ -97,7 +97,7 @@ export const cacheMiddleware = ({ type, storage, asyncSet }: CacheOptions) => { const { rootSpan: span, tracer, logger } = ctx.tracing ?? {} const key = cacheKey(ctx.config) - const segmentToken = ctx.config.headers?.[SEGMENT_HEADER] + const segmentToken = ctx.config.headers?.[HeaderKeys.SEGMENT] const keyWithSegment = key + segmentToken span?.log({ @@ -204,11 +204,11 @@ export const cacheMiddleware = ({ type, storage, asyncSet }: CacheOptions) => { } const shouldCache = maxAge || etag - const varySession = ctx.response.headers.vary && ctx.response.headers.vary.includes(SESSION_HEADER) + const varySession = ctx.response.headers.vary && ctx.response.headers.vary.includes(HeaderKeys.SESSION) if (shouldCache && !varySession) { const {responseType, responseEncoding: configResponseEncoding} = ctx.config const currentAge = revalidated ? 0 : age - const varySegment = ctx.response.headers.vary && ctx.response.headers.vary.includes(SEGMENT_HEADER) + const varySegment = ctx.response.headers.vary && ctx.response.headers.vary.includes(HeaderKeys.SEGMENT) const setKey = varySegment ? keyWithSegment : key const responseEncoding = configResponseEncoding || (responseType === 'arraybuffer' ? 'base64' : undefined) const cacheableData = type === CacheType.Disk && responseType === 'arraybuffer' diff --git a/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/spanSetup.ts b/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/spanSetup.ts index d9ead2892..fc1996602 100644 --- a/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/spanSetup.ts +++ b/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/spanSetup.ts @@ -1,7 +1,7 @@ import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios' import buildFullPath from '../../../../../../utils/buildFullPath' import { Span } from 'opentracing' -import { ROUTER_CACHE_HEADER } from '../../../../../../constants' +import { HeaderKeys } from '../../../../../../constants' import { CustomHttpTags, OpentracingTags } from '../../../../../../tracing/Tags' import { cloneAndSanitizeHeaders } from '../../../../../../tracing/utils' @@ -24,7 +24,8 @@ export const injectResponseInfoOnSpan = (span: Span | undefined, response: Axios span?.log({ 'response-headers': cloneAndSanitizeHeaders(response.headers) }) span?.setTag(OpentracingTags.HTTP_STATUS_CODE, response.status) - if (response.headers[ROUTER_CACHE_HEADER]) { - span?.setTag(CustomHttpTags.HTTP_ROUTER_CACHE_RESULT, response.headers[ROUTER_CACHE_HEADER]) + + if (response.headers[HeaderKeys.ROUTER_CACHE]) { + span?.setTag(CustomHttpTags.HTTP_ROUTER_CACHE_RESULT, response.headers[HeaderKeys.ROUTER_CACHE]) } } diff --git a/src/clients/janus/Segment.ts b/src/clients/janus/Segment.ts index 62f8a6126..6b27b4594 100644 --- a/src/clients/janus/Segment.ts +++ b/src/clients/janus/Segment.ts @@ -1,7 +1,6 @@ import parseCookie from 'cookie' import { prop } from 'ramda' - -import { PRODUCT_HEADER } from '../../constants' +import { HeaderKeys } from '../../constants' import { inflightUrlWithQuery, RequestTracingConfig } from '../../HttpClient' import { JanusClient } from './JanusClient' @@ -87,7 +86,7 @@ export class Segment extends JanusClient { forceMaxAge: SEGMENT_MAX_AGE_S, headers: { 'Content-Type': 'application/json', - [PRODUCT_HEADER]: product || '', + [HeaderKeys.PRODUCT]: product || '', }, inflightKey: inflightUrlWithQuery, metric, diff --git a/src/constants.ts b/src/constants.ts index 3860b0af3..8e8e473a9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,4 +1,13 @@ import { versionToMajor } from './utils/app' +import { + ATTR_VTEX_OPERATION_ID, + ATTR_VTEX_ACCOUNT_NAME, + ATTR_VTEX_IO_WORKSPACE_NAME, + ATTR_VTEX_IO_WORKSPACE_TYPE, + ATTR_VTEX_IO_APP_ID, + ATTR_VTEX_IO_APP_AUTHOR_TYPE +} from '@vtex/diagnostics-semconv' + // tslint:disable-next-line const pkg = require('../package.json') @@ -7,36 +16,57 @@ export const DEFAULT_WORKSPACE = 'master' export const IS_IO = process.env.VTEX_IO export const PID = process.pid -export const CACHE_CONTROL_HEADER = 'cache-control' -export const SEGMENT_HEADER = 'x-vtex-segment' -export const SESSION_HEADER = 'x-vtex-session' -export const PRODUCT_HEADER = 'x-vtex-product' -export const LOCALE_HEADER = 'x-vtex-locale' -export const FORWARDED_HOST_HEADER = 'x-forwarded-host' -export const TENANT_HEADER = 'x-vtex-tenant' -export const BINDING_HEADER = 'x-vtex-binding' -export const META_HEADER = 'x-vtex-meta' -export const META_HEADER_BUCKET = 'x-vtex-meta-bucket' -export const ETAG_HEADER = 'etag' -export const ACCOUNT_HEADER = 'x-vtex-account' -export const CREDENTIAL_HEADER = 'x-vtex-credential' -export const REQUEST_ID_HEADER = 'x-request-id' -export const ROUTER_CACHE_HEADER = 'x-router-cache' -export const OPERATION_ID_HEADER = 'x-vtex-operation-id' -export const PLATFORM_HEADER = 'x-vtex-platform' -export const WORKSPACE_IS_PRODUCTION_HEADER = 'x-vtex-workspace-is-production' -export const WORKSPACE_HEADER = 'x-vtex-workspace' -export const EVENT_KEY_HEADER = 'x-event-key' -export const EVENT_SENDER_HEADER = 'x-event-sender' -export const EVENT_SUBJECT_HEADER = 'x-event-subject' -export const EVENT_HANDLER_ID_HEADER = 'x-event-handler-id' -export const COLOSSUS_ROUTE_DECLARER_HEADER = 'x-colossus-route-declarer' -export const COLOSSUS_ROUTE_ID_HEADER = 'x-colossus-route-id' -export const COLOSSUS_PARAMS_HEADER = 'x-colossus-params' -export const TRACE_ID_HEADER = 'x-trace-id' -export const PROVIDER_HEADER = 'x-vtex-provider' +export const HeaderKeys = { + CACHE_CONTROL: 'cache-control', + SEGMENT: 'x-vtex-segment', + SESSION: 'x-vtex-session', + PRODUCT: 'x-vtex-product', + LOCALE: 'x-vtex-locale', + FORWARDED_HOST: 'x-forwarded-host', + FORWARDED_FOR: 'x-forwarded-for', + TENANT: 'x-vtex-tenant', + BINDING: 'x-vtex-binding', + META: 'x-vtex-meta', + META_BUCKET: 'x-vtex-meta-bucket', + ETAG: 'etag', + ACCOUNT: 'x-vtex-account', + CREDENTIAL: 'x-vtex-credential', + REQUEST_ID: 'x-request-id', + ROUTER_CACHE: 'x-router-cache', + OPERATION_ID: 'x-vtex-operation-id', + PLATFORM: 'x-vtex-platform', + WORKSPACE_IS_PRODUCTION: 'x-vtex-workspace-is-production', + WORKSPACE: 'x-vtex-workspace', + EVENT_KEY: 'x-event-key', + EVENT_SENDER: 'x-event-sender', + EVENT_SUBJECT: 'x-event-subject', + EVENT_HANDLER_ID: 'x-event-handler-id', + COLOSSUS_ROUTE_DECLARER: 'x-colossus-route-declarer', + COLOSSUS_ROUTE_ID: 'x-colossus-route-id', + COLOSSUS_PARAMS: 'x-colossus-params', + TRACE_ID: 'x-trace-id', + PROVIDER: 'x-vtex-provider', + USER_AGENT: 'user-agent', + VTEX_USER_AGENT: 'x-vtex-user-agent', + VTEX_IO_CALLER: 'x-vtex-io-caller', + VTEX_APP_SERVICE: 'x-vtex-app-service', + VTEX_APP_KEY: 'x-vtex-app-key', + VTEX_RETRY_COUNT: 'x-vtex-retry-count' +} + +export const AttributeKeys = { + // VTEX Semantic Attributes + VTEX_OPERATION_ID: ATTR_VTEX_OPERATION_ID, + VTEX_ACCOUNT_NAME: ATTR_VTEX_ACCOUNT_NAME, + + // VTEX IO Semantic Attributes + VTEX_IO_WORKSPACE_NAME: ATTR_VTEX_IO_WORKSPACE_NAME, + VTEX_IO_WORKSPACE_TYPE: ATTR_VTEX_IO_WORKSPACE_TYPE, + VTEX_IO_APP_ID: ATTR_VTEX_IO_APP_ID, + VTEX_IO_APP_AUTHOR_TYPE: ATTR_VTEX_IO_APP_AUTHOR_TYPE, +} -export type VaryHeaders = typeof SEGMENT_HEADER | typeof SESSION_HEADER | typeof PRODUCT_HEADER | typeof LOCALE_HEADER +export type VaryHeaders = typeof HeaderKeys.SEGMENT | typeof HeaderKeys.SESSION | typeof HeaderKeys.PRODUCT | typeof HeaderKeys.LOCALE export const BODY_HASH = '__graphqlBodyHash' diff --git a/src/service/logger/logger.ts b/src/service/logger/logger.ts index 7946b9109..18f4d3e26 100644 --- a/src/service/logger/logger.ts +++ b/src/service/logger/logger.ts @@ -1,4 +1,4 @@ -import { APP, LOG_CLIENT_INIT_TIMEOUT_MS } from '../../constants' +import { APP, LOG_CLIENT_INIT_TIMEOUT_MS, AttributeKeys } from '../../constants' import { cleanError } from '../../utils/error' import { cleanLog } from '../../utils/log' import { LogClient } from '@vtex/diagnostics-nodejs/dist/types'; @@ -82,13 +82,14 @@ export class Logger { const inflatedLog = { __VTEX_IO_LOG: true, level, - app, - account: this.account, - workspace: this.workspace, - production: this.production, - data, - operationId: this.operationId, + [AttributeKeys.VTEX_IO_APP_ID]: app, + [AttributeKeys.VTEX_ACCOUNT_NAME]: this.account, + [AttributeKeys.VTEX_IO_WORKSPACE_NAME]: this.workspace, + [AttributeKeys.VTEX_IO_WORKSPACE_TYPE]: this.production ? 'production' : 'development', + [AttributeKeys.VTEX_IO_APP_AUTHOR_TYPE]: APP.IS_THIRD_PARTY() ? '3p' : '1p', + [AttributeKeys.VTEX_OPERATION_ID]: this.operationId, requestId: this.requestId, + data, ... (this.tracingState?.isTraceSampled ? { traceId: this.tracingState.traceId } : null), } diff --git a/src/service/tracing/tracingMiddlewares.ts b/src/service/tracing/tracingMiddlewares.ts index 0e3941397..945042b8a 100644 --- a/src/service/tracing/tracingMiddlewares.ts +++ b/src/service/tracing/tracingMiddlewares.ts @@ -1,6 +1,6 @@ import { FORMAT_HTTP_HEADERS, SpanContext, Tracer } from 'opentracing' import { finished as onStreamFinished } from 'stream' -import { ACCOUNT_HEADER, REQUEST_ID_HEADER, TRACE_ID_HEADER, WORKSPACE_HEADER } from '../../constants' +import { HeaderKeys } from '../../constants' import { ErrorReport, getTraceInfo } from '../../tracing' import { RuntimeLogEvents } from '../../tracing/LogEvents' import { RuntimeLogFields } from '../../tracing/LogFields' @@ -52,14 +52,14 @@ export const addTracingMiddleware = (tracer: Tracer) => { [OpentracingTags.HTTP_METHOD]: ctx.request.method, [OpentracingTags.HTTP_STATUS_CODE]: ctx.response.status, [CustomHttpTags.HTTP_PATH]: ctx.request.path, - [VTEXIncomingRequestTags.VTEX_REQUEST_ID]: ctx.get(REQUEST_ID_HEADER), - [VTEXIncomingRequestTags.VTEX_WORKSPACE]: ctx.get(WORKSPACE_HEADER), - [VTEXIncomingRequestTags.VTEX_ACCOUNT]: ctx.get(ACCOUNT_HEADER), + [VTEXIncomingRequestTags.VTEX_REQUEST_ID]: ctx.get(HeaderKeys.REQUEST_ID), + [VTEXIncomingRequestTags.VTEX_WORKSPACE]: ctx.get(HeaderKeys.WORKSPACE), + [VTEXIncomingRequestTags.VTEX_ACCOUNT]: ctx.get(HeaderKeys.ACCOUNT), }) currentSpan?.log(cloneAndSanitizeHeaders(ctx.request.headers, 'req.headers.')) currentSpan?.log(cloneAndSanitizeHeaders(ctx.response.headers, 'res.headers.')) - ctx.set(TRACE_ID_HEADER, traceInfo.traceId!) + ctx.set(HeaderKeys.TRACE_ID, traceInfo.traceId!) } const onResFinished = () => { diff --git a/src/service/worker/runtime/builtIn/middlewares.ts b/src/service/worker/runtime/builtIn/middlewares.ts index a9ce9b055..6c0561a54 100644 --- a/src/service/worker/runtime/builtIn/middlewares.ts +++ b/src/service/worker/runtime/builtIn/middlewares.ts @@ -1,6 +1,5 @@ import { collectDefaultMetrics, register } from 'prom-client' -import { COLOSSUS_ROUTE_ID_HEADER } from '../../../../constants' - +import { HeaderKeys } from '../../../../constants' import { MetricsLogger } from '../../../logger/metricsLogger' import { EventLoopLagMeasurer } from '../../../tracing/metrics/measurers/EventLoopLagMeasurer' import { ServiceContext } from '../typings' @@ -32,7 +31,7 @@ export const prometheusLoggerMiddleware = () => { return next() } - const routeId = ctx.get(COLOSSUS_ROUTE_ID_HEADER) + const routeId = ctx.get(HeaderKeys.COLOSSUS_ROUTE_ID) if (routeId) { return next() } diff --git a/src/service/worker/runtime/events/middlewares/context.ts b/src/service/worker/runtime/events/middlewares/context.ts index 773373c29..0b3d44f7f 100644 --- a/src/service/worker/runtime/events/middlewares/context.ts +++ b/src/service/worker/runtime/events/middlewares/context.ts @@ -1,9 +1,6 @@ import { IOClients } from '../../../../../clients/IOClients' import { - EVENT_HANDLER_ID_HEADER, - EVENT_KEY_HEADER, - EVENT_SENDER_HEADER, - EVENT_SUBJECT_HEADER, + HeaderKeys, } from '../../../../../constants' import { ParamsContext, RecorderState, ServiceContext } from '../../typings' import { prepareHandlerCtx } from '../../utils/context' @@ -13,12 +10,12 @@ export async function eventContextMiddleware | null) => { return async (ctx: ServiceContext, next: () => Promise) => { - const handlerId = ctx.get(EVENT_HANDLER_ID_HEADER) + const handlerId = ctx.get(HeaderKeys.EVENT_HANDLER_ID) if (!handlerId || !events) { return next() diff --git a/src/service/worker/runtime/graphql/middlewares/response.ts b/src/service/worker/runtime/graphql/middlewares/response.ts index cdfbad6b8..bd903994d 100644 --- a/src/service/worker/runtime/graphql/middlewares/response.ts +++ b/src/service/worker/runtime/graphql/middlewares/response.ts @@ -1,10 +1,5 @@ import { - CACHE_CONTROL_HEADER, - ETAG_HEADER, - FORWARDED_HOST_HEADER, - META_HEADER, - SEGMENT_HEADER, - SESSION_HEADER, + HeaderKeys, } from '../../../../../constants' import { Maybe } from '../../typings' import { Recorder } from '../../utils/recorder' @@ -12,14 +7,13 @@ import { GraphQLCacheControl, GraphQLServiceContext } from '../typings' import { cacheControlHTTP } from '../utils/cacheControl' function setVaryHeaders (ctx: GraphQLServiceContext, cacheControl: GraphQLCacheControl) { - ctx.vary(FORWARDED_HOST_HEADER) + ctx.vary(HeaderKeys.FORWARDED_HOST) if (cacheControl.scope === 'segment') { - ctx.vary(SEGMENT_HEADER) + ctx.vary(HeaderKeys.SEGMENT) } - if (cacheControl.scope === 'private' || ctx.query.scope === 'private') { - ctx.vary(SEGMENT_HEADER) - ctx.vary(SESSION_HEADER) + ctx.vary(HeaderKeys.SEGMENT) + ctx.vary(HeaderKeys.SESSION) } else if (ctx.vtex.sessionToken) { ctx.vtex.logger.warn({ message: 'GraphQL resolver receiving session token without private scope', @@ -29,9 +23,7 @@ function setVaryHeaders (ctx: GraphQLServiceContext, cacheControl: GraphQLCacheC } export async function response (ctx: GraphQLServiceContext, next: () => Promise) { - await next() - const { cacheControl, status, @@ -39,13 +31,12 @@ export async function response (ctx: GraphQLServiceContext, next: () => Promise< } = ctx.graphql const cacheControlHeader = cacheControlHTTP(ctx) - - ctx.set(CACHE_CONTROL_HEADER, cacheControlHeader) + ctx.set(HeaderKeys.CACHE_CONTROL, cacheControlHeader) if (status === 'error') { // Do not generate etag for errors - ctx.remove(META_HEADER) - ctx.remove(ETAG_HEADER) + ctx.remove(HeaderKeys.META) + ctx.remove(HeaderKeys.ETAG) ctx.vtex.recorder?.clear() } diff --git a/src/service/worker/runtime/graphql/middlewares/updateSchema.ts b/src/service/worker/runtime/graphql/middlewares/updateSchema.ts index 42c92cbde..5efd44b76 100644 --- a/src/service/worker/runtime/graphql/middlewares/updateSchema.ts +++ b/src/service/worker/runtime/graphql/middlewares/updateSchema.ts @@ -1,5 +1,5 @@ import { IOClients } from '../../../../../clients' -import { PROVIDER_HEADER } from '../../../../../constants' +import { HeaderKeys } from '../../../../../constants' import { majorEqualAndGreaterThan, parseAppId } from '../../../../../utils' import { GraphQLOptions, ParamsContext, RecorderState } from '../../typings' import { makeSchema } from '../schema/index' @@ -17,7 +17,7 @@ export const updateSchema = ) => { return async (ctx: ServiceContext, next: () => Promise) => { - const routeId = ctx.get(COLOSSUS_ROUTE_ID_HEADER) - + const routeId = ctx.get(HeaderKeys.COLOSSUS_ROUTE_ID) if (!routeId) { return next() } diff --git a/src/service/worker/runtime/utils/context.ts b/src/service/worker/runtime/utils/context.ts index c1e66c5f9..e4b64d4bb 100644 --- a/src/service/worker/runtime/utils/context.ts +++ b/src/service/worker/runtime/utils/context.ts @@ -1,22 +1,8 @@ import { Context } from 'koa' import uuid from 'uuid/v4' - import { - ACCOUNT_HEADER, - BINDING_HEADER, - CREDENTIAL_HEADER, - FORWARDED_HOST_HEADER, - LOCALE_HEADER, - OPERATION_ID_HEADER, - PLATFORM_HEADER, - PRODUCT_HEADER, + HeaderKeys, REGION, - REQUEST_ID_HEADER, - SEGMENT_HEADER, - SESSION_HEADER, - TENANT_HEADER, - WORKSPACE_HEADER, - WORKSPACE_IS_PRODUCTION_HEADER, } from '../../../../constants' import { UserLandTracer } from '../../../../tracing/UserLandTracer' import { parseTenantHeaderValue } from '../../../../utils/tenant' @@ -32,23 +18,23 @@ const getPlatform = (account: string): string => { export const prepareHandlerCtx = (header: Context['request']['header'], tracingContext?: TracingContext): HandlerContext => { const partialContext = { - account: header[ACCOUNT_HEADER], - authToken: header[CREDENTIAL_HEADER], - binding: header[BINDING_HEADER] ? parseBindingHeaderValue(header[BINDING_HEADER]) : undefined, - host: header[FORWARDED_HOST_HEADER], - locale: header[LOCALE_HEADER], - operationId: header[OPERATION_ID_HEADER] || uuid(), - platform: header[PLATFORM_HEADER] || getPlatform(header[ACCOUNT_HEADER]), - product: header[PRODUCT_HEADER], - production: header[WORKSPACE_IS_PRODUCTION_HEADER]?.toLowerCase() === 'true' || false, + account: header[HeaderKeys.ACCOUNT], + authToken: header[HeaderKeys.CREDENTIAL], + binding: header[HeaderKeys.BINDING] ? parseBindingHeaderValue(header[HeaderKeys.BINDING]) : undefined, + host: header[HeaderKeys.FORWARDED_HOST], + locale: header[HeaderKeys.LOCALE], + operationId: header[HeaderKeys.OPERATION_ID] || uuid(), + platform: header[HeaderKeys.PLATFORM] || getPlatform(header[HeaderKeys.ACCOUNT]), + product: header[HeaderKeys.PRODUCT], + production: header[HeaderKeys.WORKSPACE_IS_PRODUCTION]?.toLowerCase() === 'true' || false, region: REGION, - requestId: header[REQUEST_ID_HEADER], - segmentToken: header[SEGMENT_HEADER], - sessionToken: header[SESSION_HEADER], - tenant: header[TENANT_HEADER] ? parseTenantHeaderValue(header[TENANT_HEADER]) : undefined, + requestId: header[HeaderKeys.REQUEST_ID], + segmentToken: header[HeaderKeys.SEGMENT], + sessionToken: header[HeaderKeys.SESSION], + tenant: header[HeaderKeys.TENANT] ? parseTenantHeaderValue(header[HeaderKeys.TENANT]) : undefined, tracer: new UserLandTracer(tracingContext?.tracer!, tracingContext?.currentSpan), userAgent: process.env.VTEX_APP_ID || '', - workspace: header[WORKSPACE_HEADER], + workspace: header[HeaderKeys.WORKSPACE], } return { diff --git a/src/service/worker/runtime/utils/recorder.ts b/src/service/worker/runtime/utils/recorder.ts index ce5900e20..83be426aa 100644 --- a/src/service/worker/runtime/utils/recorder.ts +++ b/src/service/worker/runtime/utils/recorder.ts @@ -1,9 +1,8 @@ import { Context } from 'koa' import { trim } from 'ramda' +import { HeaderKeys } from './../../../../constants' -import { META_HEADER, META_HEADER_BUCKET } from './../../../../constants' - -const HEADERS = [META_HEADER, META_HEADER_BUCKET] +const HEADERS = [HeaderKeys.META, HeaderKeys.META_BUCKET] export class Recorder { // tslint:disable-next-line: variable-name From f682d97096c5408affa872e85f40b8bd079f2d02 Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Tue, 17 Jun 2025 14:37:34 -0300 Subject: [PATCH 02/16] Remove resolutions from package.json --- package.json | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/package.json b/package.json index 3757777f2..6ff83f2d8 100644 --- a/package.json +++ b/package.json @@ -125,26 +125,5 @@ "typemoq": "^2.1.0", "typescript": "^4.4.4", "typescript-json-schema": "^0.52.0" - }, - "resolutions": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/exporter-metrics-otlp-grpc": "0.57.2", - "@opentelemetry/exporter-metrics-otlp-http": "0.57.2", - "@opentelemetry/exporter-logs-otlp-grpc": "0.57.2", - "@opentelemetry/exporter-logs-otlp-http": "0.57.2", - "@opentelemetry/exporter-trace-otlp-grpc": "0.57.2", - "@opentelemetry/exporter-trace-otlp-http": "0.57.2", - "@opentelemetry/instrumentation": "0.57.2", - "@opentelemetry/instrumentation-http": "0.57.2", - "@opentelemetry/instrumentation-grpc": "0.57.2", - "@opentelemetry/instrumentation-net": "0.43.1", - "@opentelemetry/propagator-b3": "1.30.1", - "@opentelemetry/resource-detector-aws": "1.12.0", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-node": "0.57.2", - "@opentelemetry/sdk-logs": "0.57.2", - "@opentelemetry/sdk-metrics": "1.30.1", - "@opentelemetry/sdk-trace-base": "1.30.1", - "@opentelemetry/sdk-trace-node": "1.30.1" } } From a3d5264d9339abc9035e3187c4bf7d2067b85471 Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Tue, 17 Jun 2025 14:38:17 -0300 Subject: [PATCH 03/16] Update @vtex/diagnostics-nodejs to 0.1.0-beta.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6ff83f2d8..0c92d3548 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "dependencies": { "@types/koa": "^2.11.0", "@types/koa-compose": "^3.2.3", - "@vtex/diagnostics-nodejs": "0.1.0-beta.8", + "@vtex/diagnostics-nodejs": "0.1.0-beta.10", "@vtex/diagnostics-semconv": "0.1.0-beta.8", "@vtex/node-error-report": "^0.0.3", "@wry/equality": "^0.1.9", From a1a06863d397232a6c0cf05583c3dea0935a638f Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Tue, 17 Jun 2025 14:38:52 -0300 Subject: [PATCH 04/16] Update @vtex/diagnostics-semconv to 0.1.0-beta.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0c92d3548..ee2a4ac07 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "@types/koa": "^2.11.0", "@types/koa-compose": "^3.2.3", "@vtex/diagnostics-nodejs": "0.1.0-beta.10", - "@vtex/diagnostics-semconv": "0.1.0-beta.8", + "@vtex/diagnostics-semconv": "0.1.0-beta.10", "@vtex/node-error-report": "^0.0.3", "@wry/equality": "^0.1.9", "agentkeepalive": "^4.0.2", From 2bc84df3d8b3bf5302562b45a7f0965a848f2bf3 Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Tue, 17 Jun 2025 18:13:27 -0300 Subject: [PATCH 05/16] Update yarn.lock --- yarn.lock | 96 +++++++++++++++++++++++++------------------------------ 1 file changed, 44 insertions(+), 52 deletions(-) diff --git a/yarn.lock b/yarn.lock index 6a8dc6e83..fd49540e1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-1.30.1.tgz#4f76280691a742597fd0bf682982126857622948" integrity sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA== -"@opentelemetry/core@1.30.1", "@opentelemetry/core@^1.0.0", "@opentelemetry/core@^2.0.0": +"@opentelemetry/core@1.30.1", "@opentelemetry/core@^1.0.0", "@opentelemetry/core@^1.30.1": version "1.30.1" resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.30.1.tgz#a0b468bb396358df801881709ea38299fc30ab27" integrity sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ== dependencies: "@opentelemetry/semantic-conventions" "1.28.0" -"@opentelemetry/exporter-logs-otlp-grpc@0.57.2", "@opentelemetry/exporter-logs-otlp-grpc@^0.200.0": +"@opentelemetry/exporter-logs-otlp-grpc@0.57.2", "@opentelemetry/exporter-logs-otlp-grpc@^0.57.2": version "0.57.2" resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.57.2.tgz#674b634ef284ef8caa058662518205a7134d536a" integrity sha512-eovEy10n3umjKJl2Ey6TLzikPE+W4cUQ4gCwgGP1RqzTGtgDra0WjIqdy29ohiUKfvmbiL3MndZww58xfIvyFw== @@ -494,7 +494,7 @@ "@opentelemetry/otlp-transformer" "0.57.2" "@opentelemetry/sdk-logs" "0.57.2" -"@opentelemetry/exporter-logs-otlp-http@0.57.2", "@opentelemetry/exporter-logs-otlp-http@^0.200.0": +"@opentelemetry/exporter-logs-otlp-http@0.57.2", "@opentelemetry/exporter-logs-otlp-http@^0.57.2": version "0.57.2" resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.57.2.tgz#01d4668b8f781540f94592da9284b92fd6a2ccd8" integrity sha512-0rygmvLcehBRp56NQVLSleJ5ITTduq/QfU7obOkyWgPpFHulwpw2LYTqNIz5TczKZuy5YY+5D3SDnXZL1tXImg== @@ -518,7 +518,7 @@ "@opentelemetry/sdk-logs" "0.57.2" "@opentelemetry/sdk-trace-base" "1.30.1" -"@opentelemetry/exporter-metrics-otlp-grpc@0.57.2", "@opentelemetry/exporter-metrics-otlp-grpc@^0.200.0": +"@opentelemetry/exporter-metrics-otlp-grpc@0.57.2", "@opentelemetry/exporter-metrics-otlp-grpc@^0.57.2": version "0.57.2" resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.57.2.tgz#a702069b7e89c1c0272d8cb790c9ed85860ac94a" integrity sha512-r70B8yKR41F0EC443b5CGB4rUaOMm99I5N75QQt6sHKxYDzSEc6gm48Diz1CI1biwa5tDPznpylTrywO/pT7qw== @@ -532,7 +532,7 @@ "@opentelemetry/resources" "1.30.1" "@opentelemetry/sdk-metrics" "1.30.1" -"@opentelemetry/exporter-metrics-otlp-http@0.57.2", "@opentelemetry/exporter-metrics-otlp-http@^0.200.0": +"@opentelemetry/exporter-metrics-otlp-http@0.57.2", "@opentelemetry/exporter-metrics-otlp-http@^0.57.2": version "0.57.2" resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.57.2.tgz#0983b28a4a36dee3af2c258394214004e4c68b53" integrity sha512-ttb9+4iKw04IMubjm3t0EZsYRNWr3kg44uUuzfo9CaccYlOh8cDooe4QObDUkvx9d5qQUrbEckhrWKfJnKhemA== @@ -564,7 +564,7 @@ "@opentelemetry/resources" "1.30.1" "@opentelemetry/sdk-metrics" "1.30.1" -"@opentelemetry/exporter-trace-otlp-grpc@0.57.2", "@opentelemetry/exporter-trace-otlp-grpc@^0.200.0": +"@opentelemetry/exporter-trace-otlp-grpc@0.57.2", "@opentelemetry/exporter-trace-otlp-grpc@^0.57.2": version "0.57.2" resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.57.2.tgz#1c1e593a987c211a0e9134037b7a2a7f3836f8ba" integrity sha512-gHU1vA3JnHbNxEXg5iysqCWxN9j83d7/epTYBZflqQnTyCC4N7yZXn/dMM+bEmyhQPGjhCkNZLx4vZuChH1PYw== @@ -577,7 +577,7 @@ "@opentelemetry/resources" "1.30.1" "@opentelemetry/sdk-trace-base" "1.30.1" -"@opentelemetry/exporter-trace-otlp-http@0.57.2", "@opentelemetry/exporter-trace-otlp-http@^0.200.0": +"@opentelemetry/exporter-trace-otlp-http@0.57.2", "@opentelemetry/exporter-trace-otlp-http@^0.57.2": version "0.57.2" resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.57.2.tgz#0ab8e97dc30dbabb8252b68128b80c4685f7c691" integrity sha512-sB/gkSYFu+0w2dVQ0PWY9fAMl172PKMZ/JrHkkW8dmjCL0CYkmXeE+ssqIL/yBUTPOvpLIpenX5T9RwXRBW/3g== @@ -609,15 +609,7 @@ "@opentelemetry/sdk-trace-base" "1.30.1" "@opentelemetry/semantic-conventions" "1.28.0" -"@opentelemetry/instrumentation-grpc@0.57.2": - version "0.57.2" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.57.2.tgz#18c2a5a1e168defd6452514c3416d085f4c72223" - integrity sha512-TR6YQA67cLSZzdxbf2SrbADJy2Y8eBW1+9mF15P0VK2MYcpdoUSmQTF1oMkBwa3B9NwqDFA2fq7wYTTutFQqaQ== - dependencies: - "@opentelemetry/instrumentation" "0.57.2" - "@opentelemetry/semantic-conventions" "1.28.0" - -"@opentelemetry/instrumentation-http@0.57.2", "@opentelemetry/instrumentation-http@^0.200.0": +"@opentelemetry/instrumentation-http@^0.57.2": version "0.57.2" resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-http/-/instrumentation-http-0.57.2.tgz#f425eda67b6241c3abe08e4ea972169b85ef3064" integrity sha512-1Uz5iJ9ZAlFOiPuwYg29Bf7bJJc/GeoeJIFKJYQf67nTVKFe8RHbEtxgkOmK4UGZNHKXcpW4P8cWBYzBn1USpg== @@ -628,7 +620,7 @@ forwarded-parse "2.1.2" semver "^7.5.2" -"@opentelemetry/instrumentation-net@0.43.1", "@opentelemetry/instrumentation-net@^0.44.0": +"@opentelemetry/instrumentation-net@^0.43.1": version "0.43.1" resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-net/-/instrumentation-net-0.43.1.tgz#10a3030fe090ed76204ac025179501f902dcf282" integrity sha512-TaMqP6tVx9/SxlY81dHlSyP5bWJIKq+K7vKfk4naB/LX4LBePPY3++1s0edpzH+RfwN+tEGVW9zTb9ci0up/lQ== @@ -636,7 +628,7 @@ "@opentelemetry/instrumentation" "^0.57.1" "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/instrumentation@0.57.2", "@opentelemetry/instrumentation@^0.200.0", "@opentelemetry/instrumentation@^0.57.1": +"@opentelemetry/instrumentation@0.57.2", "@opentelemetry/instrumentation@^0.57.1", "@opentelemetry/instrumentation@^0.57.2": version "0.57.2" resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.57.2.tgz#8924549d7941ba1b5c6f04d5529cf48330456d1d" integrity sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg== @@ -679,7 +671,7 @@ "@opentelemetry/sdk-trace-base" "1.30.1" protobufjs "^7.3.0" -"@opentelemetry/propagator-b3@1.30.1", "@opentelemetry/propagator-b3@^2.0.0": +"@opentelemetry/propagator-b3@1.30.1", "@opentelemetry/propagator-b3@^1.30.1": version "1.30.1" resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-b3/-/propagator-b3-1.30.1.tgz#b73321e5f30f062a9229887a4aa80c771107fdd2" integrity sha512-oATwWWDIJzybAZ4pO76ATN5N6FFbOA1otibAVlS8v90B4S1wClnhRUk7K+2CHAwN1JKYuj4jh/lpCEG5BAqFuQ== @@ -693,7 +685,7 @@ dependencies: "@opentelemetry/core" "1.30.1" -"@opentelemetry/resource-detector-aws@1.12.0", "@opentelemetry/resource-detector-aws@^1.12.0": +"@opentelemetry/resource-detector-aws@^1.12.0": version "1.12.0" resolved "https://registry.yarnpkg.com/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.12.0.tgz#740edea01ce395a67885c02bbffcad74d3bad4e0" integrity sha512-Cvi7ckOqiiuWlHBdA1IjS0ufr3sltex2Uws2RK6loVp4gzIJyOijsddAI6IZ5kiO8h/LgCWe8gxPmwkTKImd+Q== @@ -702,7 +694,7 @@ "@opentelemetry/resources" "^1.10.0" "@opentelemetry/semantic-conventions" "^1.27.0" -"@opentelemetry/resources@1.30.1", "@opentelemetry/resources@^1.10.0", "@opentelemetry/resources@^2.0.0": +"@opentelemetry/resources@1.30.1", "@opentelemetry/resources@^1.10.0", "@opentelemetry/resources@^1.30.1": version "1.30.1" resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.30.1.tgz#a4eae17ebd96947fdc7a64f931ca4b71e18ce964" integrity sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA== @@ -710,7 +702,7 @@ "@opentelemetry/core" "1.30.1" "@opentelemetry/semantic-conventions" "1.28.0" -"@opentelemetry/sdk-logs@0.57.2", "@opentelemetry/sdk-logs@^0.200.0": +"@opentelemetry/sdk-logs@0.57.2", "@opentelemetry/sdk-logs@^0.57.2": version "0.57.2" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.57.2.tgz#ddc9d1e2b86052b4b6bb954dd90fa3878bed8a23" integrity sha512-TXFHJ5c+BKggWbdEQ/inpgIzEmS2BGQowLE9UhsMd7YYlUfBQJ4uax0VF/B5NYigdM/75OoJGhAV3upEhK+3gg== @@ -719,7 +711,7 @@ "@opentelemetry/core" "1.30.1" "@opentelemetry/resources" "1.30.1" -"@opentelemetry/sdk-metrics@1.30.1", "@opentelemetry/sdk-metrics@^2.0.0": +"@opentelemetry/sdk-metrics@1.30.1", "@opentelemetry/sdk-metrics@^1.30.1": version "1.30.1" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.30.1.tgz#70e2bcd275b9df6e7e925e3fe53cfe71329b5fc8" integrity sha512-q9zcZ0Okl8jRgmy7eNW3Ku1XSgg3sDLa5evHZpCwjspw7E8Is4K/haRPDJrBcX3YSn/Y7gUvFnByNYEKQNbNog== @@ -727,7 +719,7 @@ "@opentelemetry/core" "1.30.1" "@opentelemetry/resources" "1.30.1" -"@opentelemetry/sdk-node@0.57.2", "@opentelemetry/sdk-node@^0.200.0": +"@opentelemetry/sdk-node@^0.57.2": version "0.57.2" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-node/-/sdk-node-0.57.2.tgz#27597c99d3062a3be7c02ace3cc596a02fd31996" integrity sha512-8BaeqZyN5sTuPBtAoY+UtKwXBdqyuRKmekN5bFzAO40CgbGzAxfTpiL3PBerT7rhZ7p2nBdq7FaMv/tBQgHE4A== @@ -753,7 +745,7 @@ "@opentelemetry/sdk-trace-node" "1.30.1" "@opentelemetry/semantic-conventions" "1.28.0" -"@opentelemetry/sdk-trace-base@1.30.1", "@opentelemetry/sdk-trace-base@^2.0.0": +"@opentelemetry/sdk-trace-base@1.30.1", "@opentelemetry/sdk-trace-base@^1.30.1": version "1.30.1" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz#41a42234096dc98e8f454d24551fc80b816feb34" integrity sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg== @@ -762,7 +754,7 @@ "@opentelemetry/resources" "1.30.1" "@opentelemetry/semantic-conventions" "1.28.0" -"@opentelemetry/sdk-trace-node@1.30.1", "@opentelemetry/sdk-trace-node@^2.0.0": +"@opentelemetry/sdk-trace-node@1.30.1", "@opentelemetry/sdk-trace-node@^1.30.1": version "1.30.1" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.30.1.tgz#bd7d68fcfb4d4ae76ea09810df9668b7dd09a2e5" integrity sha512-cBjYOINt1JxXdpw1e5MlHmFRc5fgj4GW/86vsKFxJCJ8AL4PdVtYH41gWwl4qd4uQjqEL1oJVrXkSy5cnduAnQ== @@ -1227,40 +1219,40 @@ dependencies: "@types/yargs-parser" "*" -"@vtex/diagnostics-nodejs@0.1.0-beta.8": - version "0.1.0-beta.8" - resolved "https://registry.yarnpkg.com/@vtex/diagnostics-nodejs/-/diagnostics-nodejs-0.1.0-beta.8.tgz#a3c5cb9d6d2e72564bb0350e66c7415f21ca1e0d" - integrity sha512-teMWNKgakm5ETGfd9J5U/6xiZfCx2p7V2NMYSQ3ibvLwEjMWCItPlI+ThwR3YOPKPX55P8prZwn1GzW4VActjQ== +"@vtex/diagnostics-nodejs@0.1.0-beta.10": + version "0.1.0-beta.10" + resolved "https://registry.yarnpkg.com/@vtex/diagnostics-nodejs/-/diagnostics-nodejs-0.1.0-beta.10.tgz#af255418c0777bf49d02f1e650d654d20f11e513" + integrity sha512-w5IOo+P1RcGXYZZw5RV4guQFIKpIqmq7reEQRx6qJYDh0RwLFFhr7NS8MNGm792xOs59hyYMulhx8FMmcOXVxA== dependencies: "@opentelemetry/api" "^1.9.0" "@opentelemetry/api-logs" "^0.200.0" - "@opentelemetry/core" "^2.0.0" - "@opentelemetry/exporter-logs-otlp-grpc" "^0.200.0" - "@opentelemetry/exporter-logs-otlp-http" "^0.200.0" - "@opentelemetry/exporter-metrics-otlp-grpc" "^0.200.0" - "@opentelemetry/exporter-metrics-otlp-http" "^0.200.0" - "@opentelemetry/exporter-trace-otlp-grpc" "^0.200.0" - "@opentelemetry/exporter-trace-otlp-http" "^0.200.0" - "@opentelemetry/instrumentation" "^0.200.0" - "@opentelemetry/instrumentation-http" "^0.200.0" - "@opentelemetry/instrumentation-net" "^0.44.0" - "@opentelemetry/propagator-b3" "^2.0.0" + "@opentelemetry/core" "^1.30.1" + "@opentelemetry/exporter-logs-otlp-grpc" "^0.57.2" + "@opentelemetry/exporter-logs-otlp-http" "^0.57.2" + "@opentelemetry/exporter-metrics-otlp-grpc" "^0.57.2" + "@opentelemetry/exporter-metrics-otlp-http" "^0.57.2" + "@opentelemetry/exporter-trace-otlp-grpc" "^0.57.2" + "@opentelemetry/exporter-trace-otlp-http" "^0.57.2" + "@opentelemetry/instrumentation" "^0.57.2" + "@opentelemetry/instrumentation-http" "^0.57.2" + "@opentelemetry/instrumentation-net" "^0.43.1" + "@opentelemetry/propagator-b3" "^1.30.1" "@opentelemetry/resource-detector-aws" "^1.12.0" - "@opentelemetry/resources" "^2.0.0" - "@opentelemetry/sdk-logs" "^0.200.0" - "@opentelemetry/sdk-metrics" "^2.0.0" - "@opentelemetry/sdk-node" "^0.200.0" - "@opentelemetry/sdk-trace-base" "^2.0.0" - "@opentelemetry/sdk-trace-node" "^2.0.0" + "@opentelemetry/resources" "^1.30.1" + "@opentelemetry/sdk-logs" "^0.57.2" + "@opentelemetry/sdk-metrics" "^1.30.1" + "@opentelemetry/sdk-node" "^0.57.2" + "@opentelemetry/sdk-trace-base" "^1.30.1" + "@opentelemetry/sdk-trace-node" "^1.30.1" "@opentelemetry/semantic-conventions" "^1.30.0" - "@vtex/diagnostics-semconv" "0.1.0-beta.8" + "@vtex/diagnostics-semconv" "0.1.0-beta.10" tslib "^2.8.1" uuid "^11.1.0" -"@vtex/diagnostics-semconv@0.1.0-beta.8": - version "0.1.0-beta.8" - resolved "https://registry.yarnpkg.com/@vtex/diagnostics-semconv/-/diagnostics-semconv-0.1.0-beta.8.tgz#f741e4d9b91acbac2865bde7310dd471387108a4" - integrity sha512-LK+REJfrdWQLzKyapfuI/ZnB7imBL9CPqWGoKFWEeYGaqj1QbkATTVN5BrwpZBP8jFx/iS2IuVz+CW6hsD6T0Q== +"@vtex/diagnostics-semconv@0.1.0-beta.10": + version "0.1.0-beta.10" + resolved "https://registry.yarnpkg.com/@vtex/diagnostics-semconv/-/diagnostics-semconv-0.1.0-beta.10.tgz#f5b6aa4444cbb4bc1fb0c9e38ca52594d9c2b939" + integrity sha512-a5D8tlBJjBqJBTPsbm3la4gy6hiduWyTTWzjOqoICdgsmCNB9E8mw6NcloEMkBILQ7n8X3EDfXZvkea6OILibQ== "@vtex/node-error-report@^0.0.3": version "0.0.3" From 70bb00ceec6f56d3f8aa61c7588358db9ea7729d Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Wed, 18 Jun 2025 11:23:47 -0300 Subject: [PATCH 06/16] Add mock for @vtex/diagnostics-semconv Also update Jest config --- __mocks__/@vtex/diagnostics-semconv.ts | 16 ++++++++++++++++ jest.config.js | 3 +++ 2 files changed, 19 insertions(+) create mode 100644 __mocks__/@vtex/diagnostics-semconv.ts diff --git a/__mocks__/@vtex/diagnostics-semconv.ts b/__mocks__/@vtex/diagnostics-semconv.ts new file mode 100644 index 000000000..2599806d8 --- /dev/null +++ b/__mocks__/@vtex/diagnostics-semconv.ts @@ -0,0 +1,16 @@ +// Mock para @vtex/diagnostics-semconv +const ATTR_VTEX_OPERATION_ID = 'vtex.operation.id' +const ATTR_VTEX_ACCOUNT_NAME = 'vtex.account.name' +const ATTR_VTEX_IO_WORKSPACE_NAME = 'vtex_io.workspace.name' +const ATTR_VTEX_IO_WORKSPACE_TYPE = 'vtex_io.workspace.type' +const ATTR_VTEX_IO_APP_ID = 'vtex_io.app.id' +const ATTR_VTEX_IO_APP_AUTHOR_TYPE = 'vtex_io.app.author-type' + +export { + ATTR_VTEX_OPERATION_ID, + ATTR_VTEX_ACCOUNT_NAME, + ATTR_VTEX_IO_WORKSPACE_NAME, + ATTR_VTEX_IO_WORKSPACE_TYPE, + ATTR_VTEX_IO_APP_ID, + ATTR_VTEX_IO_APP_AUTHOR_TYPE, +} diff --git a/jest.config.js b/jest.config.js index 9689a2108..c3cf78386 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,4 +5,7 @@ module.exports = { }, testRegex: '(.*(test|spec)).tsx?$', testEnvironment: 'node', + moduleNameMapper: { + '^@vtex/diagnostics-semconv$': '/__mocks__/@vtex/diagnostics-semconv.ts', + }, } From eb7bdb853c3c89739a120b35bdb64f071220e2fb Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Wed, 18 Jun 2025 11:27:37 -0300 Subject: [PATCH 07/16] Add tests for constants.ts Tests constants and their properties, checking attributes and headers introduced by the @vtex/diagnostics-semconv package --- src/constants.test.ts | 432 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 432 insertions(+) create mode 100644 src/constants.test.ts diff --git a/src/constants.test.ts b/src/constants.test.ts new file mode 100644 index 000000000..8861e2076 --- /dev/null +++ b/src/constants.test.ts @@ -0,0 +1,432 @@ +import { + NODE_VTEX_API_VERSION, + DEFAULT_WORKSPACE, + IS_IO, + PID, + HeaderKeys, + AttributeKeys, + BODY_HASH, + UP_SIGNAL, + MAX_AGE, + HTTP_SERVER_PORT, + MAX_WORKERS, + LINKED, + REGION, + PUBLIC_ENDPOINT, + APP, + NODE_ENV, + ACCOUNT, + WORKSPACE, + PRODUCTION, + INSPECT_DEBUGGER_PORT, + cancellableMethods, + LOG_CLIENT_INIT_TIMEOUT_MS +} from './constants' + +describe('constants', () => { + describe('Basic constants', () => { + test('NODE_VTEX_API_VERSION should match package.json version', () => { + const pkg = require('../package.json') + expect(NODE_VTEX_API_VERSION).toBe(pkg.version) + expect(typeof NODE_VTEX_API_VERSION).toBe('string') + expect(NODE_VTEX_API_VERSION.length).toBeGreaterThan(0) + }) + + test('DEFAULT_WORKSPACE should be a non-empty string', () => { + expect(typeof DEFAULT_WORKSPACE).toBe('string') + expect(DEFAULT_WORKSPACE.length).toBeGreaterThan(0) + }) + + test('IS_IO should reflect VTEX_IO environment variable', () => { + expect(IS_IO).toBe(process.env.VTEX_IO) + }) + + test('PID should be the current process ID', () => { + expect(PID).toBe(process.pid) + expect(typeof PID).toBe('number') + expect(PID).toBeGreaterThan(0) + }) + }) + + describe('HeaderKeys', () => { + test('should be an object with string properties', () => { + expect(typeof HeaderKeys).toBe('object') + expect(HeaderKeys).not.toBeNull() + }) + + test('all header keys should be uppercase with underscores', () => { + Object.keys(HeaderKeys).forEach(key => { + expect(key).toMatch(/^[A-Z_]+$/) + }) + }) + + test('VTEX headers should follow x-vtex- or x- naming pattern', () => { + const vtexSpecificHeaders = Object.entries(HeaderKeys).filter(([key]) => + key.includes('VTEX') || + key === 'ACCOUNT' || + key === 'WORKSPACE' || + key === 'OPERATION_ID' || + key === 'SEGMENT' + ) + + vtexSpecificHeaders.forEach(([, value]) => { + expect(value).toMatch(/^x-/) + }) + }) + + test('should not contain empty or invalid header values', () => { + Object.values(HeaderKeys).forEach(value => { + expect(value).not.toContain(' ') + expect(value).not.toMatch(/[A-Z]/) + expect(value).not.toContain('\n') + expect(value).not.toContain('\r') + }) + }) + }) + + describe('AttributeKeys', () => { + test('should be an object with string properties', () => { + expect(typeof AttributeKeys).toBe('object') + expect(AttributeKeys).not.toBeNull() + }) + + test('should contain VTEX semantic attributes', () => { + expect(AttributeKeys).toHaveProperty('VTEX_OPERATION_ID') + expect(AttributeKeys).toHaveProperty('VTEX_ACCOUNT_NAME') + + expect(typeof AttributeKeys.VTEX_OPERATION_ID).toBe('string') + expect(typeof AttributeKeys.VTEX_ACCOUNT_NAME).toBe('string') + }) + + test('should contain VTEX IO semantic attributes', () => { + expect(AttributeKeys).toHaveProperty('VTEX_IO_WORKSPACE_NAME') + expect(AttributeKeys).toHaveProperty('VTEX_IO_WORKSPACE_TYPE') + expect(AttributeKeys).toHaveProperty('VTEX_IO_APP_ID') + expect(AttributeKeys).toHaveProperty('VTEX_IO_APP_AUTHOR_TYPE') + + expect(typeof AttributeKeys.VTEX_IO_WORKSPACE_NAME).toBe('string') + expect(typeof AttributeKeys.VTEX_IO_WORKSPACE_TYPE).toBe('string') + expect(typeof AttributeKeys.VTEX_IO_APP_ID).toBe('string') + expect(typeof AttributeKeys.VTEX_IO_APP_AUTHOR_TYPE).toBe('string') + }) + + test('should have non-empty string values', () => { + Object.values(AttributeKeys).forEach((value: any) => { + expect(typeof value).toBe('string') + expect(value.length).toBeGreaterThan(0) + }) + }) + + test('attribute names should follow naming convention', () => { + Object.keys(AttributeKeys).forEach(key => { + expect(key).toMatch(/^VTEX(_IO)?_[A-Z_]+$/) + }) + }) + + test('should import from external module without errors', () => { + // Test that the AttributeKeys structure exists and is properly imported + expect(AttributeKeys).toBeDefined() + Object.values(AttributeKeys).forEach(value => { + expect(value).toBeTruthy() + }) + }) + }) + + describe('Cache constants', () => { + test('MAX_AGE should be an object with numeric properties', () => { + expect(typeof MAX_AGE).toBe('object') + expect(MAX_AGE).not.toBeNull() + }) + + test('MAX_AGE should contain LONG, MEDIUM, SHORT properties', () => { + expect(MAX_AGE).toHaveProperty('LONG') + expect(MAX_AGE).toHaveProperty('MEDIUM') + expect(MAX_AGE).toHaveProperty('SHORT') + + expect(typeof MAX_AGE.LONG).toBe('number') + expect(typeof MAX_AGE.MEDIUM).toBe('number') + expect(typeof MAX_AGE.SHORT).toBe('number') + }) + + test('MAX_AGE values should be positive integers', () => { + Object.values(MAX_AGE).forEach(value => { + expect(value).toBeGreaterThan(0) + expect(Number.isInteger(value)).toBe(true) + }) + }) + + test('MAX_AGE values should be in logical order', () => { + expect(MAX_AGE.LONG).toBeGreaterThan(MAX_AGE.MEDIUM) + expect(MAX_AGE.MEDIUM).toBeGreaterThan(MAX_AGE.SHORT) + }) + }) + + describe('Server configuration', () => { + test('server ports should have specific expected values', () => { + expect(HTTP_SERVER_PORT).toBe(5050) + expect(INSPECT_DEBUGGER_PORT).toBe(5858) + + // Ensure they are numbers + expect(typeof HTTP_SERVER_PORT).toBe('number') + expect(typeof INSPECT_DEBUGGER_PORT).toBe('number') + }) + + test('MAX_WORKERS should be a positive integer', () => { + expect(typeof MAX_WORKERS).toBe('number') + expect(MAX_WORKERS).toBeGreaterThan(0) + expect(Number.isInteger(MAX_WORKERS)).toBe(true) + }) + + test('LOG_CLIENT_INIT_TIMEOUT_MS should be a positive number', () => { + expect(typeof LOG_CLIENT_INIT_TIMEOUT_MS).toBe('number') + expect(LOG_CLIENT_INIT_TIMEOUT_MS).toBeGreaterThan(0) + }) + }) + + describe('Environment-based constants', () => { + test('boolean environment constants should have correct types', () => { + expect(typeof LINKED).toBe('boolean') + expect(typeof PRODUCTION).toBe('boolean') + }) + + test('string environment constants should match their env vars', () => { + expect(REGION).toBe(process.env.VTEX_REGION as string) + expect(NODE_ENV).toBe(process.env.NODE_ENV as string) + expect(ACCOUNT).toBe(process.env.VTEX_ACCOUNT as string) + expect(WORKSPACE).toBe(process.env.VTEX_WORKSPACE as string) + }) + + test('PUBLIC_ENDPOINT should have a fallback value', () => { + expect(typeof PUBLIC_ENDPOINT).toBe('string') + expect(PUBLIC_ENDPOINT.length).toBeGreaterThan(0) + }) + + test('LINKED should reflect boolean conversion of VTEX_APP_LINK', () => { + expect(LINKED).toBe(!!process.env.VTEX_APP_LINK) + }) + + test('PRODUCTION should reflect string comparison', () => { + expect(PRODUCTION).toBe(process.env.VTEX_PRODUCTION === 'true') + }) + }) + + describe('APP object', () => { + test('should be an object with required properties', () => { + expect(typeof APP).toBe('object') + expect(APP).not.toBeNull() + + const requiredProperties = ['ID', 'MAJOR', 'NAME', 'VENDOR', 'VERSION', 'IS_THIRD_PARTY'] + requiredProperties.forEach(prop => { + expect(APP).toHaveProperty(prop) + }) + }) + + test('string properties should match environment variables', () => { + expect(APP.ID).toBe(process.env.VTEX_APP_ID as string) + expect(APP.NAME).toBe(process.env.VTEX_APP_NAME as string) + expect(APP.VENDOR).toBe(process.env.VTEX_APP_VENDOR as string) + expect(APP.VERSION).toBe(process.env.VTEX_APP_VERSION as string) + }) + + test('MAJOR should be extracted from VERSION', () => { + if (process.env.VTEX_APP_VERSION) { + expect(typeof APP.MAJOR).toBe('string') + } else { + expect(APP.MAJOR).toBe('') + } + }) + + test('IS_THIRD_PARTY should be a function', () => { + expect(typeof APP.IS_THIRD_PARTY).toBe('function') + }) + + test('IS_THIRD_PARTY should return boolean', () => { + const result = APP.IS_THIRD_PARTY() + expect(typeof result).toBe('boolean') + }) + + test('IS_THIRD_PARTY logic should work correctly', () => { + // Test the logic with different vendor values + const testCases = [ + { vendor: 'vtex', expected: false }, + { vendor: 'gocommerce', expected: false }, + { vendor: 'other', expected: true }, + { vendor: undefined, expected: true } + ] + + testCases.forEach(({ vendor, expected }) => { + const mockApp = { + VENDOR: vendor, + IS_THIRD_PARTY() { + return 'vtex' !== this.VENDOR && 'gocommerce' !== this.VENDOR + } + } + expect(mockApp.IS_THIRD_PARTY()).toBe(expected) + }) + }) + }) + + describe('HTTP methods', () => { + test('cancellableMethods should be a Set', () => { + expect(cancellableMethods).toBeInstanceOf(Set) + }) + + test('cancellableMethods should contain safe HTTP methods', () => { + expect(cancellableMethods.has('GET')).toBe(true) + expect(cancellableMethods.has('OPTIONS')).toBe(true) + expect(cancellableMethods.has('HEAD')).toBe(true) + }) + + test('cancellableMethods should not contain unsafe HTTP methods', () => { + const unsafeMethods = ['POST', 'PUT', 'DELETE', 'PATCH'] + unsafeMethods.forEach(method => { + expect(cancellableMethods.has(method)).toBe(false) + }) + }) + + test('cancellableMethods should have appropriate size', () => { + expect(cancellableMethods.size).toBeGreaterThan(0) + expect(cancellableMethods.size).toBeLessThan(10) // Reasonable upper bound + }) + + test('all methods in cancellableMethods should be strings', () => { + cancellableMethods.forEach((method: any) => { + expect(typeof method).toBe('string') + expect(method.length).toBeGreaterThan(0) + }) + }) + }) + + describe('Integration and dependencies', () => { + test('should import required modules without errors', () => { + expect(() => { + require('./utils/app') + }).not.toThrow() + }) + + test('package.json should be accessible and valid', () => { + const pkg = require('../package.json') + expect(pkg).toHaveProperty('name') + expect(pkg).toHaveProperty('version') + expect(typeof pkg.name).toBe('string') + expect(typeof pkg.version).toBe('string') + }) + + test('should handle external module imports gracefully', () => { + // Test that AttributeKeys exists even if external module has issues + expect(AttributeKeys).toBeDefined() + expect(typeof AttributeKeys).toBe('object') + }) + }) + + describe('Constants structure and exports', () => { + test('should export all required constants', () => { + // Test that all expected exports are defined using direct references + const constants = { + NODE_VTEX_API_VERSION, + DEFAULT_WORKSPACE, + IS_IO, + PID, + HeaderKeys, + AttributeKeys, + BODY_HASH, + UP_SIGNAL, + MAX_AGE, + HTTP_SERVER_PORT, + MAX_WORKERS, + LINKED, + REGION, + PUBLIC_ENDPOINT, + APP, + NODE_ENV, + ACCOUNT, + WORKSPACE, + PRODUCTION, + INSPECT_DEBUGGER_PORT, + cancellableMethods, + LOG_CLIENT_INIT_TIMEOUT_MS + } + + // Environment-based constants that can be undefined in test environment + const envBasedConstants = ['IS_IO', 'REGION', 'ACCOUNT', 'WORKSPACE', 'NODE_ENV'] + + Object.entries(constants).forEach(([name, value]) => { + if (envBasedConstants.includes(name)) { + // Environment-based constants can be undefined, but should not be null + expect(value).not.toBeNull() + } else { + // Other constants should be defined + expect(value).toBeDefined() + expect(value).not.toBeNull() + } + }) + }) + + test('constants should have consistent types', () => { + // Test type consistency + expect(typeof NODE_VTEX_API_VERSION).toBe('string') + expect(typeof DEFAULT_WORKSPACE).toBe('string') + expect(typeof PID).toBe('number') + expect(typeof HeaderKeys).toBe('object') + expect(typeof AttributeKeys).toBe('object') + expect(typeof BODY_HASH).toBe('string') + expect(typeof UP_SIGNAL).toBe('string') + expect(typeof MAX_AGE).toBe('object') + expect(typeof HTTP_SERVER_PORT).toBe('number') + expect(typeof MAX_WORKERS).toBe('number') + expect(typeof LINKED).toBe('boolean') + expect(typeof PUBLIC_ENDPOINT).toBe('string') + expect(typeof APP).toBe('object') + expect(typeof PRODUCTION).toBe('boolean') + expect(typeof INSPECT_DEBUGGER_PORT).toBe('number') + expect(cancellableMethods).toBeInstanceOf(Set) + expect(typeof LOG_CLIENT_INIT_TIMEOUT_MS).toBe('number') + }) + + test('should not have null or undefined critical constants', () => { + expect(NODE_VTEX_API_VERSION).not.toBeNull() + expect(DEFAULT_WORKSPACE).not.toBeNull() + expect(PID).not.toBeNull() + expect(HeaderKeys).not.toBeNull() + expect(AttributeKeys).not.toBeNull() + expect(BODY_HASH).not.toBeNull() + expect(UP_SIGNAL).not.toBeNull() + expect(MAX_AGE).not.toBeNull() + expect(APP).not.toBeNull() + expect(cancellableMethods).not.toBeNull() + }) + }) + + describe('Backward compatibility', () => { + test('should maintain critical header structure', () => { + // Test that critical headers exist without testing specific values + const criticalHeaders = ['ACCOUNT', 'WORKSPACE', 'OPERATION_ID', 'REQUEST_ID', 'TRACE_ID'] + + criticalHeaders.forEach(header => { + expect(HeaderKeys).toHaveProperty(header) + expect(typeof HeaderKeys[header as keyof typeof HeaderKeys]).toBe('string') + }) + }) + + test('should maintain AttributeKeys structure', () => { + const requiredAttributes = [ + 'VTEX_OPERATION_ID', 'VTEX_ACCOUNT_NAME', + 'VTEX_IO_WORKSPACE_NAME', 'VTEX_IO_WORKSPACE_TYPE', + 'VTEX_IO_APP_ID', 'VTEX_IO_APP_AUTHOR_TYPE' + ] + + requiredAttributes.forEach(attr => { + expect(AttributeKeys).toHaveProperty(attr) + expect(typeof AttributeKeys[attr as keyof typeof AttributeKeys]).toBe('string') + }) + }) + + test('should maintain APP object structure', () => { + const requiredProperties = ['ID', 'MAJOR', 'NAME', 'VENDOR', 'VERSION', 'IS_THIRD_PARTY'] + + requiredProperties.forEach(prop => { + expect(APP).toHaveProperty(prop) + }) + }) + }) +}) From d4b51962b4a7492f9248660fff12bbac45afcfbb Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Wed, 10 Sep 2025 13:57:51 -0300 Subject: [PATCH 08/16] Bump `@vtex/diagnostics-semconv` version --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index fd3cc016d..c534c2ede 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@types/koa": "^2.11.0", "@types/koa-compose": "^3.2.3", "@vtex/diagnostics-nodejs": "0.1.0-io-beta.20", - "@vtex/diagnostics-semconv": "0.1.0-beta.10", + "@vtex/diagnostics-semconv": "^1.1.2", "@vtex/node-error-report": "^0.0.3", "@wry/equality": "^0.1.9", "agentkeepalive": "^4.0.2", diff --git a/yarn.lock b/yarn.lock index 223ad12fd..673ae7b6a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1282,16 +1282,16 @@ tslib "^2.8.1" uuid "^11.1.0" -"@vtex/diagnostics-semconv@0.1.0-beta.10": - version "0.1.0-beta.10" - resolved "https://registry.yarnpkg.com/@vtex/diagnostics-semconv/-/diagnostics-semconv-0.1.0-beta.10.tgz#f5b6aa4444cbb4bc1fb0c9e38ca52594d9c2b939" - integrity sha512-a5D8tlBJjBqJBTPsbm3la4gy6hiduWyTTWzjOqoICdgsmCNB9E8mw6NcloEMkBILQ7n8X3EDfXZvkea6OILibQ== - "@vtex/diagnostics-semconv@0.1.0-beta.11": version "0.1.0-beta.11" resolved "https://registry.yarnpkg.com/@vtex/diagnostics-semconv/-/diagnostics-semconv-0.1.0-beta.11.tgz#2ddfff7dffdc1c052d23b335f914de91653d9659" integrity sha512-H3KM5fYAFmcxhlA4wT5iPgWJtgKsumFqGkkxjcA/BSwC5tgSWezN82sZDKvBsVo24EoZxVGgLlsjNw1tsp9U3Q== +"@vtex/diagnostics-semconv@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@vtex/diagnostics-semconv/-/diagnostics-semconv-1.1.2.tgz#ed58b4c0f403cf5d9ff5e3d487e959ff9c1802e2" + integrity sha512-CUz58FTeYHC6z5n0qJKcHesJK00ykwDAFKXUaBKjzI166lm/LqMkdPJA8KE2h4RWGDdSaPDIUDdkueSD76oUfw== + "@vtex/node-error-report@^0.0.3": version "0.0.3" resolved "https://registry.yarnpkg.com/@vtex/node-error-report/-/node-error-report-0.0.3.tgz#365a2652aeebbd6b51ddc5d64c3c0bc1a326dc71" From a84c6539e3f2f95d2a0806fa7fdf4d9cefc1b21d Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Wed, 10 Sep 2025 13:58:54 -0300 Subject: [PATCH 09/16] Remove deprecated attribute `ATTR_VTEX_OPERATION_ID` --- src/constants.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 736558005..38f4c7630 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,6 +1,5 @@ import { versionToMajor } from './utils/app' import { - ATTR_VTEX_OPERATION_ID, ATTR_VTEX_ACCOUNT_NAME, ATTR_VTEX_IO_WORKSPACE_NAME, ATTR_VTEX_IO_WORKSPACE_TYPE, @@ -56,7 +55,6 @@ export const HeaderKeys = { export const AttributeKeys = { // VTEX Semantic Attributes - VTEX_OPERATION_ID: ATTR_VTEX_OPERATION_ID, VTEX_ACCOUNT_NAME: ATTR_VTEX_ACCOUNT_NAME, // VTEX IO Semantic Attributes From 01583f4ee70fe79ffcebbf32ac60bf7e32cc511a Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Wed, 10 Sep 2025 14:01:37 -0300 Subject: [PATCH 10/16] Refactor logger `operationId` key Refactor logger module to remove usage of deprecated attribute --- src/service/logger/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/logger/logger.ts b/src/service/logger/logger.ts index 1e1870223..1edbac51a 100644 --- a/src/service/logger/logger.ts +++ b/src/service/logger/logger.ts @@ -87,7 +87,7 @@ export class Logger { [AttributeKeys.VTEX_IO_WORKSPACE_NAME]: this.workspace, [AttributeKeys.VTEX_IO_WORKSPACE_TYPE]: this.production ? 'production' : 'development', [AttributeKeys.VTEX_IO_APP_AUTHOR_TYPE]: APP.IS_THIRD_PARTY() ? '3p' : '1p', - [AttributeKeys.VTEX_OPERATION_ID]: this.operationId, + operationId: this.operationId, requestId: this.requestId, data, ... (this.tracingState?.isTraceSampled ? { traceId: this.tracingState.traceId } : null), From d06916edd7c399e8986652156a5797095c7fcd10 Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Wed, 10 Sep 2025 14:10:10 -0300 Subject: [PATCH 11/16] Update test Remove references to deprecated `VTEX_OPERATION_ID` in constants tests --- src/constants.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/constants.test.ts b/src/constants.test.ts index 8861e2076..522acfb10 100644 --- a/src/constants.test.ts +++ b/src/constants.test.ts @@ -91,10 +91,8 @@ describe('constants', () => { }) test('should contain VTEX semantic attributes', () => { - expect(AttributeKeys).toHaveProperty('VTEX_OPERATION_ID') expect(AttributeKeys).toHaveProperty('VTEX_ACCOUNT_NAME') - expect(typeof AttributeKeys.VTEX_OPERATION_ID).toBe('string') expect(typeof AttributeKeys.VTEX_ACCOUNT_NAME).toBe('string') }) @@ -410,7 +408,7 @@ describe('constants', () => { test('should maintain AttributeKeys structure', () => { const requiredAttributes = [ - 'VTEX_OPERATION_ID', 'VTEX_ACCOUNT_NAME', + 'VTEX_ACCOUNT_NAME', 'VTEX_IO_WORKSPACE_NAME', 'VTEX_IO_WORKSPACE_TYPE', 'VTEX_IO_APP_ID', 'VTEX_IO_APP_AUTHOR_TYPE' ] From 3b236741103e9b76424b5454ed915f9e09620875 Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Wed, 10 Sep 2025 14:18:55 -0300 Subject: [PATCH 12/16] Update mock file Remove deprecated constant `ATTR_VTEX_OPERATION_ID` from diagnostics-semconv mock --- __mocks__/@vtex/diagnostics-semconv.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/__mocks__/@vtex/diagnostics-semconv.ts b/__mocks__/@vtex/diagnostics-semconv.ts index 2599806d8..29a85bedb 100644 --- a/__mocks__/@vtex/diagnostics-semconv.ts +++ b/__mocks__/@vtex/diagnostics-semconv.ts @@ -1,5 +1,4 @@ // Mock para @vtex/diagnostics-semconv -const ATTR_VTEX_OPERATION_ID = 'vtex.operation.id' const ATTR_VTEX_ACCOUNT_NAME = 'vtex.account.name' const ATTR_VTEX_IO_WORKSPACE_NAME = 'vtex_io.workspace.name' const ATTR_VTEX_IO_WORKSPACE_TYPE = 'vtex_io.workspace.type' @@ -7,7 +6,6 @@ const ATTR_VTEX_IO_APP_ID = 'vtex_io.app.id' const ATTR_VTEX_IO_APP_AUTHOR_TYPE = 'vtex_io.app.author-type' export { - ATTR_VTEX_OPERATION_ID, ATTR_VTEX_ACCOUNT_NAME, ATTR_VTEX_IO_WORKSPACE_NAME, ATTR_VTEX_IO_WORKSPACE_TYPE, From 12178235e5c0cd5abcc1b592f1bbfe4165bd8124 Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Thu, 11 Sep 2025 11:27:38 -0300 Subject: [PATCH 13/16] Replaced constant to use HeaderKeys --- .../request/setupAxios/__tests__/axiosTracingTestSuite.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HttpClient/middlewares/request/setupAxios/__tests__/axiosTracingTestSuite.ts b/src/HttpClient/middlewares/request/setupAxios/__tests__/axiosTracingTestSuite.ts index 3caff4f58..8d08411cd 100644 --- a/src/HttpClient/middlewares/request/setupAxios/__tests__/axiosTracingTestSuite.ts +++ b/src/HttpClient/middlewares/request/setupAxios/__tests__/axiosTracingTestSuite.ts @@ -1,7 +1,7 @@ import { MockSpanContext } from '@tiagonapoli/opentracing-alternate-mock' import { AxiosError, AxiosInstance } from 'axios' import { REFERENCE_CHILD_OF, REFERENCE_FOLLOWS_FROM } from 'opentracing' -import { ROUTER_CACHE_HEADER } from '../../../../../constants' +import { HeaderKeys } from '../../../../../constants' import { SpanReferenceTypes } from '../../../../../tracing' import { ErrorReportLogFields } from '../../../../../tracing/LogFields' import { CustomHttpTags, OpentracingTags } from '../../../../../tracing/Tags' @@ -141,7 +141,7 @@ export const registerSharedTestSuite = (testSuiteConfig: TestSuiteConfig) => { if (testSuiteConfig.testServer) { it(`Properly assigns router cache tag when it's present`, async () => { - testSuiteConfig.testServer!.mockResponseHeaders({ [ROUTER_CACHE_HEADER]: 'MISS' }) + testSuiteConfig.testServer!.mockResponseHeaders({ [HeaderKeys.ROUTER_CACHE]: 'MISS' }) const { allRequestSpans } = await TracedTestRequest.doRequest(http, testSuiteConfig.requestsConfig) allRequestSpans.forEach((requestSpan) => { expect(requestSpan.tags()[CustomHttpTags.HTTP_ROUTER_CACHE_RESULT]).toEqual('MISS') From 9b61006ce4b97cabb0b204f027a7c9c96ea37345 Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Wed, 24 Sep 2025 16:54:08 -0300 Subject: [PATCH 14/16] Release beta version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c534c2ede..c6da2cef4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vtex/api", - "version": "7.2.1", + "version": "7.2.2-beta.0", "description": "VTEX I/O API client", "main": "lib/index.js", "typings": "lib/index.d.ts", From 70d56495df7588f3d4e2abb1e1255e73c0fff12b Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Fri, 26 Sep 2025 10:12:31 -0300 Subject: [PATCH 15/16] Update telemetry client to use AttributeKeys Updated the telemetry client to replace hardcoded attribute keys with constants from AttributeKeys --- src/service/telemetry/client.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/service/telemetry/client.ts b/src/service/telemetry/client.ts index 2a5312703..ad32fb3b2 100644 --- a/src/service/telemetry/client.ts +++ b/src/service/telemetry/client.ts @@ -6,7 +6,7 @@ import { Metrics, Traces, } from '@vtex/diagnostics-nodejs'; -import { APP, OTEL_EXPORTER_OTLP_ENDPOINT, DK_APP_ID, DIAGNOSTICS_TELEMETRY_ENABLED, WORKSPACE, PRODUCTION } from '../../constants'; +import { APP, OTEL_EXPORTER_OTLP_ENDPOINT, DK_APP_ID, DIAGNOSTICS_TELEMETRY_ENABLED, WORKSPACE, PRODUCTION, AttributeKeys } from '../../constants'; import { TelemetryClient } from '@vtex/diagnostics-nodejs/dist/telemetry'; import { KoaInstrumentation } from '@opentelemetry/instrumentation-koa'; import { HostMetricsInstrumentation } from '../metrics/instruments/hostMetrics'; @@ -68,11 +68,11 @@ class TelemetryClientSingleton { // Use built-in no-op functionality when telemetry is disabled noop: !DIAGNOSTICS_TELEMETRY_ENABLED, additionalAttrs: { - 'app.id': APPLICATION_ID, + [AttributeKeys.VTEX_IO_APP_ID]: APPLICATION_ID, 'vendor': APP.VENDOR, 'version': APP.VERSION || '', - 'workspace': WORKSPACE, - 'production': PRODUCTION.toString(), + [AttributeKeys.VTEX_IO_WORKSPACE_NAME]: WORKSPACE, + [AttributeKeys.VTEX_IO_WORKSPACE_TYPE]: PRODUCTION.toString(), }, } ); From 9ab955ddd58588a9bf5c1858689672e6e05db878 Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Fri, 26 Sep 2025 10:27:16 -0300 Subject: [PATCH 16/16] Release v7.2.2 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 145e0f1c6..ba31be812 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.2.2] - 2025-09-26 +### Changed +- Adds integration with @vtex/diagnostics-semconv library to support VTEX semantic conventions for diagnostics-based logs + ## [7.2.1] - 2025-09-08 ### Fixed - Ensure `global.metrics` is initialized in both master and worker processes to prevent undefined errors in status tracking and metrics reporting diff --git a/package.json b/package.json index c6da2cef4..63d975e6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vtex/api", - "version": "7.2.2-beta.0", + "version": "7.2.2", "description": "VTEX I/O API client", "main": "lib/index.js", "typings": "lib/index.d.ts",