diff --git a/CHANGELOG.md b/CHANGELOG.md index 925741a8e..582e8f21c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +## [6.45.21] - 2023-09-19 +### Changed +- Fix tracingMiddleware shouldTrace decision +- Fix HttpClient tracing based on sampling decision + +## [6.45.21-beta.2] - 2023-09-19 + +## [6.45.21-beta.1] - 2023-09-07 + +## [6.45.21-beta.0] - 2023-09-04 + +## [6.45.21-beta] - 2023-09-04 + ## [6.45.20] - 2023-08-30 ### Changed - Remove sampling decision from runtime @@ -1776,10 +1789,15 @@ instead - `HttpClient` now adds `'Accept-Encoding': 'gzip'` header by default. -[Unreleased]: https://github.com/vtex/node-vtex-api/compare/v6.45.20...HEAD +[Unreleased]: https://github.com/vtex/node-vtex-api/compare/v6.45.21...HEAD [6.45.15]: https://github.com/vtex/node-vtex-api/compare/v6.45.14...v6.45.15 [6.45.14]: https://github.com/vtex/node-vtex-api/compare/v6.45.13...v6.45.14 [6.45.13]: https://github.com/vtex/node-vtex-api/compare/v6.45.12...v6.45.13 +[6.45.21]: https://github.com/vtex/node-vtex-api/compare/v6.45.21-beta.2...v6.45.21 +[6.45.21-beta.2]: https://github.com/vtex/node-vtex-api/compare/v6.45.21-beta.1...v6.45.21-beta.2 +[6.45.21-beta.1]: https://github.com/vtex/node-vtex-api/compare/v6.45.21-beta.0...v6.45.21-beta.1 +[6.45.21-beta.0]: https://github.com/vtex/node-vtex-api/compare/v6.45.21-beta...v6.45.21-beta.0 +[6.45.21-beta]: https://github.com/vtex/node-vtex-api/compare/v6.45.20...v6.45.21-beta [6.45.20]: https://github.com/vtex/node-vtex-api/compare/v6.45.20-beta...v6.45.20 [6.45.20-beta]: https://github.com/vtex/node-vtex-api/compare/v6.45.19...v6.45.20-beta diff --git a/package.json b/package.json index bd4ecf2d4..a77a26374 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vtex/api", - "version": "6.45.20", + "version": "6.45.21", "description": "VTEX I/O API client", "main": "lib/index.js", "typings": "lib/index.d.ts", diff --git a/src/HttpClient/middlewares/cache.ts b/src/HttpClient/middlewares/cache.ts index 6af403290..2d36e40ca 100644 --- a/src/HttpClient/middlewares/cache.ts +++ b/src/HttpClient/middlewares/cache.ts @@ -90,13 +90,13 @@ export const cacheMiddleware = ({ type, storage }: CacheOptions) => { return await next() } - const span = ctx.tracing!.rootSpan + const span = ctx.tracing?.rootSpan const key = cacheKey(ctx.config) const segmentToken = ctx.config.headers[SEGMENT_HEADER] const keyWithSegment = key + segmentToken - span.log({ + span?.log({ event: HttpLogEvents.CACHE_KEY_CREATE, [HttpCacheLogFields.CACHE_TYPE]: cacheType, [HttpCacheLogFields.KEY]: key, @@ -115,7 +115,7 @@ export const cacheMiddleware = ({ type, storage }: CacheOptions) => { const now = Date.now() - span.log({ + span?.log({ event: HttpLogEvents.LOCAL_CACHE_HIT_INFO, [HttpCacheLogFields.CACHE_TYPE]: cacheType, [HttpCacheLogFields.ETAG]: cachedEtag, @@ -132,18 +132,18 @@ export const cacheMiddleware = ({ type, storage }: CacheOptions) => { router: 0, } - span.setTag(CACHE_RESULT_TAG, CacheResult.HIT) + span?.setTag(CACHE_RESULT_TAG, CacheResult.HIT) return } - span.setTag(CACHE_RESULT_TAG, CacheResult.STALE) + span?.setTag(CACHE_RESULT_TAG, CacheResult.STALE) const validateStatus = addNotModified(ctx.config.validateStatus!) if (cachedEtag && validateStatus(response.status as number)) { ctx.config.headers['if-none-match'] = cachedEtag ctx.config.validateStatus = validateStatus } } else { - span.setTag(CACHE_RESULT_TAG, CacheResult.MISS) + span?.setTag(CACHE_RESULT_TAG, CacheResult.MISS) } await next() @@ -168,7 +168,7 @@ export const cacheMiddleware = ({ type, storage }: CacheOptions) => { const {forceMaxAge} = ctx.config const maxAge = forceMaxAge && cacheableStatusCodes.includes(status) ? Math.max(forceMaxAge, headerMaxAge) : headerMaxAge - span.log({ + span?.log({ event: HttpLogEvents.CACHE_CONFIG, [HttpCacheLogFields.CACHE_TYPE]: cacheType, [HttpCacheLogFields.AGE]: age, @@ -182,7 +182,7 @@ export const cacheMiddleware = ({ type, storage }: CacheOptions) => { // Indicates this should NOT be cached and this request will not be considered a miss. if (!forceMaxAge && (noStore || (noCache && !etag))) { - span.log({ event: HttpLogEvents.NO_LOCAL_CACHE_SAVE, [HttpCacheLogFields.CACHE_TYPE]: cacheType }) + span?.log({ event: HttpLogEvents.NO_LOCAL_CACHE_SAVE, [HttpCacheLogFields.CACHE_TYPE]: cacheType }) return } @@ -207,7 +207,7 @@ export const cacheMiddleware = ({ type, storage }: CacheOptions) => { responseType, }) - span.log({ + span?.log({ event: HttpLogEvents.LOCAL_CACHE_SAVED, [HttpCacheLogFields.CACHE_TYPE]: cacheType, [HttpCacheLogFields.KEY_SET]: setKey, @@ -221,7 +221,7 @@ export const cacheMiddleware = ({ type, storage }: CacheOptions) => { return } - span.log({ event: HttpLogEvents.NO_LOCAL_CACHE_SAVE, [HttpCacheLogFields.CACHE_TYPE]: cacheType }) + span?.log({ event: HttpLogEvents.NO_LOCAL_CACHE_SAVE, [HttpCacheLogFields.CACHE_TYPE]: cacheType }) } } diff --git a/src/HttpClient/middlewares/memoization.ts b/src/HttpClient/middlewares/memoization.ts index e58930d35..dd9b04fb6 100644 --- a/src/HttpClient/middlewares/memoization.ts +++ b/src/HttpClient/middlewares/memoization.ts @@ -17,21 +17,21 @@ export const memoizationMiddleware = ({ memoizedCache }: MemoizationOptions) => return next() } - const span = ctx.tracing!.rootSpan + const span = ctx.tracing?.rootSpan const key = cacheKey(ctx.config) const isMemoized = !!memoizedCache.has(key) - span.log({ event: HttpLogEvents.CACHE_KEY_CREATE, [HttpCacheLogFields.CACHE_TYPE]: 'memoization', [HttpCacheLogFields.KEY]: key }) + span?.log({ event: HttpLogEvents.CACHE_KEY_CREATE, [HttpCacheLogFields.CACHE_TYPE]: 'memoization', [HttpCacheLogFields.KEY]: key }) if (isMemoized) { - span.setTag(CustomHttpTags.HTTP_MEMOIZATION_CACHE_RESULT, CacheResult.HIT) + span?.setTag(CustomHttpTags.HTTP_MEMOIZATION_CACHE_RESULT, CacheResult.HIT) const memoized = await memoizedCache.get(key)! ctx.memoizedHit = isMemoized ctx.response = memoized.response return } else { - span.setTag(CustomHttpTags.HTTP_MEMOIZATION_CACHE_RESULT, CacheResult.MISS) + span?.setTag(CustomHttpTags.HTTP_MEMOIZATION_CACHE_RESULT, CacheResult.MISS) const promise = new Promise(async (resolve, reject) => { try { await next() @@ -40,10 +40,10 @@ export const memoizationMiddleware = ({ memoizedCache }: MemoizationOptions) => response: ctx.response!, }) - span.log({ event: HttpLogEvents.MEMOIZATION_CACHE_SAVED, [HttpCacheLogFields.KEY_SET]: key }) + span?.log({ event: HttpLogEvents.MEMOIZATION_CACHE_SAVED, [HttpCacheLogFields.KEY_SET]: key }) } catch (err) { reject(err) - span.log({ event: HttpLogEvents.MEMOIZATION_CACHE_SAVED_ERROR, [HttpCacheLogFields.KEY_SET]: key }) + span?.log({ event: HttpLogEvents.MEMOIZATION_CACHE_SAVED_ERROR, [HttpCacheLogFields.KEY_SET]: key }) } }) memoizedCache.set(key, promise) diff --git a/src/HttpClient/middlewares/request/index.ts b/src/HttpClient/middlewares/request/index.ts index 5c874b41a..2ec3f3f9d 100644 --- a/src/HttpClient/middlewares/request/index.ts +++ b/src/HttpClient/middlewares/request/index.ts @@ -65,10 +65,10 @@ export const defaultsMiddleware = ({ baseURL, rawHeaders, params, timeout, retri } - if(ctx.tracing!.isSampled) { + if(ctx.tracing?.isSampled) { const { config } = ctx const fullUrl = buildFullPath(config.baseURL, http.getUri(config)) - ctx.tracing!.rootSpan.addTags({ + ctx.tracing?.rootSpan?.addTags({ [OpentracingTags.HTTP_METHOD]: config.method || 'get', [OpentracingTags.HTTP_URL]: fullUrl, }) @@ -89,7 +89,7 @@ export const routerCacheMiddleware = async (ctx: MiddlewareContext, next: () => const status = ctx.response?.status if(routerCacheHit) { - ctx.tracing!.rootSpan.setTag(CustomHttpTags.HTTP_ROUTER_CACHE_RESULT, routerCacheHit) + ctx.tracing?.rootSpan?.setTag(CustomHttpTags.HTTP_ROUTER_CACHE_RESULT, routerCacheHit) } if (routerCacheHit === ROUTER_CACHE_HIT || (routerCacheHit === ROUTER_CACHE_REVALIDATED && status !== 304)) { @@ -106,4 +106,4 @@ export const requestMiddleware = (limit?: Limit) => async (ctx: MiddlewareContex const makeRequest = () => http.request(ctx.config) ctx.response = await (limit ? limit(makeRequest) : makeRequest()) -} \ No newline at end of file +} diff --git a/src/HttpClient/middlewares/request/setupAxios/interceptors/exponentialBackoff.ts b/src/HttpClient/middlewares/request/setupAxios/interceptors/exponentialBackoff.ts index a16cf7cc8..94c869c0b 100644 --- a/src/HttpClient/middlewares/request/setupAxios/interceptors/exponentialBackoff.ts +++ b/src/HttpClient/middlewares/request/setupAxios/interceptors/exponentialBackoff.ts @@ -65,7 +65,7 @@ const onResponseError = (http: AxiosInstance) => (error: any) => { : config.timeout config.transformRequest = [data => data] - config.tracing!.rootSpan!.log({ event: HttpLogEvents.SETUP_REQUEST_RETRY, [HttpRetryLogFields.RETRY_NUMBER]: config.retryCount, [HttpRetryLogFields.RETRY_IN]: delay }) + config.tracing?.rootSpan?.log({ event: HttpLogEvents.SETUP_REQUEST_RETRY, [HttpRetryLogFields.RETRY_NUMBER]: config.retryCount, [HttpRetryLogFields.RETRY_IN]: delay }) return new Promise(resolve => setTimeout(() => resolve(http(config)), delay)) } diff --git a/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/index.ts b/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/index.ts index 703fdbea9..451a34ae2 100644 --- a/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/index.ts +++ b/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/index.ts @@ -26,7 +26,7 @@ export const requestSpanPrefix = 'http-request' const preRequestInterceptor = (http: AxiosInstance) => ( config: TraceableAxiosRequestConfig ): TraceableAxiosRequestConfig => { - if (!config.tracing || !config.tracing.isSampled) { + if (!config.tracing || !config.tracing?.isSampled) { return config } @@ -48,18 +48,18 @@ const preRequestInterceptor = (http: AxiosInstance) => ( } const onResponseSuccess = (response: TraceableAxiosResponse): TraceableAxiosResponse => { - if (!response.config.tracing || !response.config.tracing.isSampled) { + if (!response.config.tracing || !response.config.tracing?.isSampled) { return response } - const requestSpan = response.config.tracing.requestSpan! + const requestSpan = response.config.tracing?.requestSpan injectResponseInfoOnSpan(requestSpan, response) - requestSpan.finish() + requestSpan?.finish() return response } const onResponseError = (err: ExtendedAxiosError) => { - if (!err?.config?.tracing?.requestSpan || !err.config.tracing.isSampled) { + if (!err?.config?.tracing?.requestSpan || !err.config.tracing?.isSampled) { return Promise.reject(err) } diff --git a/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/spanSetup.ts b/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/spanSetup.ts index e59497744..6ca32dcc4 100644 --- a/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/spanSetup.ts +++ b/src/HttpClient/middlewares/request/setupAxios/interceptors/tracing/spanSetup.ts @@ -5,26 +5,26 @@ import { ROUTER_CACHE_HEADER } from '../../../../../../constants' import { CustomHttpTags, OpentracingTags } from '../../../../../../tracing/Tags' import { cloneAndSanitizeHeaders } from '../../../../../../tracing/utils' -export const injectRequestInfoOnSpan = (span: Span, http: AxiosInstance, config: AxiosRequestConfig) => { - span.addTags({ +export const injectRequestInfoOnSpan = (span: Span | undefined, http: AxiosInstance, config: AxiosRequestConfig) => { + span?.addTags({ [OpentracingTags.SPAN_KIND]: OpentracingTags.SPAN_KIND_RPC_CLIENT, [OpentracingTags.HTTP_METHOD]: config.method, [OpentracingTags.HTTP_URL]: buildFullPath(config.baseURL, http.getUri(config)), }) - span.log({ 'request-headers': cloneAndSanitizeHeaders(config.headers) }) + span?.log({ 'request-headers': cloneAndSanitizeHeaders(config.headers) }) } // Response may be undefined in case of client timeout, invalid URL, ... -export const injectResponseInfoOnSpan = (span: Span, response: AxiosResponse | undefined) => { +export const injectResponseInfoOnSpan = (span: Span | undefined, response: AxiosResponse | undefined) => { if (!response) { - span.setTag(CustomHttpTags.HTTP_NO_RESPONSE, 'true') + span?.setTag(CustomHttpTags.HTTP_NO_RESPONSE, 'true') return } - span.log({ 'response-headers': cloneAndSanitizeHeaders(response.headers) }) - span.setTag(OpentracingTags.HTTP_STATUS_CODE, response.status) + 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]) + span?.setTag(CustomHttpTags.HTTP_ROUTER_CACHE_RESULT, response.headers[ROUTER_CACHE_HEADER]) } } diff --git a/src/HttpClient/middlewares/tracing.ts b/src/HttpClient/middlewares/tracing.ts index fdf39c60c..d7c93ce79 100644 --- a/src/HttpClient/middlewares/tracing.ts +++ b/src/HttpClient/middlewares/tracing.ts @@ -1,6 +1,6 @@ import { MiddlewaresTracingContext, RequestConfig } from '..' import { IOContext } from '../../service/worker/runtime/typings' -import { createSpanReference, ErrorReport, getTraceInfo, SpanReferenceTypes } from '../../tracing' +import { ErrorReport, getTraceInfo } from '../../tracing' import { CustomHttpTags, OpentracingTags } from '../../tracing/Tags' import { MiddlewareContext } from '../typings' import { CacheType, isLocallyCacheable } from './cache' @@ -25,13 +25,15 @@ export const createHttpClientTracingMiddleware = ({ hasDiskCacheMiddleware, }: HttpClientTracingMiddlewareConfig) => { return async function tracingMiddleware(ctx: MiddlewareContext, next: () => Promise) { - const { rootSpan, requestSpanNameSuffix, referenceType = SpanReferenceTypes.CHILD_OF } = ctx.config.tracing || {} + if(!tracer.isTraceSampled){ + await next() + return + } + + const rootSpan = tracer.fallbackSpanContext() + const { requestSpanNameSuffix } = ctx.config.tracing || {} const spanName = requestSpanNameSuffix ? `request:${requestSpanNameSuffix}` : 'request' - const span = rootSpan - ? tracer.startSpan(spanName, { - references: [createSpanReference(rootSpan, referenceType)], - }) - : tracer.startSpan(spanName) + const span = tracer.startSpan(spanName, {childOf: rootSpan}) ctx.tracing = { ...ctx.config.tracing, @@ -49,7 +51,7 @@ export const createHttpClientTracingMiddleware = ({ const hasMemoryCache = hasMemoryCacheMiddleware && !!isLocallyCacheable(ctx.config, CacheType.Memory) const hasDiskCache = hasDiskCacheMiddleware && !!isLocallyCacheable(ctx.config, CacheType.Disk) - span.addTags({ + span?.addTags({ [CustomHttpTags.HTTP_MEMOIZATION_CACHE_ENABLED]: hasMemoCache, [CustomHttpTags.HTTP_MEMORY_CACHE_ENABLED]: hasMemoryCache, [CustomHttpTags.HTTP_DISK_CACHE_ENABLED]: hasDiskCache, @@ -62,19 +64,19 @@ export const createHttpClientTracingMiddleware = ({ response = ctx.response } catch (err) { response = err.response - if(ctx.tracing.isSampled) { + if(ctx.tracing?.isSampled) { ErrorReport.create({ originalError: err }).injectOnSpan(span, logger) } - + throw err } finally { if (response) { - span.setTag(OpentracingTags.HTTP_STATUS_CODE, response.status) + span?.setTag(OpentracingTags.HTTP_STATUS_CODE, response.status) } else { - span.setTag(CustomHttpTags.HTTP_NO_RESPONSE, true) + span?.setTag(CustomHttpTags.HTTP_NO_RESPONSE, true) } - span.finish() + span?.finish() } } } diff --git a/src/HttpClient/typings.ts b/src/HttpClient/typings.ts index 0303de6b6..a5183c0b2 100644 --- a/src/HttpClient/typings.ts +++ b/src/HttpClient/typings.ts @@ -63,7 +63,7 @@ export interface CacheHit { export interface MiddlewaresTracingContext extends Omit { tracer: IUserLandTracer logger: IOContext['logger'] - rootSpan: Span + rootSpan?: Span isSampled: boolean } diff --git a/src/service/logger/logger.ts b/src/service/logger/logger.ts index a37ebd5bc..7b6f5b766 100644 --- a/src/service/logger/logger.ts +++ b/src/service/logger/logger.ts @@ -26,7 +26,7 @@ interface LoggerContext extends Pick { const start = process.hrtime() concurrentRequests.inc(1) const rootSpan = tracer.extract(FORMAT_HTTP_HEADERS, ctx.request.headers) as undefined | SpanContext + ctx.tracing = { tracer, currentSpan: undefined} if (!shouldTrace(ctx, rootSpan)) { await next() @@ -76,12 +77,12 @@ export const addTracingMiddleware = (tracer: Tracer) => { ) const traceInfo = getTraceInfo(currentSpan) - if (traceInfo.isSampled) { + if (traceInfo?.isSampled) { if (!initialSamplingDecision) { - currentSpan.setTag(OpentracingTags.SPAN_KIND, OpentracingTags.SPAN_KIND_RPC_SERVER) + currentSpan?.setTag(OpentracingTags.SPAN_KIND, OpentracingTags.SPAN_KIND_RPC_SERVER) } - currentSpan.addTags({ + currentSpan?.addTags({ [OpentracingTags.HTTP_URL]: ctx.request.href, [OpentracingTags.HTTP_METHOD]: ctx.request.method, [OpentracingTags.HTTP_STATUS_CODE]: ctx.response.status, @@ -91,9 +92,9 @@ export const addTracingMiddleware = (tracer: Tracer) => { [VTEXIncomingRequestTags.VTEX_ACCOUNT]: ctx.get(ACCOUNT_HEADER), }) - currentSpan.log(cloneAndSanitizeHeaders(ctx.request.headers, 'req.headers.')) - currentSpan.log(cloneAndSanitizeHeaders(ctx.response.headers, 'res.headers.')) - ctx.set(TRACE_ID_HEADER, traceInfo.traceId) + currentSpan?.log(cloneAndSanitizeHeaders(ctx.request.headers, 'req.headers.')) + currentSpan?.log(cloneAndSanitizeHeaders(ctx.response.headers, 'res.headers.')) + ctx.set(TRACE_ID_HEADER, traceInfo.traceId!) } const onResFinished = () => { @@ -105,7 +106,7 @@ export const addTracingMiddleware = (tracer: Tracer) => { ) concurrentRequests.dec(1) - currentSpan.finish() + currentSpan?.finish() } if (responseClosed) { @@ -119,30 +120,30 @@ export const addTracingMiddleware = (tracer: Tracer) => { export const nameSpanOperationMiddleware = (operationType: string, operationName: string) => { return function nameSpanOperation(ctx: ServiceContext, next: () => Promise) { - ctx.tracing?.currentSpan.setOperationName(`${operationType}:${operationName}`) + ctx.tracing?.currentSpan?.setOperationName(`${operationType}:${operationName}`) return next() } } export const traceUserLandRemainingPipelineMiddleware = () => { return async function traceUserLandRemainingPipeline(ctx: ServiceContext, next: () => Promise) { - const tracingCtx = ctx.tracing! + const tracingCtx = ctx.tracing ctx.tracing = undefined - const span = tracingCtx.currentSpan + const span = tracingCtx?.currentSpan const userLandTracer = ctx.vtex.tracer! as UserLandTracer userLandTracer.setFallbackSpan(span) userLandTracer.lockFallbackSpan() const startTime = process.hrtime() try { - span.log({ event: RuntimeLogEvents.USER_MIDDLEWARES_START }) + span?.log({ event: RuntimeLogEvents.USER_MIDDLEWARES_START }) await next() } catch (err) { ErrorReport.create({ originalError: err }).injectOnSpan(span, ctx.vtex.logger) throw err } finally { - span.log({ + span?.log({ event: RuntimeLogEvents.USER_MIDDLEWARES_FINISH, [RuntimeLogFields.USER_MIDDLEWARES_DURATION]: hrToMillis(process.hrtime(startTime)), }) @@ -151,7 +152,10 @@ export const traceUserLandRemainingPipelineMiddleware = () => { } } function shouldTrace(ctx: ServiceContext, rootSpan: SpanContext | undefined) { - // Should trace if path isnt blacklisted and tracing decision came from the edge - return !PATHS_BLACKLISTED_FOR_TRACING.includes(ctx.request.path) && rootSpan != null + /** Should trace if path isnt blacklisted and sampling decision came from the edge + * ((rootSpan as any).isSampled. returns whether or not this span context was sampled + * There is a cast to bypass opentracing typescript + */ + return !PATHS_BLACKLISTED_FOR_TRACING.includes(ctx.request.path) && ((rootSpan as any).isSampled?.() ?? false) } diff --git a/src/service/worker/runtime/builtIn/handlers.ts b/src/service/worker/runtime/builtIn/handlers.ts index 16d3c3f05..f817e9a9e 100644 --- a/src/service/worker/runtime/builtIn/handlers.ts +++ b/src/service/worker/runtime/builtIn/handlers.ts @@ -4,7 +4,7 @@ export const whoAmIHandler = ({ events, routes, }: ServiceJSON) => (ctx: ServiceContext) => { - ctx.tracing?.currentSpan.setOperationName('builtin:whoami') + ctx.tracing?.currentSpan?.setOperationName('builtin:whoami') ctx.status = 200 ctx.body = { events, @@ -17,7 +17,7 @@ export const healthcheckHandler = ({ events, routes, }: ServiceJSON) => (ctx: ServiceContext) => { - ctx.tracing?.currentSpan.setOperationName('builtin:healthcheck') + ctx.tracing?.currentSpan?.setOperationName('builtin:healthcheck') ctx.status = 200 ctx.body = { events, @@ -26,7 +26,7 @@ export const healthcheckHandler = ({ } export const metricsLoggerHandler = (ctx: ServiceContext) => { - ctx.tracing?.currentSpan.setOperationName('builtin:metrics-logger') + ctx.tracing?.currentSpan?.setOperationName('builtin:metrics-logger') ctx.status = 200 ctx.body = ctx.metricsLogger.getSummaries() } diff --git a/src/service/worker/runtime/events/middlewares/context.ts b/src/service/worker/runtime/events/middlewares/context.ts index e5608cd5e..773373c29 100644 --- a/src/service/worker/runtime/events/middlewares/context.ts +++ b/src/service/worker/runtime/events/middlewares/context.ts @@ -11,7 +11,7 @@ import { prepareHandlerCtx } from '../../utils/context' export async function eventContextMiddleware (ctx: ServiceContext, next: () => Promise) { const { request: { header } } = ctx ctx.vtex = { - ...prepareHandlerCtx(header, ctx.tracing!), + ...prepareHandlerCtx(header, ctx.tracing), eventInfo: { key: header[EVENT_KEY_HEADER], sender: header[EVENT_SENDER_HEADER], diff --git a/src/service/worker/runtime/http/middlewares/context.ts b/src/service/worker/runtime/http/middlewares/context.ts index 6e653e8ea..e484d5520 100644 --- a/src/service/worker/runtime/http/middlewares/context.ts +++ b/src/service/worker/runtime/http/middlewares/context.ts @@ -27,7 +27,7 @@ export const createPvtContextMiddleware = ( request: { header }, } = ctx ctx.vtex = { - ...prepareHandlerCtx(header, ctx.tracing!), + ...prepareHandlerCtx(header, ctx.tracing), ...(smartcache && { recorder: ctx.state.recorder }), route: { id: routeId, @@ -53,7 +53,7 @@ export const createPubContextMiddleware = ( } = ctx ctx.vtex = { - ...prepareHandlerCtx(header, ctx.tracing!), + ...prepareHandlerCtx(header, ctx.tracing), ...(smartcache && { recorder: ctx.state.recorder }), route: { declarer: header[COLOSSUS_ROUTE_DECLARER_HEADER], diff --git a/src/service/worker/runtime/http/middlewares/settings.ts b/src/service/worker/runtime/http/middlewares/settings.ts index 990868399..cc033f952 100644 --- a/src/service/worker/runtime/http/middlewares/settings.ts +++ b/src/service/worker/runtime/http/middlewares/settings.ts @@ -60,7 +60,7 @@ export const getServiceSettings = () => { clients: { apps, assets }, } = ctx - const rootSpan = ctx.tracing!.currentSpan + const rootSpan = ctx.tracing?.currentSpan const dependenciesSettings = await getDependenciesSettings(apps, assets, { tracing: { rootSpan } }) // TODO: for now returning all settings, but the ideia is to do merge diff --git a/src/service/worker/runtime/statusTrack.ts b/src/service/worker/runtime/statusTrack.ts index 5c3930d34..60ea53752 100644 --- a/src/service/worker/runtime/statusTrack.ts +++ b/src/service/worker/runtime/statusTrack.ts @@ -24,7 +24,7 @@ export const isStatusTrackBroadcast = (message: any): message is typeof BROADCAS message === BROADCAST_STATUS_TRACK export const statusTrackHandler = async (ctx: ServiceContext) => { - ctx.tracing?.currentSpan.setOperationName('builtin:status-track') + ctx.tracing?.currentSpan?.setOperationName('builtin:status-track') if (!LINKED) { process.send?.(BROADCAST_STATUS_TRACK) } diff --git a/src/service/worker/runtime/typings.ts b/src/service/worker/runtime/typings.ts index 8392cbe64..357a61cda 100644 --- a/src/service/worker/runtime/typings.ts +++ b/src/service/worker/runtime/typings.ts @@ -28,7 +28,7 @@ export type Maybe = T | null | undefined export interface TracingContext { tracer: Tracer - currentSpan: Span + currentSpan: Span | undefined } export interface Context { diff --git a/src/service/worker/runtime/utils/context.ts b/src/service/worker/runtime/utils/context.ts index 6fe1f1408..c1e66c5f9 100644 --- a/src/service/worker/runtime/utils/context.ts +++ b/src/service/worker/runtime/utils/context.ts @@ -30,7 +30,7 @@ const getPlatform = (account: string): string => { return account.startsWith('gc-') ? 'gocommerce' : 'vtex' } -export const prepareHandlerCtx = (header: Context['request']['header'], tracingContext: TracingContext): HandlerContext => { +export const prepareHandlerCtx = (header: Context['request']['header'], tracingContext?: TracingContext): HandlerContext => { const partialContext = { account: header[ACCOUNT_HEADER], authToken: header[CREDENTIAL_HEADER], @@ -46,7 +46,7 @@ export const prepareHandlerCtx = (header: Context['request']['header'], tracingC segmentToken: header[SEGMENT_HEADER], sessionToken: header[SESSION_HEADER], tenant: header[TENANT_HEADER] ? parseTenantHeaderValue(header[TENANT_HEADER]) : undefined, - tracer: new UserLandTracer(tracingContext.tracer, tracingContext.currentSpan), + tracer: new UserLandTracer(tracingContext?.tracer!, tracingContext?.currentSpan), userAgent: process.env.VTEX_APP_ID || '', workspace: header[WORKSPACE_HEADER], } diff --git a/src/tracing/UserLandTracer.ts b/src/tracing/UserLandTracer.ts index 7b3e616f5..4f8454656 100644 --- a/src/tracing/UserLandTracer.ts +++ b/src/tracing/UserLandTracer.ts @@ -3,11 +3,11 @@ import { TracerSingleton } from '../service/tracing/TracerSingleton' import { getTraceInfo } from './utils' export interface IUserLandTracer { - traceId: string + traceId?: string isTraceSampled: boolean startSpan: Tracer['startSpan'] inject: Tracer['inject'] - fallbackSpanContext: () => SpanContext + fallbackSpanContext: () => SpanContext | undefined } export const createTracingContextFromCarrier = ( @@ -28,15 +28,15 @@ export const createTracingContextFromCarrier = ( export class UserLandTracer implements IUserLandTracer { private tracer: Tracer - private fallbackSpan: Span + private fallbackSpan: Span | undefined private fallbackSpanLock: boolean // tslint:disable-next-line private _isSampled: boolean // tslint:disable-next-line - private _traceId: string + private _traceId?: string - constructor(tracer: Tracer, fallbackSpan: Span) { + constructor(tracer: Tracer, fallbackSpan?: Span) { this.tracer = tracer this.fallbackSpan = fallbackSpan this.fallbackSpanLock = false @@ -58,7 +58,7 @@ export class UserLandTracer implements IUserLandTracer { this.fallbackSpanLock = true } - public setFallbackSpan(newSpan: Span) { + public setFallbackSpan(newSpan?: Span) { if (this.fallbackSpanLock) { throw new Error(`FallbackSpan is locked, can't change it`) } @@ -78,7 +78,7 @@ export class UserLandTracer implements IUserLandTracer { return this.tracer.inject(spanContext, format, carrier) } - public fallbackSpanContext(): SpanContext { - return this.fallbackSpan.context() + public fallbackSpanContext(): SpanContext | undefined { + return this.fallbackSpan?.context() } } diff --git a/src/tracing/errorReporting/ErrorReport.ts b/src/tracing/errorReporting/ErrorReport.ts index 91bf164a2..9446b835e 100644 --- a/src/tracing/errorReporting/ErrorReport.ts +++ b/src/tracing/errorReporting/ErrorReport.ts @@ -43,8 +43,8 @@ export class ErrorReport extends ErrorReportBase { * instance on the provided Span. If a logger is provided and the * span is part of a **sampled** trace, then the error will be logged. */ - public injectOnSpan(span: Span, logger?: IOContext['logger']) { - span.setTag(TracingTags.ERROR, 'true') + public injectOnSpan(span?: Span, logger?: IOContext['logger']) { + span?.setTag(TracingTags.ERROR, 'true') const indexedLogs: Record = { [ErrorReportLogFields.ERROR_KIND]: this.kind, @@ -61,7 +61,7 @@ export class ErrorReport extends ErrorReportBase { } const serializableError = this.toObject() - span.log({ event: 'error', ...indexedLogs, error: serializableError }) + span?.log({ event: 'error', ...indexedLogs, error: serializableError }) if (logger && this.shouldLogToSplunk(span)) { logger.error(serializableError) @@ -71,7 +71,7 @@ export class ErrorReport extends ErrorReportBase { return this } - private shouldLogToSplunk(span: Span) { - return !this.isErrorReported() && getTraceInfo(span).isSampled + private shouldLogToSplunk(span?: Span) { + return !this.isErrorReported() && getTraceInfo(span)?.isSampled } } diff --git a/src/tracing/utils.ts b/src/tracing/utils.ts index 51d3be2e9..633f6df95 100644 --- a/src/tracing/utils.ts +++ b/src/tracing/utils.ts @@ -2,15 +2,15 @@ import { authFields, sanitizeAuth } from '@vtex/node-error-report' import { Span } from 'opentracing' export interface TraceInfo { - traceId: string + traceId?: string isSampled: boolean } -export function getTraceInfo(span: Span): TraceInfo { - const spanContext = span.context() +export function getTraceInfo(span?: Span): TraceInfo { + const spanContext = span?.context() return { - isSampled: (spanContext as any).isSampled?.() ?? false, - traceId: spanContext.toTraceId(), + isSampled: (spanContext as any)?.isSampled?.() ?? false, + traceId: spanContext?.toTraceId(), } }