UNPKG

@opentelemetry/api

Version:
1 lines • 6.41 kB
{"version":3,"file":"tracestate-impl.cjs","names":["validateKey","validateValue"],"sources":["../../../src/trace/internal/tracestate-impl.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { TraceState } from '../trace_state';\nimport { validateKey, validateValue } from './tracestate-validators';\n\nconst MAX_TRACE_STATE_ITEMS = 32;\nconst MAX_TRACE_STATE_LEN = 512;\nconst LIST_MEMBERS_SEPARATOR = ',';\nconst LIST_MEMBER_KEY_VALUE_SPLITTER = '=';\n\n/**\n * TraceState must be a class and not a simple object type because of the spec\n * requirement (https://www.w3.org/TR/trace-context/#tracestate-field).\n *\n * Here is the list of allowed mutations:\n * - New key-value pair should be added into the beginning of the list\n * - The value of any key can be updated. Modified keys MUST be moved to the\n * beginning of the list.\n *\n * @deprecated Use TraceState from \"@opentelemetry/core\". This will be removed in the next major version.\n */\nexport class TraceStateImpl implements TraceState {\n private _internalState: Map<string, string> = new Map();\n\n constructor(rawTraceState?: string) {\n if (rawTraceState) this._parse(rawTraceState);\n }\n\n set(key: string, value: string): TraceStateImpl {\n // TODO: Benchmark the different approaches(map vs list) and\n // use the faster one.\n const currValue = this._internalState.get(key);\n\n // Get the length the serialized list would have after the mutation\n // - for existing keys only the length of the value changes\n // - for new keys it is the key & value length plus\n // - +1 for the key/value splitter\n // - +1 for the separator if there are other keys\n let newLength = this.serialize().length;\n if (typeof currValue === 'string') {\n newLength += value.length - currValue.length;\n } else {\n // A list can hold at most 32 list-members, so a new key is only\n // accepted while there is room for it. Updating an existing key does\n // not change the count and is always allowed.\n if (this._internalState.size >= MAX_TRACE_STATE_ITEMS) {\n return this;\n }\n newLength +=\n key.length + value.length + (this._internalState.size > 0 ? 2 : 1);\n }\n if (newLength > MAX_TRACE_STATE_LEN) {\n return this;\n }\n\n const traceState = this._clone();\n if (traceState._internalState.has(key)) {\n traceState._internalState.delete(key);\n }\n traceState._internalState.set(key, value);\n return traceState;\n }\n\n unset(key: string): TraceStateImpl {\n const traceState = this._clone();\n traceState._internalState.delete(key);\n return traceState;\n }\n\n get(key: string): string | undefined {\n return this._internalState.get(key);\n }\n\n serialize(): string {\n return (\n Array.from(this._internalState.keys())\n // Use reduceRight() because keys are stored in reverse insertion order.\n .reduceRight((agg: string[], key) => {\n agg.push(key + LIST_MEMBER_KEY_VALUE_SPLITTER + this.get(key));\n return agg;\n }, [])\n .join(LIST_MEMBERS_SEPARATOR)\n );\n }\n\n private _parse(rawTraceState: string) {\n if (rawTraceState.length > MAX_TRACE_STATE_LEN) return;\n this._internalState = rawTraceState\n .split(LIST_MEMBERS_SEPARATOR)\n // Use reduceRight() so new keys (.set(...)) will be placed at the beginning\n .reduceRight((agg: Map<string, string>, part: string) => {\n const listMember = part.trim(); // Optional Whitespace (OWS) handling\n const i = listMember.indexOf(LIST_MEMBER_KEY_VALUE_SPLITTER);\n if (i !== -1) {\n const key = listMember.slice(0, i);\n const value = listMember.slice(i + 1, part.length);\n if (validateKey(key) && validateValue(value)) {\n agg.set(key, value);\n } else {\n // TODO: Consider to add warning log\n }\n }\n return agg;\n }, new Map());\n\n // Because of the reverse() requirement, trunc must be done after map is created\n if (this._internalState.size > MAX_TRACE_STATE_ITEMS) {\n this._internalState = new Map(\n Array.from(this._internalState.entries())\n .reverse() // Use reverse same as original tracestate parse chain\n .slice(0, MAX_TRACE_STATE_ITEMS)\n );\n }\n }\n\n // @ts-expect-error TS6133 Accessed in tests only.\n private _keys(): string[] {\n return Array.from(this._internalState.keys()).reverse();\n }\n\n private _clone(): TraceStateImpl {\n const traceState = new TraceStateImpl();\n traceState._internalState = new Map(this._internalState);\n return traceState;\n }\n}\n"],"mappings":";;AAQA,MAAM,wBAAwB;AAC9B,MAAM,sBAAsB;AAC5B,MAAM,yBAAyB;AAC/B,MAAM,iCAAiC;;;;;;;;;;;;AAavC,IAAa,iBAAb,MAAa,eAAqC;CAGhD,YAAY,eAAwB;EAFpC,KAAQ,iCAAsC,IAAI,IAAI;EAGpD,IAAI,eAAe,KAAK,OAAO,aAAa;CAC9C;CAEA,IAAI,KAAa,OAA+B;EAG9C,MAAM,YAAY,KAAK,eAAe,IAAI,GAAG;EAO7C,IAAI,YAAY,KAAK,UAAU,CAAC,CAAC;EACjC,IAAI,OAAO,cAAc,UACvB,aAAa,MAAM,SAAS,UAAU;OACjC;GAIL,IAAI,KAAK,eAAe,QAAQ,uBAC9B,OAAO;GAET,aACE,IAAI,SAAS,MAAM,UAAU,KAAK,eAAe,OAAO,IAAI,IAAI;EACpE;EACA,IAAI,YAAY,qBACd,OAAO;EAGT,MAAM,aAAa,KAAK,OAAO;EAC/B,IAAI,WAAW,eAAe,IAAI,GAAG,GACnC,WAAW,eAAe,OAAO,GAAG;EAEtC,WAAW,eAAe,IAAI,KAAK,KAAK;EACxC,OAAO;CACT;CAEA,MAAM,KAA6B;EACjC,MAAM,aAAa,KAAK,OAAO;EAC/B,WAAW,eAAe,OAAO,GAAG;EACpC,OAAO;CACT;CAEA,IAAI,KAAiC;EACnC,OAAO,KAAK,eAAe,IAAI,GAAG;CACpC;CAEA,YAAoB;EAClB,OACE,MAAM,KAAK,KAAK,eAAe,KAAK,CAAC,CAAC,CAEnC,aAAa,KAAe,QAAQ;GACnC,IAAI,KAAK,MAAM,iCAAiC,KAAK,IAAI,GAAG,CAAC;GAC7D,OAAO;EACT,GAAG,CAAC,CAAC,CAAC,CACL,KAAK,sBAAsB;CAElC;CAEA,OAAe,eAAuB;EACpC,IAAI,cAAc,SAAS,qBAAqB;EAChD,KAAK,iBAAiB,cACnB,MAAM,sBAAsB,CAAC,CAE7B,aAAa,KAA0B,SAAiB;GACvD,MAAM,aAAa,KAAK,KAAK;GAC7B,MAAM,IAAI,WAAW,QAAQ,8BAA8B;GAC3D,IAAI,MAAM,IAAI;IACZ,MAAM,MAAM,WAAW,MAAM,GAAG,CAAC;IACjC,MAAM,QAAQ,WAAW,MAAM,IAAI,GAAG,KAAK,MAAM;IACjD,IAAIA,8BAAAA,YAAY,GAAG,KAAKC,8BAAAA,cAAc,KAAK,GACzC,IAAI,IAAI,KAAK,KAAK;GAItB;GACA,OAAO;EACT,mBAAG,IAAI,IAAI,CAAC;EAGd,IAAI,KAAK,eAAe,OAAO,uBAC7B,KAAK,iBAAiB,IAAI,IACxB,MAAM,KAAK,KAAK,eAAe,QAAQ,CAAC,CAAC,CACtC,QAAQ,CAAC,CACT,MAAM,GAAG,qBAAqB,CACnC;CAEJ;CAGA,QAA0B;EACxB,OAAO,MAAM,KAAK,KAAK,eAAe,KAAK,CAAC,CAAC,CAAC,QAAQ;CACxD;CAEA,SAAiC;EAC/B,MAAM,aAAa,IAAI,eAAe;EACtC,WAAW,iBAAiB,IAAI,IAAI,KAAK,cAAc;EACvD,OAAO;CACT;AACF"}