From 55031de97e81d20c563bdbdf050d493f4cc0e251 Mon Sep 17 00:00:00 2001 From: JonasBa Date: Wed, 15 Dec 2021 14:33:02 +0200 Subject: [PATCH] ref(span): deprecate span status enum --- .../test/unit/mocks/simpletransport.ts | 2 +- packages/node/test/handlers.test.ts | 4 +- packages/tracing/src/browser/backgroundtab.ts | 7 +-- .../tracing/src/browser/browsertracing.ts | 3 +- packages/tracing/src/browser/request.ts | 3 +- packages/tracing/src/errors.ts | 7 +-- packages/tracing/src/idletransaction.ts | 5 +- packages/tracing/src/index.ts | 1 + packages/tracing/src/span.ts | 16 +++--- packages/tracing/src/spanstatus.ts | 54 ++----------------- .../test/browser/backgroundtab.test.ts | 5 +- .../test/browser/browsertracing.test.ts | 5 +- packages/tracing/test/browser/request.test.ts | 6 +-- packages/tracing/test/errors.test.ts | 8 +-- packages/tracing/test/idletransaction.test.ts | 15 +++--- packages/tracing/test/span.test.ts | 8 +-- packages/types/src/index.ts | 2 +- packages/types/src/span.ts | 41 ++++++++++++-- packages/utils/src/index.ts | 1 + packages/utils/src/span.ts | 46 ++++++++++++++++ 20 files changed, 138 insertions(+), 101 deletions(-) create mode 100644 packages/utils/src/span.ts diff --git a/packages/browser/test/unit/mocks/simpletransport.ts b/packages/browser/test/unit/mocks/simpletransport.ts index ba38110ab2a0..8422329aa274 100644 --- a/packages/browser/test/unit/mocks/simpletransport.ts +++ b/packages/browser/test/unit/mocks/simpletransport.ts @@ -1,4 +1,4 @@ -import { SyncPromise, statusFromHttpCode } from '@sentry/utils'; +import { statusFromHttpCode,SyncPromise } from '@sentry/utils'; import { Event, Response } from '../../../src'; import { BaseTransport } from '../../../src/transports'; diff --git a/packages/node/test/handlers.test.ts b/packages/node/test/handlers.test.ts index 4a2b060c887b..9033ffc2ba81 100644 --- a/packages/node/test/handlers.test.ts +++ b/packages/node/test/handlers.test.ts @@ -1,7 +1,7 @@ import * as sentryCore from '@sentry/core'; import { Hub } from '@sentry/hub'; import * as sentryHub from '@sentry/hub'; -import { SpanStatus, Transaction } from '@sentry/tracing'; +import { Transaction } from '@sentry/tracing'; import { RequestSessionStatus, Runtime } from '@sentry/types'; import * as http from 'http'; import * as net from 'net'; @@ -403,7 +403,7 @@ describe('tracingHandler', () => { setImmediate(() => { expect(finishTransaction).toHaveBeenCalled(); - expect(transaction.status).toBe(SpanStatus.Ok); + expect(transaction.status).toBe('ok'); expect(transaction.tags).toEqual(expect.objectContaining({ 'http.status_code': '200' })); done(); }); diff --git a/packages/tracing/src/browser/backgroundtab.ts b/packages/tracing/src/browser/backgroundtab.ts index d2c3d55eeb86..b75178959236 100644 --- a/packages/tracing/src/browser/backgroundtab.ts +++ b/packages/tracing/src/browser/backgroundtab.ts @@ -1,8 +1,8 @@ +import { SpanStatusType } from '@sentry/types'; import { getGlobalObject, logger } from '@sentry/utils'; import { FINISH_REASON_TAG, IDLE_TRANSACTION_FINISH_REASONS } from '../constants'; import { IdleTransaction } from '../idletransaction'; -import { SpanStatus } from '../spanstatus'; import { getActiveTransaction } from '../utils'; const global = getGlobalObject(); @@ -16,13 +16,14 @@ export function registerBackgroundTabDetection(): void { global.document.addEventListener('visibilitychange', () => { const activeTransaction = getActiveTransaction() as IdleTransaction; if (global.document.hidden && activeTransaction) { + const status: SpanStatusType = 'cancelled'; logger.log( - `[Tracing] Transaction: ${SpanStatus.Cancelled} -> since tab moved to the background, op: ${activeTransaction.op}`, + `[Tracing] Transaction: ${status} -> since tab moved to the background, op: ${activeTransaction.op}`, ); // We should not set status if it is already set, this prevent important statuses like // error or data loss from being overwritten on transaction. if (!activeTransaction.status) { - activeTransaction.setStatus(SpanStatus.Cancelled); + activeTransaction.setStatus(status); } activeTransaction.setTag('visibilitychange', 'document.hidden'); activeTransaction.setTag(FINISH_REASON_TAG, IDLE_TRANSACTION_FINISH_REASONS[2]); diff --git a/packages/tracing/src/browser/browsertracing.ts b/packages/tracing/src/browser/browsertracing.ts index 5fda84855208..4218f8e84fd7 100644 --- a/packages/tracing/src/browser/browsertracing.ts +++ b/packages/tracing/src/browser/browsertracing.ts @@ -4,7 +4,6 @@ import { getGlobalObject, logger } from '@sentry/utils'; import { startIdleTransaction } from '../hubextensions'; import { DEFAULT_IDLE_TIMEOUT, IdleTransaction } from '../idletransaction'; -import { SpanStatus } from '../spanstatus'; import { extractTraceparentData, secToMs } from '../utils'; import { registerBackgroundTabDetection } from './backgroundtab'; import { MetricsInstrumentation } from './metrics'; @@ -269,7 +268,7 @@ function adjustTransactionDuration(maxDuration: number, transaction: IdleTransac const diff = endTimestamp - transaction.startTimestamp; const isOutdatedTransaction = endTimestamp && (diff > maxDuration || diff < 0); if (isOutdatedTransaction) { - transaction.setStatus(SpanStatus.DeadlineExceeded); + transaction.setStatus('deadline_exceeded'); transaction.setTag('maxTransactionDurationExceeded', 'true'); } } diff --git a/packages/tracing/src/browser/request.ts b/packages/tracing/src/browser/request.ts index db9bf8066314..2094d2052292 100644 --- a/packages/tracing/src/browser/request.ts +++ b/packages/tracing/src/browser/request.ts @@ -1,7 +1,6 @@ import { addInstrumentationHandler, isInstanceOf, isMatchingPattern } from '@sentry/utils'; import { Span } from '../span'; -import { SpanStatus } from '../spanstatus'; import { getActiveTransaction, hasTracingEnabled } from '../utils'; export const DEFAULT_TRACING_ORIGINS = ['localhost', /^\//]; @@ -156,7 +155,7 @@ export function fetchCallback( // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access span.setHttpStatus(handlerData.response.status); } else if (handlerData.error) { - span.setStatus(SpanStatus.InternalError); + span.setStatus('internal_error'); } span.finish(); diff --git a/packages/tracing/src/errors.ts b/packages/tracing/src/errors.ts index eb15d592cb7c..6f8910b272ea 100644 --- a/packages/tracing/src/errors.ts +++ b/packages/tracing/src/errors.ts @@ -1,6 +1,6 @@ +import { SpanStatusType } from '@sentry/types'; import { addInstrumentationHandler, logger } from '@sentry/utils'; -import { SpanStatus } from './spanstatus'; import { getActiveTransaction } from './utils'; /** @@ -23,7 +23,8 @@ export function registerErrorInstrumentation(): void { function errorCallback(): void { const activeTransaction = getActiveTransaction(); if (activeTransaction) { - logger.log(`[Tracing] Transaction: ${SpanStatus.InternalError} -> Global error occured`); - activeTransaction.setStatus(SpanStatus.InternalError); + const errorType: SpanStatusType = 'internal_error'; + logger.log(`[Tracing] Transaction: ${errorType} -> Global error occured`); + activeTransaction.setStatus(errorType); } } diff --git a/packages/tracing/src/idletransaction.ts b/packages/tracing/src/idletransaction.ts index c14e079b50c2..07839d6c6616 100644 --- a/packages/tracing/src/idletransaction.ts +++ b/packages/tracing/src/idletransaction.ts @@ -4,7 +4,6 @@ import { logger, timestampWithMs } from '@sentry/utils'; import { FINISH_REASON_TAG, IDLE_TRANSACTION_FINISH_REASONS } from './constants'; import { Span, SpanRecorder } from './span'; -import { SpanStatus } from './spanstatus'; import { Transaction } from './transaction'; export const DEFAULT_IDLE_TIMEOUT = 1000; @@ -125,7 +124,7 @@ export class IdleTransaction extends Transaction { // We cancel all pending spans with status "cancelled" to indicate the idle transaction was finished early if (!span.endTimestamp) { span.endTimestamp = endTimestamp; - span.setStatus(SpanStatus.Cancelled); + span.setStatus('cancelled'); logger.log('[Tracing] cancelling span since transaction ended early', JSON.stringify(span, undefined, 2)); } @@ -253,7 +252,7 @@ export class IdleTransaction extends Transaction { if (this._heartbeatCounter >= 3) { logger.log(`[Tracing] Transaction finished because of no change for 3 heart beats`); - this.setStatus(SpanStatus.DeadlineExceeded); + this.setStatus('deadline_exceeded'); this.setTag(FINISH_REASON_TAG, IDLE_TRANSACTION_FINISH_REASONS[0]); this.finish(); } else { diff --git a/packages/tracing/src/index.ts b/packages/tracing/src/index.ts index 1974227b2ff1..f673ead767ad 100644 --- a/packages/tracing/src/index.ts +++ b/packages/tracing/src/index.ts @@ -29,6 +29,7 @@ export { RequestInstrumentationOptions, defaultRequestInstrumentationOptions, } from './browser'; +/* eslint-disable-next-line deprecation/deprecation */ export { SpanStatus } from './spanstatus'; export { IdleTransaction } from './idletransaction'; export { startIdleTransaction } from './hubextensions'; diff --git a/packages/tracing/src/span.ts b/packages/tracing/src/span.ts index ed3c03651ba0..443d39e21734 100644 --- a/packages/tracing/src/span.ts +++ b/packages/tracing/src/span.ts @@ -1,8 +1,6 @@ /* eslint-disable max-lines */ -import { Primitive, Span as SpanInterface, SpanContext, Transaction } from '@sentry/types'; -import { dropUndefinedKeys, timestampWithMs, uuid4 } from '@sentry/utils'; - -import { SpanStatus } from './spanstatus'; +import { Primitive, Span as SpanInterface, SpanContext, SpanStatusType, Transaction } from '@sentry/types'; +import { dropUndefinedKeys, spanStatusfromHttpCode, timestampWithMs, uuid4 } from '@sentry/utils'; /** * Keeps track of finished spans for a given transaction @@ -56,7 +54,7 @@ export class Span implements SpanInterface { /** * Internal keeper of the status */ - public status?: SpanStatus | string; + public status?: SpanStatusType; /** * @inheritDoc @@ -204,7 +202,7 @@ export class Span implements SpanInterface { /** * @inheritDoc */ - public setStatus(value: SpanStatus): this { + public setStatus(value: SpanStatusType): this { this.status = value; return this; } @@ -214,8 +212,8 @@ export class Span implements SpanInterface { */ public setHttpStatus(httpStatus: number): this { this.setTag('http.status_code', String(httpStatus)); - const spanStatus = SpanStatus.fromHttpCode(httpStatus); - if (spanStatus !== SpanStatus.UnknownError) { + const spanStatus = spanStatusfromHttpCode(httpStatus); + if (spanStatus !== 'unknown_error') { this.setStatus(spanStatus); } return this; @@ -225,7 +223,7 @@ export class Span implements SpanInterface { * @inheritDoc */ public isSuccess(): boolean { - return this.status === SpanStatus.Ok; + return this.status === 'ok'; } /** diff --git a/packages/tracing/src/spanstatus.ts b/packages/tracing/src/spanstatus.ts index 692b60d7d364..9493250a2074 100644 --- a/packages/tracing/src/spanstatus.ts +++ b/packages/tracing/src/spanstatus.ts @@ -1,5 +1,6 @@ -/** The status of an Span. */ -// eslint-disable-next-line import/export +/** JSDoc + * @deprecated Use string literals - if you require type casting, cast to SpanStatusType type + */ export enum SpanStatus { /** The operation completed successfully. */ Ok = 'ok', @@ -36,52 +37,3 @@ export enum SpanStatus { /** Unrecoverable data loss or corruption */ DataLoss = 'data_loss', } - -// eslint-disable-next-line @typescript-eslint/no-namespace, import/export -export namespace SpanStatus { - /** - * Converts a HTTP status code into a {@link SpanStatus}. - * - * @param httpStatus The HTTP response status code. - * @returns The span status or {@link SpanStatus.UnknownError}. - */ - export function fromHttpCode(httpStatus: number): SpanStatus { - if (httpStatus < 400 && httpStatus >= 100) { - return SpanStatus.Ok; - } - - if (httpStatus >= 400 && httpStatus < 500) { - switch (httpStatus) { - case 401: - return SpanStatus.Unauthenticated; - case 403: - return SpanStatus.PermissionDenied; - case 404: - return SpanStatus.NotFound; - case 409: - return SpanStatus.AlreadyExists; - case 413: - return SpanStatus.FailedPrecondition; - case 429: - return SpanStatus.ResourceExhausted; - default: - return SpanStatus.InvalidArgument; - } - } - - if (httpStatus >= 500 && httpStatus < 600) { - switch (httpStatus) { - case 501: - return SpanStatus.Unimplemented; - case 503: - return SpanStatus.Unavailable; - case 504: - return SpanStatus.DeadlineExceeded; - default: - return SpanStatus.InternalError; - } - } - - return SpanStatus.UnknownError; - } -} diff --git a/packages/tracing/test/browser/backgroundtab.test.ts b/packages/tracing/test/browser/backgroundtab.test.ts index 71b8810c9142..0d5ef5e08b4c 100644 --- a/packages/tracing/test/browser/backgroundtab.test.ts +++ b/packages/tracing/test/browser/backgroundtab.test.ts @@ -2,7 +2,7 @@ import { BrowserClient } from '@sentry/browser'; import { Hub, makeMain } from '@sentry/hub'; import { JSDOM } from 'jsdom'; -import { SpanStatus } from '../../src'; +import { SpanStatusType } from '../../../types/src/span'; import { registerBackgroundTabDetection } from '../../src/browser/backgroundtab'; describe('registerBackgroundTabDetection', () => { @@ -49,7 +49,8 @@ describe('registerBackgroundTabDetection', () => { global.document.hidden = true; events.visibilitychange(); - expect(transaction.status).toBe(SpanStatus.Cancelled); + const status: SpanStatusType = 'cancelled'; + expect(transaction.status).toBe(status); expect(transaction.tags.visibilitychange).toBe('document.hidden'); expect(transaction.endTimestamp).toBeDefined(); }); diff --git a/packages/tracing/test/browser/browsertracing.test.ts b/packages/tracing/test/browser/browsertracing.test.ts index e8a123eeb93c..00e6351b4c45 100644 --- a/packages/tracing/test/browser/browsertracing.test.ts +++ b/packages/tracing/test/browser/browsertracing.test.ts @@ -3,7 +3,7 @@ import { Hub, makeMain } from '@sentry/hub'; import { getGlobalObject } from '@sentry/utils'; import { JSDOM } from 'jsdom'; -import { SpanStatus } from '../../src'; +import { SpanStatusType } from '../../../types/src/span'; import { BrowserTracing, BrowserTracingOptions, @@ -273,7 +273,8 @@ describe('BrowserTracing', () => { const transaction = getActiveTransaction(hub) as IdleTransaction; transaction.finish(transaction.startTimestamp + secToMs(DEFAULT_MAX_TRANSACTION_DURATION_SECONDS) + 1); - expect(transaction.status).toBe(SpanStatus.DeadlineExceeded); + const status: SpanStatusType = 'deadline_exceeded'; + expect(transaction.status).toBe(status); expect(transaction.tags.maxTransactionDurationExceeded).toBeDefined(); }); diff --git a/packages/tracing/test/browser/request.test.ts b/packages/tracing/test/browser/request.test.ts index 4c2a18788131..4bee09a6f119 100644 --- a/packages/tracing/test/browser/request.test.ts +++ b/packages/tracing/test/browser/request.test.ts @@ -2,7 +2,7 @@ import { BrowserClient } from '@sentry/browser'; import { Hub, makeMain } from '@sentry/hub'; import * as utils from '@sentry/utils'; -import { Span, SpanStatus, Transaction } from '../../src'; +import { Span, Transaction } from '../../src'; import { fetchCallback, FetchData, instrumentOutgoingRequests, xhrCallback, XHRData } from '../../src/browser/request'; import { addExtensionMethods } from '../../src/hubextensions'; import * as tracingUtils from '../../src/utils'; @@ -176,7 +176,7 @@ describe('callbacks', () => { // triggered by response coming back fetchCallback(postRequestFetchHandlerData, alwaysCreateSpan, spans); - expect(newSpan!.status).toBe(SpanStatus.fromHttpCode(404)); + expect(newSpan!.status).toBe(utils.spanStatusfromHttpCode(404)); }); it('adds sentry-trace header to fetch requests', () => { @@ -267,7 +267,7 @@ describe('callbacks', () => { // triggered by response coming back xhrCallback(postRequestXHRHandlerData, alwaysCreateSpan, spans); - expect(newSpan!.status).toBe(SpanStatus.fromHttpCode(404)); + expect(newSpan!.status).toBe(utils.spanStatusfromHttpCode(404)); }); }); }); diff --git a/packages/tracing/test/errors.test.ts b/packages/tracing/test/errors.test.ts index 5a0477cb9d31..21eac8e3c985 100644 --- a/packages/tracing/test/errors.test.ts +++ b/packages/tracing/test/errors.test.ts @@ -1,7 +1,7 @@ import { BrowserClient } from '@sentry/browser'; import { Hub, makeMain } from '@sentry/hub'; -import { SpanStatus } from '../src'; +import { SpanStatusType } from '../../types/src/span'; import { registerErrorInstrumentation } from '../src/errors'; import { _addTracingExtensions } from '../src/hubextensions'; @@ -71,7 +71,8 @@ describe('registerErrorHandlers()', () => { hub.configureScope(scope => scope.setSpan(transaction)); mockErrorCallback(); - expect(transaction.status).toBe(SpanStatus.InternalError); + const status: SpanStatusType = 'internal_error'; + expect(transaction.status).toBe(status); transaction.finish(); }); @@ -82,7 +83,8 @@ describe('registerErrorHandlers()', () => { hub.configureScope(scope => scope.setSpan(transaction)); mockUnhandledRejectionCallback(); - expect(transaction.status).toBe(SpanStatus.InternalError); + const status: SpanStatusType = 'internal_error'; + expect(transaction.status).toBe(status); transaction.finish(); }); }); diff --git a/packages/tracing/test/idletransaction.test.ts b/packages/tracing/test/idletransaction.test.ts index a7a29cf6ff86..94c6d14fb655 100644 --- a/packages/tracing/test/idletransaction.test.ts +++ b/packages/tracing/test/idletransaction.test.ts @@ -1,6 +1,6 @@ import { BrowserClient, Transports } from '@sentry/browser'; import { Hub } from '@sentry/hub'; -import { Outcome } from '@sentry/types'; +import { Outcome, SpanStatusType } from '@sentry/types'; import { DEFAULT_IDLE_TIMEOUT, @@ -9,7 +9,6 @@ import { IdleTransactionSpanRecorder, } from '../src/idletransaction'; import { Span } from '../src/span'; -import { SpanStatus } from '../src/spanstatus'; export class SimpleTransport extends Transports.BaseTransport {} @@ -160,7 +159,8 @@ describe('IdleTransaction', () => { // Cancelled Span - has endtimestamp of transaction expect(spans[2].spanId).toBe(cancelledSpan.spanId); - expect(spans[2].status).toBe(SpanStatus.Cancelled); + const status: SpanStatusType = 'cancelled'; + expect(spans[2].status).toBe(status); expect(spans[2].endTimestamp).toBe(transaction.endTimestamp); } }); @@ -203,22 +203,23 @@ describe('IdleTransaction', () => { const transaction = new IdleTransaction({ name: 'foo' }, hub, 20000); const mockFinish = jest.spyOn(transaction, 'finish'); - expect(transaction.status).not.toEqual(SpanStatus.DeadlineExceeded); + const status: SpanStatusType = 'deadline_exceeded'; + expect(transaction.status).not.toEqual(status); expect(mockFinish).toHaveBeenCalledTimes(0); // Beat 1 jest.advanceTimersByTime(HEARTBEAT_INTERVAL); - expect(transaction.status).not.toEqual(SpanStatus.DeadlineExceeded); + expect(transaction.status).not.toEqual(status); expect(mockFinish).toHaveBeenCalledTimes(0); // Beat 2 jest.advanceTimersByTime(HEARTBEAT_INTERVAL); - expect(transaction.status).not.toEqual(SpanStatus.DeadlineExceeded); + expect(transaction.status).not.toEqual(status); expect(mockFinish).toHaveBeenCalledTimes(0); // Beat 3 jest.advanceTimersByTime(HEARTBEAT_INTERVAL); - expect(transaction.status).not.toEqual(SpanStatus.DeadlineExceeded); + expect(transaction.status).not.toEqual(status); expect(mockFinish).toHaveBeenCalledTimes(0); }); diff --git a/packages/tracing/test/span.test.ts b/packages/tracing/test/span.test.ts index 3690f13ce3f5..aa18504941b5 100644 --- a/packages/tracing/test/span.test.ts +++ b/packages/tracing/test/span.test.ts @@ -72,7 +72,7 @@ describe('Span', () => { describe('status', () => { test('setStatus', () => { const span = new Span({}); - span.setStatus(SpanStatus.PermissionDenied); + span.setStatus('permission_denied'); expect((span.getTraceContext() as any).status).toBe('permission_denied'); }); @@ -88,7 +88,7 @@ describe('Span', () => { expect(span.isSuccess()).toBe(false); span.setHttpStatus(200); expect(span.isSuccess()).toBe(true); - span.setStatus(SpanStatus.PermissionDenied); + span.setStatus('permission_denied'); expect(span.isSuccess()).toBe(false); span.setHttpStatus(0); expect(span.isSuccess()).toBe(false); @@ -287,14 +287,14 @@ describe('Span', () => { test('should have success status extracted from tags', () => { const span = new Span({}); - span.setStatus(SpanStatus.Ok); + span.setStatus('ok'); const context = span.getTraceContext(); expect((context as any).status).toBe('ok'); }); test('should have failure status extracted from tags', () => { const span = new Span({}); - span.setStatus(SpanStatus.ResourceExhausted); + span.setStatus('resource_exhausted'); const context = span.getTraceContext(); expect((context as any).status).toBe('resource_exhausted'); }); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 7eb6da4d85b6..688ff3df1c69 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -35,7 +35,7 @@ export { /* eslint-disable-next-line deprecation/deprecation */ export { Severity } from './severity'; export { SeverityLevel, SeverityLevels } from './severity'; -export { Span, SpanContext } from './span'; +export { Span, SpanContext, SpanStatusType } from './span'; export { StackFrame } from './stackframe'; export { Stacktrace } from './stacktrace'; /* eslint-disable-next-line deprecation/deprecation */ diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 09b69454835e..750e56a14695 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -1,6 +1,42 @@ import { Primitive } from './misc'; import { Transaction } from './transaction'; +export type SpanStatusType = + /** The operation completed successfully. */ + | 'ok' + /** Deadline expired before operation could complete. */ + | 'deadline_exceeded' + /** 401 Unauthorized (actually does mean unauthenticated according to RFC 7235) */ + | 'unauthenticated' + /** 403 Forbidden */ + | 'permission_denied' + /** 404 Not Found. Some requested entity (file or directory) was not found. */ + | 'not_found' + /** 429 Too Many Requests */ + | 'resource_exhausted' + /** Client specified an invalid argument. 4xx. */ + | 'invalid_argument' + /** 501 Not Implemented */ + | 'unimplemented' + /** 503 Service Unavailable */ + | 'unavailable' + /** Other/generic 5xx. */ + | 'internal_error' + /** Unknown. Any non-standard HTTP status code. */ + | 'unknown_error' + /** The operation was cancelled (typically by the user). */ + | 'cancelled' + /** Already exists (409) */ + | 'already_exists' + /** Operation was rejected because the system is not in a state required for the operation's */ + | 'failed_precondition' + /** The operation was aborted, typically due to a concurrency issue. */ + | 'aborted' + /** Operation was attempted past the valid range. */ + | 'out_of_range' + /** Unrecoverable data loss or corruption */ + | 'data_loss'; + /** Interface holding all properties that can be set on a Span on creation. */ export interface SpanContext { /** @@ -15,9 +51,8 @@ export interface SpanContext { /** * Completion status of the Span. - * See: {@sentry/tracing SpanStatus} for possible values */ - status?: string; + status?: SpanStatusType; /** * Parent Span ID @@ -120,7 +155,7 @@ export interface Span extends SpanContext { * See: {@sentry/tracing SpanStatus} for possible values * @param status http code used to set the status */ - setStatus(status: string): this; + setStatus(status: SpanStatusType): this; /** * Sets the status attribute on the current span based on the http code diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 4219bcffd61a..f2018f4e93d0 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -13,6 +13,7 @@ export * from './object'; export * from './path'; export * from './promisebuffer'; export * from './severity'; +export * from './span'; export * from './stacktrace'; export * from './status'; export * from './string'; diff --git a/packages/utils/src/span.ts b/packages/utils/src/span.ts new file mode 100644 index 000000000000..4c231e3f2682 --- /dev/null +++ b/packages/utils/src/span.ts @@ -0,0 +1,46 @@ +import { SpanStatusType } from '@sentry/types'; +/** + * Converts a HTTP status code into a {@link SpanStatusType}. + * + * @param httpStatus The HTTP response status code. + * @returns The span status or unknown_error. + */ +export function spanStatusfromHttpCode(httpStatus: number): SpanStatusType { + if (httpStatus < 400 && httpStatus >= 100) { + return 'ok'; + } + + if (httpStatus >= 400 && httpStatus < 500) { + switch (httpStatus) { + case 401: + return 'unauthenticated'; + case 403: + return 'permission_denied'; + case 404: + return 'not_found'; + case 409: + return 'already_exists'; + case 413: + return 'failed_precondition'; + case 429: + return 'resource_exhausted'; + default: + return 'invalid_argument'; + } + } + + if (httpStatus >= 500 && httpStatus < 600) { + switch (httpStatus) { + case 501: + return 'unimplemented'; + case 503: + return 'unavailable'; + case 504: + return 'deadline_exceeded'; + default: + return 'internal_error'; + } + } + + return 'unknown_error'; +}