├── .commitlintrc.yml ├── .editorconfig ├── .eslintrc.js ├── .gitattributes ├── .github ├── CODEOWNERS └── workflows │ ├── codeql-analysis.yml │ ├── docs.yaml │ ├── lint.yaml │ ├── release-please.yml │ └── test.yaml ├── .gitignore ├── .markdownlint.json ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs ├── context.md ├── library-author.md ├── propagation.md ├── sdk-registration.md └── tracing.md ├── karma.base.js ├── karma.conf.js ├── karma.webpack.js ├── package.json ├── renovate.json ├── scripts └── version-update.js ├── src ├── api │ ├── context.ts │ ├── diag.ts │ ├── propagation.ts │ └── trace.ts ├── baggage │ ├── context-helpers.ts │ ├── internal │ │ ├── baggage-impl.ts │ │ └── symbol.ts │ ├── types.ts │ └── utils.ts ├── common │ ├── Attributes.ts │ ├── Exception.ts │ └── Time.ts ├── context │ ├── NoopContextManager.ts │ ├── context.ts │ └── types.ts ├── diag │ ├── ComponentLogger.ts │ ├── consoleLogger.ts │ ├── index.ts │ ├── internal │ │ ├── logLevelLogger.ts │ │ └── noopLogger.ts │ └── types.ts ├── index.ts ├── internal │ ├── global-utils.ts │ └── semver.ts ├── platform │ ├── browser │ │ ├── globalThis.ts │ │ └── index.ts │ ├── index.ts │ └── node │ │ ├── globalThis.ts │ │ └── index.ts ├── propagation │ ├── NoopTextMapPropagator.ts │ └── TextMapPropagator.ts └── trace │ ├── NonRecordingSpan.ts │ ├── NoopTracer.ts │ ├── NoopTracerProvider.ts │ ├── ProxyTracer.ts │ ├── ProxyTracerProvider.ts │ ├── Sampler.ts │ ├── SamplingResult.ts │ ├── SpanOptions.ts │ ├── attributes.ts │ ├── context-utils.ts │ ├── internal │ ├── tracestate-impl.ts │ ├── tracestate-validators.ts │ └── utils.ts │ ├── invalid-span-constants.ts │ ├── link.ts │ ├── span.ts │ ├── span_context.ts │ ├── span_kind.ts │ ├── spancontext-utils.ts │ ├── status.ts │ ├── trace_flags.ts │ ├── trace_state.ts │ ├── tracer.ts │ ├── tracer_options.ts │ └── tracer_provider.ts ├── test ├── api │ └── api.test.ts ├── baggage │ └── Baggage.test.ts ├── context │ └── NoopContextManager.test.ts ├── diag │ ├── ComponentLogger.test.ts │ ├── consoleLogger.test.ts │ ├── logLevel.test.ts │ └── logger.test.ts ├── index-webpack.ts ├── internal │ ├── global.test.ts │ ├── semver.test.ts │ └── version.test.ts ├── noop-implementations │ ├── noop-span.test.ts │ ├── noop-tracer-provider.test.ts │ └── noop-tracer.test.ts ├── proxy-implementations │ └── proxy-tracer.test.ts └── trace │ ├── spancontext-utils.test.ts │ ├── tracestate-validators.test.ts │ └── tracestate.test.ts ├── tsconfig.esm.json ├── tsconfig.json └── webpack.node-polyfills.js /.commitlintrc.yml: -------------------------------------------------------------------------------- 1 | extends: 2 | - '@commitlint/config-conventional' 3 | rules: 4 | header-max-length: [1, 'always', 72] 5 | type-enum: 6 | - 2 7 | - always 8 | - - ci 9 | - feat 10 | - fix 11 | - docs 12 | - style 13 | - refactor 14 | - perf 15 | - test 16 | - revert 17 | - chore 18 | help: | 19 | **Possible types**: 20 | `ci`: Changes to our CI configuration files and scripts (example scopes: Travis, Circle CI, BrowserStack, SauceLabs) 21 | `feat`: Adds a new feature. 22 | `fix`: Solves a bug. 23 | `docs`: Adds or alters documentation. (example scopes: readme, worker, code_of_conduct, contributors) 24 | `style`: Improves formatting, white-space. 25 | `refactor`: Rewrites code without feature, performance or bug changes. 26 | `perf`: Improves performance. 27 | `test`: Adds or modifies tests. (example scopes: functionals, unit-tests) 28 | `revert`: Changes that reverting other changes 29 | `chore`: No production code change. Updating grunt tasks etc; 30 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | "@typescript-eslint", 4 | "header", 5 | "node" 6 | ], 7 | extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], 8 | parser: "@typescript-eslint/parser", 9 | parserOptions: { 10 | "project": "./tsconfig.json" 11 | }, 12 | rules: { 13 | "quotes": [2, "single", { "avoidEscape": true }], 14 | "@typescript-eslint/no-floating-promises": 2, 15 | "@typescript-eslint/no-this-alias": "off", 16 | "brace-style": ["error", "1tbs"], 17 | "eqeqeq": [ 18 | "error", 19 | "smart" 20 | ], 21 | "prefer-rest-params": "off", 22 | "@typescript-eslint/naming-convention": [ 23 | "error", 24 | { 25 | "selector": "memberLike", 26 | "modifiers": ["private", "protected"], 27 | "format": ["camelCase"], 28 | "leadingUnderscore": "require" 29 | } 30 | ], 31 | "no-console": "error", 32 | "no-shadow": "off", 33 | "@typescript-eslint/no-shadow": ["warn"], 34 | "@typescript-eslint/no-unused-vars": ["error", {"argsIgnorePattern": "^_", "args": "after-used"}], 35 | "@typescript-eslint/no-inferrable-types": ["error", { ignoreProperties: true }], 36 | "@typescript-eslint/no-empty-function": ["off"], 37 | "@typescript-eslint/ban-types": ["warn", { 38 | "types": { 39 | "Function": null, 40 | } 41 | }], 42 | "@typescript-eslint/no-shadow": ["warn"], 43 | "arrow-parens": ["error", "as-needed"], 44 | "node/no-deprecated-api": ["warn"], 45 | "header/header": [2, "block", [{ 46 | pattern: / \* Copyright The OpenTelemetry Authors[\r\n]+ \*[\r\n]+ \* Licensed under the Apache License, Version 2\.0 \(the \"License\"\);[\r\n]+ \* you may not use this file except in compliance with the License\.[\r\n]+ \* You may obtain a copy of the License at[\r\n]+ \*[\r\n]+ \* https:\/\/www\.apache\.org\/licenses\/LICENSE-2\.0[\r\n]+ \*[\r\n]+ \* Unless required by applicable law or agreed to in writing, software[\r\n]+ \* distributed under the License is distributed on an \"AS IS\" BASIS,[\r\n]+ \* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.[\r\n]+ \* See the License for the specific language governing permissions and[\r\n]+ \* limitations under the License\./gm, 47 | template: 48 | `\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the "License");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ` 49 | }]] 50 | }, 51 | overrides: [ 52 | { 53 | "files": ["test/**/*.ts"], 54 | "rules": { 55 | "no-empty": "off", 56 | "@typescript-eslint/ban-ts-ignore": "off", 57 | "@typescript-eslint/no-empty-function": "off", 58 | "@typescript-eslint/no-explicit-any": "off", 59 | "@typescript-eslint/no-floating-promises": 1, 60 | "@typescript-eslint/no-unused-vars": "off", 61 | "@typescript-eslint/no-var-requires": "off", 62 | "@typescript-eslint/no-shadow": ["off"], 63 | "@typescript-eslint/no-floating-promises": ["off"], 64 | "@typescript-eslint/no-non-null-assertion": ["off"], 65 | "@typescript-eslint/explicit-module-boundary-types": ["off"] 66 | } 67 | } 68 | ] 69 | }; 70 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ## This .gitattributes file automatically formats the EOL character in certain filetypes within the repository 2 | 3 | ## Source code 4 | # JavaScript, TypeScript, c, and h source files 5 | *.js text eol=lf 6 | *.ts text eol=lf 7 | *.h text eol=lf diff=cpp 8 | *.c text eol=lf diff=cpp 9 | 10 | # Shell scripts 11 | *.sh text eol=lf 12 | *.bash text eol=lf 13 | 14 | # Windows batch and PowerShell scripts 15 | *.bat text eol=crlf 16 | *.cmd text eol=crlf 17 | *.ps1 text eol=crlf 18 | 19 | ##### Other file types ##### 20 | 21 | ## Text files and documentation 22 | *.txt text 23 | README* text 24 | RELEASING* text 25 | CHANGELOG* text 26 | CONTRIBUTING* text 27 | INSTALL* text 28 | LICENSE* text 29 | 30 | ## Non-text documentation 31 | *.html text diff=html 32 | *.pdf binary 33 | *.json text eol=lf 34 | *.rtf binary 35 | 36 | ## Git Properties 37 | .gitignore text 38 | .gitmodules text 39 | .gitattributes text 40 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | ##################################################### 2 | # 3 | # List of approvers for OpenTelemetry JS SDK 4 | # 5 | ##################################################### 6 | # 7 | # Learn about membership in OpenTelemetry community: 8 | # https://github.com/open-telemetry/community/blob/master/community-membership.md 9 | # 10 | # 11 | # Learn about CODEOWNERS file format: 12 | # https://help.github.com/en/articles/about-code-owners 13 | # 14 | 15 | * @open-telemetry/javascript-approvers 16 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | # ┌───────────── minute (0 - 59) 7 | # │ ┌───────────── hour (0 - 23) 8 | # │ │ ┌───────────── day of the month (1 - 31) 9 | # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) 10 | # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) 11 | # │ │ │ │ │ 12 | # │ │ │ │ │ 13 | # │ │ │ │ │ 14 | # * * * * * 15 | - cron: '30 1 * * *' 16 | 17 | jobs: 18 | CodeQL-Build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v2 24 | 25 | - name: Initialize CodeQL 26 | uses: github/codeql-action/init@v1 27 | with: 28 | languages: javascript 29 | 30 | - name: Autobuild 31 | uses: github/codeql-action/autobuild@v1 32 | 33 | - name: Perform CodeQL Analysis 34 | uses: github/codeql-action/analyze@v1 35 | -------------------------------------------------------------------------------- /.github/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy API Documentation 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build-and-deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 🛎️ 12 | uses: actions/checkout@v2 13 | 14 | - name: Install root dependencies 15 | run: npm install --ignore-scripts 16 | 17 | - name: Build 🔧 18 | run: | 19 | npm run compile 20 | npm run docs 21 | 22 | - name: Deploy 🚀 23 | uses: JamesIves/github-pages-deploy-action@releases/v3 24 | with: 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | BRANCH: gh-pages # The branch the action should deploy to. 27 | FOLDER: docs/out # The folder the action should deploy. 28 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Lint markdown files 17 | uses: docker://avtodev/markdown-lint:v1 18 | with: 19 | args: "./**/*.md -i ./CHANGELOG.md" 20 | 21 | - name: Install dependencies 22 | run: npm install 23 | 24 | - name: Build 🔧 25 | run: npm run compile 26 | 27 | - name: Lint 28 | run: npm run lint 29 | 30 | - name: Check for Circular Dependencies 31 | run: npm run cycle-check 32 | 33 | - name: Generate Documentation 📜 34 | run: npm run docs 35 | 36 | - name: Test Docs 37 | run: npm run docs:test 38 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | name: release-please 6 | jobs: 7 | release-please: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: GoogleCloudPlatform/release-please-action@v2 11 | id: release 12 | with: 13 | token: ${{secrets.RELEASE_PR_TOKEN}} 14 | release-type: node 15 | package-name: "@opentelemetry/api" 16 | # The logic below handles the npm publication: 17 | - uses: actions/checkout@v2 18 | # these if statements ensure that a publication only occurs when 19 | # a new release is created: 20 | if: ${{ steps.release.outputs.release_created }} 21 | - uses: actions/setup-node@v1 22 | with: 23 | node-version: 14 24 | registry-url: 'https://registry.npmjs.org' 25 | if: ${{ steps.release.outputs.release_created }} 26 | - run: npm install 27 | if: ${{ steps.release.outputs.release_created }} 28 | - run: npm run compile 29 | if: ${{ steps.release.outputs.release_created }} 30 | - run: npm publish --tag next 31 | env: 32 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 33 | if: ${{ steps.release.outputs.release_created }} 34 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Unit Tests 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | 8 | jobs: 9 | unit-test: 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | node: ["8", "10", "12", "14", "16"] 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v2 18 | 19 | - name: Setup Node 20 | uses: actions/setup-node@v2 21 | with: 22 | node-version: ${{ matrix.node }} 23 | 24 | - name: Install Dependencies 25 | run: npm install 26 | 27 | - name: Compile 🔧 28 | run: npm run compile 29 | 30 | - name: Unit tests 31 | run: npm run test 32 | 33 | - name: Report Coverage 34 | run: npm run codecov 35 | if: ${{ matrix.node == '14' }} 36 | 37 | browser-tests: 38 | runs-on: ubuntu-latest 39 | container: 40 | image: circleci/node:12-browsers 41 | steps: 42 | - name: Permission Setup 43 | run: sudo chmod -R 777 /github /__w 44 | 45 | - name: Checkout 46 | uses: actions/checkout@v2 47 | 48 | - name: Install Dependencies 49 | run: npm install 50 | 51 | - name: Compile 🔧 52 | run: npm run compile 53 | 54 | - name: Unit tests 55 | run: npm run test:browser 56 | 57 | - name: Report Coverage 58 | run: npm run codecov:browser 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # version.ts file is autogenerated at compile time 2 | src/version.ts 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | build/ 39 | 40 | # TypeScript v1 declaration files 41 | typings/ 42 | 43 | # Optional npm cache directory 44 | .npm 45 | 46 | # Optional eslint cache 47 | .eslintcache 48 | 49 | # Optional REPL history 50 | .node_repl_history 51 | 52 | # Output of 'npm pack' 53 | *.tgz 54 | 55 | # Yarn Integrity file 56 | .yarn-integrity 57 | 58 | # dotenv environment variables file 59 | .env 60 | 61 | # next.js build output 62 | .next 63 | 64 | # lock files 65 | yarn.lock 66 | package-lock.json 67 | 68 | # generated gh-pages files 69 | docs/out 70 | 71 | .nyc_output 72 | 73 | #lerna 74 | .changelog 75 | package.json.lerna_backup 76 | 77 | # OS generated files 78 | .DS_Store 79 | 80 | # VsCode configs 81 | .vscode/ 82 | 83 | #Visual Studio 84 | .vs/ 85 | 86 | #IDEA 87 | .idea 88 | *.iml 89 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD013": false, 3 | "MD024": false, 4 | "MD033": false, 5 | "MD041": false, 6 | "MD026": false 7 | } 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /coverage 3 | /doc 4 | /test 5 | -------------------------------------------------------------------------------- /docs/library-author.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry for Library Authors 2 | 3 | TODO 4 | -------------------------------------------------------------------------------- /docs/propagation.md: -------------------------------------------------------------------------------- 1 | # Propagation 2 | 3 | TODO 4 | 5 | _Propagation API reference: _ 6 | -------------------------------------------------------------------------------- /docs/sdk-registration.md: -------------------------------------------------------------------------------- 1 | # SDK Registration Methods 2 | 3 | These methods are used to register a compatible OpenTelemetry SDK. Some SDKs like the [OpenTelemetry JS SDK][opentelemetry-js] provide convenience methods which call these registration methods for you. 4 | 5 | - [Trace API Documentation][trace-api-docs] 6 | - [Propagation API Documentation][propagation-api-docs] 7 | - [Context API Documentation][context-api-docs] 8 | 9 | ```javascript 10 | const api = require("@opentelemetry/api"); 11 | 12 | /* Register a global TracerProvider */ 13 | api.trace.setGlobalTracerProvider(tracerProvider); 14 | /* returns tracerProvider (no-op if a working provider has not been initialized) */ 15 | api.trace.getTracerProvider(); 16 | /* returns a tracer from the registered global tracer provider (no-op if a working provider has not been initialized) */ 17 | api.trace.getTracer(name, version); 18 | 19 | /* Register a global Propagator */ 20 | api.propagation.setGlobalPropagator(httpTraceContextPropagator); 21 | 22 | /* Register a global Context Manager */ 23 | api.context.setGlobalContextManager(asyncHooksContextManager); 24 | ``` 25 | 26 | [trace-api-docs]: https://open-telemetry.github.io/opentelemetry-js-api/classes/traceapi.html 27 | [propagation-api-docs]: https://open-telemetry.github.io/opentelemetry-js-api/classes/propagationapi.html 28 | [context-api-docs]: https://open-telemetry.github.io/opentelemetry-js-api/classes/contextapi.html 29 | -------------------------------------------------------------------------------- /karma.base.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | module.exports = { 18 | listenAddress: 'localhost', 19 | hostname: 'localhost', 20 | browsers: ['ChromeHeadless'], 21 | frameworks: ['mocha'], 22 | coverageIstanbulReporter: { 23 | reports: ['html', 'json'], 24 | dir: '.nyc_output', 25 | fixWebpackSourcePaths: true 26 | }, 27 | reporters: ['spec', 'coverage-istanbul'], 28 | files: ['test/index-webpack.ts'], 29 | preprocessors: { 'test/index-webpack.ts': ['webpack'] }, 30 | webpackMiddleware: { noInfo: true } 31 | }; 32 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | const karmaWebpackConfig = require('./karma.webpack'); 2 | const karmaBaseConfig = require('./karma.base'); 3 | 4 | module.exports = (config) => { 5 | config.set(Object.assign({}, karmaBaseConfig, { 6 | webpack: karmaWebpackConfig 7 | })) 8 | }; -------------------------------------------------------------------------------- /karma.webpack.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const webpackNodePolyfills = require('./webpack.node-polyfills.js'); 18 | 19 | // This is the webpack configuration for browser Karma tests with coverage. 20 | module.exports = { 21 | mode: 'development', 22 | target: 'web', 23 | output: { filename: 'bundle.js' }, 24 | resolve: { extensions: ['.ts', '.js'] }, 25 | devtool: 'inline-source-map', 26 | module: { 27 | rules: [ 28 | { test: /\.ts$/, use: 'ts-loader' }, 29 | { 30 | enforce: 'post', 31 | exclude: /(node_modules|\.test\.[tj]sx?$)/, 32 | test: /\.ts$/, 33 | use: { 34 | loader: 'istanbul-instrumenter-loader', 35 | options: { esModules: true } 36 | } 37 | }, 38 | // This setting configures Node polyfills for the browser that will be 39 | // added to the webpack bundle for Karma tests. 40 | { parser: { node: webpackNodePolyfills } } 41 | ] 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@opentelemetry/api", 3 | "version": "1.2.0", 4 | "description": "Public API for OpenTelemetry", 5 | "main": "build/src/index.js", 6 | "module": "build/esm/index.js", 7 | "types": "build/src/index.d.ts", 8 | "browser": { 9 | "./src/platform/index.ts": "./src/platform/browser/index.ts", 10 | "./build/esm/platform/index.js": "./build/esm/platform/browser/index.js", 11 | "./build/src/platform/index.js": "./build/src/platform/browser/index.js" 12 | }, 13 | "repository": "https://github.com/open-telemetry/opentelemetry-js-api.git", 14 | "scripts": { 15 | "clean": "tsc --build --clean tsconfig.json tsconfig.esm.json", 16 | "codecov:browser": "nyc report --reporter=json && codecov -f coverage/*.json -p .", 17 | "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p .", 18 | "precompile": "npm run version", 19 | "compile": "tsc --build tsconfig.json tsconfig.esm.json", 20 | "docs": "typedoc", 21 | "docs:deploy": "gh-pages --dist docs/out", 22 | "docs:test": "linkinator docs/out --silent && linkinator docs/*.md *.md --markdown --silent", 23 | "lint:fix": "eslint src test --ext .ts --fix", 24 | "lint": "eslint src test --ext .ts", 25 | "test:browser": "nyc karma start --single-run", 26 | "test": "nyc ts-mocha -p tsconfig.json test/**/*.test.ts", 27 | "cycle-check": "dpdm --exit-code circular:1 src/index.ts", 28 | "version": "node scripts/version-update.js", 29 | "prewatch": "npm run version", 30 | "watch": "tsc --build --watch" 31 | }, 32 | "keywords": [ 33 | "opentelemetry", 34 | "nodejs", 35 | "browser", 36 | "tracing", 37 | "profiling", 38 | "stats", 39 | "monitoring" 40 | ], 41 | "author": "OpenTelemetry Authors", 42 | "license": "Apache-2.0", 43 | "engines": { 44 | "node": ">=8.0.0" 45 | }, 46 | "files": [ 47 | "build/esm/**/*.js", 48 | "build/esm/**/*.js.map", 49 | "build/esm/**/*.d.ts", 50 | "build/src/**/*.js", 51 | "build/src/**/*.js.map", 52 | "build/src/**/*.d.ts", 53 | "LICENSE", 54 | "README.md" 55 | ], 56 | "publishConfig": { 57 | "access": "public" 58 | }, 59 | "devDependencies": { 60 | "@types/mocha": "8.2.2", 61 | "@types/node": "14.17.4", 62 | "@types/sinon": "10.0.2", 63 | "@types/webpack-env": "1.16.0", 64 | "@typescript-eslint/eslint-plugin": "5.0.0", 65 | "@typescript-eslint/parser": "5.0.0", 66 | "codecov": "3.8.2", 67 | "dpdm": "3.7.1", 68 | "eslint": "7.32.0", 69 | "eslint-plugin-header": "3.1.1", 70 | "eslint-plugin-node": "11.1.0", 71 | "gh-pages": "3.2.0", 72 | "istanbul-instrumenter-loader": "3.0.1", 73 | "karma": "5.2.3", 74 | "karma-chrome-launcher": "3.1.0", 75 | "karma-coverage-istanbul-reporter": "3.0.3", 76 | "karma-mocha": "2.0.1", 77 | "karma-spec-reporter": "0.0.32", 78 | "karma-webpack": "4.0.2", 79 | "lerna-changelog": "1.0.1", 80 | "linkinator": "2.13.6", 81 | "mocha": "7.2.0", 82 | "nyc": "15.1.0", 83 | "sinon": "11.1.1", 84 | "ts-loader": "8.2.0", 85 | "ts-mocha": "8.0.0", 86 | "typedoc": "0.21.2", 87 | "typescript": "4.3.5", 88 | "webpack": "4.46.0" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "packageRules": [ 6 | { 7 | "groupName": "all non-major dependencies", 8 | "updateTypes": ["patch", "minor"], 9 | "groupSlug": "all-minor-patch" 10 | } 11 | ], 12 | "ignoreDeps": [ 13 | "gcp-metadata", 14 | "got", 15 | "mocha" 16 | ], 17 | "assignees": [ 18 | "@dyladan", 19 | "@vmarchaud" 20 | ], 21 | "schedule": [ 22 | "before 3am on Friday" 23 | ], 24 | "labels": ["dependencies"] 25 | } 26 | -------------------------------------------------------------------------------- /scripts/version-update.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const fs = require('fs'); 18 | const os = require('os'); 19 | const path = require('path'); 20 | 21 | const appRoot = process.cwd(); 22 | 23 | const packageJsonUrl = path.resolve(`${appRoot}/package.json`); 24 | const pjson = require(packageJsonUrl); 25 | 26 | const content = `/* 27 | * Copyright The OpenTelemetry Authors 28 | * 29 | * Licensed under the Apache License, Version 2.0 (the "License"); 30 | * you may not use this file except in compliance with the License. 31 | * You may obtain a copy of the License at 32 | * 33 | * https://www.apache.org/licenses/LICENSE-2.0 34 | * 35 | * Unless required by applicable law or agreed to in writing, software 36 | * distributed under the License is distributed on an "AS IS" BASIS, 37 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 38 | * See the License for the specific language governing permissions and 39 | * limitations under the License. 40 | */ 41 | 42 | // this is autogenerated file, see scripts/version-update.js 43 | export const VERSION = '${pjson.version}'; 44 | `; 45 | 46 | const fileUrl = path.join(appRoot, "src", "version.ts") 47 | 48 | fs.writeFileSync(fileUrl, content); -------------------------------------------------------------------------------- /src/api/context.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { NoopContextManager } from '../context/NoopContextManager'; 18 | import { Context, ContextManager } from '../context/types'; 19 | import { 20 | getGlobal, 21 | registerGlobal, 22 | unregisterGlobal, 23 | } from '../internal/global-utils'; 24 | import { DiagAPI } from './diag'; 25 | 26 | const API_NAME = 'context'; 27 | const NOOP_CONTEXT_MANAGER = new NoopContextManager(); 28 | 29 | /** 30 | * Singleton object which represents the entry point to the OpenTelemetry Context API 31 | */ 32 | export class ContextAPI { 33 | private static _instance?: ContextAPI; 34 | 35 | /** Empty private constructor prevents end users from constructing a new instance of the API */ 36 | private constructor() {} 37 | 38 | /** Get the singleton instance of the Context API */ 39 | public static getInstance(): ContextAPI { 40 | if (!this._instance) { 41 | this._instance = new ContextAPI(); 42 | } 43 | 44 | return this._instance; 45 | } 46 | 47 | /** 48 | * Set the current context manager. 49 | * 50 | * @returns true if the context manager was successfully registered, else false 51 | */ 52 | public setGlobalContextManager(contextManager: ContextManager): boolean { 53 | return registerGlobal(API_NAME, contextManager, DiagAPI.instance()); 54 | } 55 | 56 | /** 57 | * Get the currently active context 58 | */ 59 | public active(): Context { 60 | return this._getContextManager().active(); 61 | } 62 | 63 | /** 64 | * Execute a function with an active context 65 | * 66 | * @param context context to be active during function execution 67 | * @param fn function to execute in a context 68 | * @param thisArg optional receiver to be used for calling fn 69 | * @param args optional arguments forwarded to fn 70 | */ 71 | public with ReturnType>( 72 | context: Context, 73 | fn: F, 74 | thisArg?: ThisParameterType, 75 | ...args: A 76 | ): ReturnType { 77 | return this._getContextManager().with(context, fn, thisArg, ...args); 78 | } 79 | 80 | /** 81 | * Bind a context to a target function or event emitter 82 | * 83 | * @param context context to bind to the event emitter or function. Defaults to the currently active context 84 | * @param target function or event emitter to bind 85 | */ 86 | public bind(context: Context, target: T): T { 87 | return this._getContextManager().bind(context, target); 88 | } 89 | 90 | private _getContextManager(): ContextManager { 91 | return getGlobal(API_NAME) || NOOP_CONTEXT_MANAGER; 92 | } 93 | 94 | /** Disable and remove the global context manager */ 95 | public disable() { 96 | this._getContextManager().disable(); 97 | unregisterGlobal(API_NAME, DiagAPI.instance()); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/api/diag.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { DiagComponentLogger } from '../diag/ComponentLogger'; 18 | import { createLogLevelDiagLogger } from '../diag/internal/logLevelLogger'; 19 | import { 20 | ComponentLoggerOptions, 21 | DiagLogFunction, 22 | DiagLogger, 23 | DiagLogLevel, 24 | } from '../diag/types'; 25 | import { 26 | getGlobal, 27 | registerGlobal, 28 | unregisterGlobal, 29 | } from '../internal/global-utils'; 30 | 31 | const API_NAME = 'diag'; 32 | 33 | /** 34 | * Singleton object which represents the entry point to the OpenTelemetry internal 35 | * diagnostic API 36 | */ 37 | export class DiagAPI implements DiagLogger { 38 | private static _instance?: DiagAPI; 39 | 40 | /** Get the singleton instance of the DiagAPI API */ 41 | public static instance(): DiagAPI { 42 | if (!this._instance) { 43 | this._instance = new DiagAPI(); 44 | } 45 | 46 | return this._instance; 47 | } 48 | 49 | /** 50 | * Private internal constructor 51 | * @private 52 | */ 53 | private constructor() { 54 | function _logProxy(funcName: keyof DiagLogger): DiagLogFunction { 55 | return function (...args) { 56 | const logger = getGlobal('diag'); 57 | // shortcut if logger not set 58 | if (!logger) return; 59 | return logger[funcName](...args); 60 | }; 61 | } 62 | 63 | // Using self local variable for minification purposes as 'this' cannot be minified 64 | const self = this; 65 | 66 | // DiagAPI specific functions 67 | 68 | self.setLogger = ( 69 | logger: DiagLogger, 70 | logLevel: DiagLogLevel = DiagLogLevel.INFO 71 | ) => { 72 | if (logger === self) { 73 | // There isn't much we can do here. 74 | // Logging to the console might break the user application. 75 | // Try to log to self. If a logger was previously registered it will receive the log. 76 | const err = new Error( 77 | 'Cannot use diag as the logger for itself. Please use a DiagLogger implementation like ConsoleDiagLogger or a custom implementation' 78 | ); 79 | self.error(err.stack ?? err.message); 80 | return false; 81 | } 82 | 83 | const oldLogger = getGlobal('diag'); 84 | const newLogger = createLogLevelDiagLogger(logLevel, logger); 85 | // There already is an logger registered. We'll let it know before overwriting it. 86 | if (oldLogger) { 87 | const stack = new Error().stack ?? ''; 88 | oldLogger.warn(`Current logger will be overwritten from ${stack}`); 89 | newLogger.warn( 90 | `Current logger will overwrite one already registered from ${stack}` 91 | ); 92 | } 93 | 94 | return registerGlobal('diag', newLogger, self, true); 95 | }; 96 | 97 | self.disable = () => { 98 | unregisterGlobal(API_NAME, self); 99 | }; 100 | 101 | self.createComponentLogger = (options: ComponentLoggerOptions) => { 102 | return new DiagComponentLogger(options); 103 | }; 104 | 105 | self.verbose = _logProxy('verbose'); 106 | self.debug = _logProxy('debug'); 107 | self.info = _logProxy('info'); 108 | self.warn = _logProxy('warn'); 109 | self.error = _logProxy('error'); 110 | } 111 | 112 | /** 113 | * Set the global DiagLogger and DiagLogLevel. 114 | * If a global diag logger is already set, this will override it. 115 | * 116 | * @param logger - [Optional] The DiagLogger instance to set as the default logger. 117 | * @param logLevel - [Optional] The DiagLogLevel used to filter logs sent to the logger. If not provided it will default to INFO. 118 | * @returns true if the logger was successfully registered, else false 119 | */ 120 | public setLogger!: (logger: DiagLogger, logLevel?: DiagLogLevel) => boolean; 121 | /** 122 | * 123 | */ 124 | public createComponentLogger!: ( 125 | options: ComponentLoggerOptions 126 | ) => DiagLogger; 127 | 128 | // DiagLogger implementation 129 | public verbose!: DiagLogFunction; 130 | public debug!: DiagLogFunction; 131 | public info!: DiagLogFunction; 132 | public warn!: DiagLogFunction; 133 | public error!: DiagLogFunction; 134 | 135 | /** 136 | * Unregister the global logger and return to Noop 137 | */ 138 | public disable!: () => void; 139 | } 140 | -------------------------------------------------------------------------------- /src/api/propagation.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Context } from '../context/types'; 18 | import { 19 | getGlobal, 20 | registerGlobal, 21 | unregisterGlobal, 22 | } from '../internal/global-utils'; 23 | import { NoopTextMapPropagator } from '../propagation/NoopTextMapPropagator'; 24 | import { 25 | defaultTextMapGetter, 26 | defaultTextMapSetter, 27 | TextMapGetter, 28 | TextMapPropagator, 29 | TextMapSetter, 30 | } from '../propagation/TextMapPropagator'; 31 | import { 32 | getBaggage, 33 | setBaggage, 34 | deleteBaggage, 35 | } from '../baggage/context-helpers'; 36 | import { createBaggage } from '../baggage/utils'; 37 | import { DiagAPI } from './diag'; 38 | 39 | const API_NAME = 'propagation'; 40 | const NOOP_TEXT_MAP_PROPAGATOR = new NoopTextMapPropagator(); 41 | 42 | /** 43 | * Singleton object which represents the entry point to the OpenTelemetry Propagation API 44 | */ 45 | export class PropagationAPI { 46 | private static _instance?: PropagationAPI; 47 | 48 | /** Empty private constructor prevents end users from constructing a new instance of the API */ 49 | private constructor() {} 50 | 51 | /** Get the singleton instance of the Propagator API */ 52 | public static getInstance(): PropagationAPI { 53 | if (!this._instance) { 54 | this._instance = new PropagationAPI(); 55 | } 56 | 57 | return this._instance; 58 | } 59 | 60 | /** 61 | * Set the current propagator. 62 | * 63 | * @returns true if the propagator was successfully registered, else false 64 | */ 65 | public setGlobalPropagator(propagator: TextMapPropagator): boolean { 66 | return registerGlobal(API_NAME, propagator, DiagAPI.instance()); 67 | } 68 | 69 | /** 70 | * Inject context into a carrier to be propagated inter-process 71 | * 72 | * @param context Context carrying tracing data to inject 73 | * @param carrier carrier to inject context into 74 | * @param setter Function used to set values on the carrier 75 | */ 76 | public inject( 77 | context: Context, 78 | carrier: Carrier, 79 | setter: TextMapSetter = defaultTextMapSetter 80 | ): void { 81 | return this._getGlobalPropagator().inject(context, carrier, setter); 82 | } 83 | 84 | /** 85 | * Extract context from a carrier 86 | * 87 | * @param context Context which the newly created context will inherit from 88 | * @param carrier Carrier to extract context from 89 | * @param getter Function used to extract keys from a carrier 90 | */ 91 | public extract( 92 | context: Context, 93 | carrier: Carrier, 94 | getter: TextMapGetter = defaultTextMapGetter 95 | ): Context { 96 | return this._getGlobalPropagator().extract(context, carrier, getter); 97 | } 98 | 99 | /** 100 | * Return a list of all fields which may be used by the propagator. 101 | */ 102 | public fields(): string[] { 103 | return this._getGlobalPropagator().fields(); 104 | } 105 | 106 | /** Remove the global propagator */ 107 | public disable() { 108 | unregisterGlobal(API_NAME, DiagAPI.instance()); 109 | } 110 | 111 | public createBaggage = createBaggage; 112 | 113 | public getBaggage = getBaggage; 114 | 115 | public setBaggage = setBaggage; 116 | 117 | public deleteBaggage = deleteBaggage; 118 | 119 | private _getGlobalPropagator(): TextMapPropagator { 120 | return getGlobal(API_NAME) || NOOP_TEXT_MAP_PROPAGATOR; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/api/trace.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { 18 | getGlobal, 19 | registerGlobal, 20 | unregisterGlobal, 21 | } from '../internal/global-utils'; 22 | import { ProxyTracerProvider } from '../trace/ProxyTracerProvider'; 23 | import { 24 | isSpanContextValid, 25 | wrapSpanContext, 26 | } from '../trace/spancontext-utils'; 27 | import { Tracer } from '../trace/tracer'; 28 | import { TracerProvider } from '../trace/tracer_provider'; 29 | import { 30 | deleteSpan, 31 | getActiveSpan, 32 | getSpan, 33 | getSpanContext, 34 | setSpan, 35 | setSpanContext, 36 | } from '../trace/context-utils'; 37 | import { DiagAPI } from './diag'; 38 | 39 | const API_NAME = 'trace'; 40 | 41 | /** 42 | * Singleton object which represents the entry point to the OpenTelemetry Tracing API 43 | */ 44 | export class TraceAPI { 45 | private static _instance?: TraceAPI; 46 | 47 | private _proxyTracerProvider = new ProxyTracerProvider(); 48 | 49 | /** Empty private constructor prevents end users from constructing a new instance of the API */ 50 | private constructor() {} 51 | 52 | /** Get the singleton instance of the Trace API */ 53 | public static getInstance(): TraceAPI { 54 | if (!this._instance) { 55 | this._instance = new TraceAPI(); 56 | } 57 | 58 | return this._instance; 59 | } 60 | 61 | /** 62 | * Set the current global tracer. 63 | * 64 | * @returns true if the tracer provider was successfully registered, else false 65 | */ 66 | public setGlobalTracerProvider(provider: TracerProvider): boolean { 67 | const success = registerGlobal( 68 | API_NAME, 69 | this._proxyTracerProvider, 70 | DiagAPI.instance() 71 | ); 72 | if (success) { 73 | this._proxyTracerProvider.setDelegate(provider); 74 | } 75 | return success; 76 | } 77 | 78 | /** 79 | * Returns the global tracer provider. 80 | */ 81 | public getTracerProvider(): TracerProvider { 82 | return getGlobal(API_NAME) || this._proxyTracerProvider; 83 | } 84 | 85 | /** 86 | * Returns a tracer from the global tracer provider. 87 | */ 88 | public getTracer(name: string, version?: string): Tracer { 89 | return this.getTracerProvider().getTracer(name, version); 90 | } 91 | 92 | /** Remove the global tracer provider */ 93 | public disable() { 94 | unregisterGlobal(API_NAME, DiagAPI.instance()); 95 | this._proxyTracerProvider = new ProxyTracerProvider(); 96 | } 97 | 98 | public wrapSpanContext = wrapSpanContext; 99 | 100 | public isSpanContextValid = isSpanContextValid; 101 | 102 | public deleteSpan = deleteSpan; 103 | 104 | public getSpan = getSpan; 105 | 106 | public getActiveSpan = getActiveSpan; 107 | 108 | public getSpanContext = getSpanContext; 109 | 110 | public setSpan = setSpan; 111 | 112 | public setSpanContext = setSpanContext; 113 | } 114 | -------------------------------------------------------------------------------- /src/baggage/context-helpers.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { createContextKey } from '../context/context'; 18 | import { Context } from '../context/types'; 19 | import { Baggage } from './types'; 20 | 21 | /** 22 | * Baggage key 23 | */ 24 | const BAGGAGE_KEY = createContextKey('OpenTelemetry Baggage Key'); 25 | 26 | /** 27 | * Retrieve the current baggage from the given context 28 | * 29 | * @param {Context} Context that manage all context values 30 | * @returns {Baggage} Extracted baggage from the context 31 | */ 32 | export function getBaggage(context: Context): Baggage | undefined { 33 | return (context.getValue(BAGGAGE_KEY) as Baggage) || undefined; 34 | } 35 | 36 | /** 37 | * Store a baggage in the given context 38 | * 39 | * @param {Context} Context that manage all context values 40 | * @param {Baggage} baggage that will be set in the actual context 41 | */ 42 | export function setBaggage(context: Context, baggage: Baggage): Context { 43 | return context.setValue(BAGGAGE_KEY, baggage); 44 | } 45 | 46 | /** 47 | * Delete the baggage stored in the given context 48 | * 49 | * @param {Context} Context that manage all context values 50 | */ 51 | export function deleteBaggage(context: Context): Context { 52 | return context.deleteValue(BAGGAGE_KEY); 53 | } 54 | -------------------------------------------------------------------------------- /src/baggage/internal/baggage-impl.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import type { Baggage, BaggageEntry } from '../types'; 18 | 19 | export class BaggageImpl implements Baggage { 20 | private _entries: Map; 21 | 22 | constructor(entries?: Map) { 23 | this._entries = entries ? new Map(entries) : new Map(); 24 | } 25 | 26 | getEntry(key: string): BaggageEntry | undefined { 27 | const entry = this._entries.get(key); 28 | if (!entry) { 29 | return undefined; 30 | } 31 | 32 | return Object.assign({}, entry); 33 | } 34 | 35 | getAllEntries(): [string, BaggageEntry][] { 36 | return Array.from(this._entries.entries()).map(([k, v]) => [k, v]); 37 | } 38 | 39 | setEntry(key: string, entry: BaggageEntry): BaggageImpl { 40 | const newBaggage = new BaggageImpl(this._entries); 41 | newBaggage._entries.set(key, entry); 42 | return newBaggage; 43 | } 44 | 45 | removeEntry(key: string): BaggageImpl { 46 | const newBaggage = new BaggageImpl(this._entries); 47 | newBaggage._entries.delete(key); 48 | return newBaggage; 49 | } 50 | 51 | removeEntries(...keys: string[]): BaggageImpl { 52 | const newBaggage = new BaggageImpl(this._entries); 53 | for (const key of keys) { 54 | newBaggage._entries.delete(key); 55 | } 56 | return newBaggage; 57 | } 58 | 59 | clear(): BaggageImpl { 60 | return new BaggageImpl(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/baggage/internal/symbol.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Symbol used to make BaggageEntryMetadata an opaque type 19 | */ 20 | export const baggageEntryMetadataSymbol = Symbol('BaggageEntryMetadata'); 21 | -------------------------------------------------------------------------------- /src/baggage/types.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { baggageEntryMetadataSymbol } from './internal/symbol'; 18 | 19 | /* 20 | * Copyright The OpenTelemetry Authors 21 | * 22 | * Licensed under the Apache License, Version 2.0 (the "License"); 23 | * you may not use this file except in compliance with the License. 24 | * You may obtain a copy of the License at 25 | * 26 | * https://www.apache.org/licenses/LICENSE-2.0 27 | * 28 | * Unless required by applicable law or agreed to in writing, software 29 | * distributed under the License is distributed on an "AS IS" BASIS, 30 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | * See the License for the specific language governing permissions and 32 | * limitations under the License. 33 | */ 34 | 35 | export interface BaggageEntry { 36 | /** `String` value of the `BaggageEntry`. */ 37 | value: string; 38 | /** 39 | * Metadata is an optional string property defined by the W3C baggage specification. 40 | * It currently has no special meaning defined by the specification. 41 | */ 42 | metadata?: BaggageEntryMetadata; 43 | } 44 | 45 | /** 46 | * Serializable Metadata defined by the W3C baggage specification. 47 | * It currently has no special meaning defined by the OpenTelemetry or W3C. 48 | */ 49 | export type BaggageEntryMetadata = { toString(): string } & { 50 | __TYPE__: typeof baggageEntryMetadataSymbol; 51 | }; 52 | 53 | /** 54 | * Baggage represents collection of key-value pairs with optional metadata. 55 | * Each key of Baggage is associated with exactly one value. 56 | * Baggage may be used to annotate and enrich telemetry data. 57 | */ 58 | export interface Baggage { 59 | /** 60 | * Get an entry from Baggage if it exists 61 | * 62 | * @param key The key which identifies the BaggageEntry 63 | */ 64 | getEntry(key: string): BaggageEntry | undefined; 65 | 66 | /** 67 | * Get a list of all entries in the Baggage 68 | */ 69 | getAllEntries(): [string, BaggageEntry][]; 70 | 71 | /** 72 | * Returns a new baggage with the entries from the current bag and the specified entry 73 | * 74 | * @param key string which identifies the baggage entry 75 | * @param entry BaggageEntry for the given key 76 | */ 77 | setEntry(key: string, entry: BaggageEntry): Baggage; 78 | 79 | /** 80 | * Returns a new baggage with the entries from the current bag except the removed entry 81 | * 82 | * @param key key identifying the entry to be removed 83 | */ 84 | removeEntry(key: string): Baggage; 85 | 86 | /** 87 | * Returns a new baggage with the entries from the current bag except the removed entries 88 | * 89 | * @param key keys identifying the entries to be removed 90 | */ 91 | removeEntries(...key: string[]): Baggage; 92 | 93 | /** 94 | * Returns a new baggage with no entries 95 | */ 96 | clear(): Baggage; 97 | } 98 | -------------------------------------------------------------------------------- /src/baggage/utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { DiagAPI } from '../api/diag'; 18 | import { BaggageImpl } from './internal/baggage-impl'; 19 | import { baggageEntryMetadataSymbol } from './internal/symbol'; 20 | import { Baggage, BaggageEntry, BaggageEntryMetadata } from './types'; 21 | 22 | const diag = DiagAPI.instance(); 23 | 24 | /** 25 | * Create a new Baggage with optional entries 26 | * 27 | * @param entries An array of baggage entries the new baggage should contain 28 | */ 29 | export function createBaggage( 30 | entries: Record = {} 31 | ): Baggage { 32 | return new BaggageImpl(new Map(Object.entries(entries))); 33 | } 34 | 35 | /** 36 | * Create a serializable BaggageEntryMetadata object from a string. 37 | * 38 | * @param str string metadata. Format is currently not defined by the spec and has no special meaning. 39 | * 40 | */ 41 | export function baggageEntryMetadataFromString( 42 | str: string 43 | ): BaggageEntryMetadata { 44 | if (typeof str !== 'string') { 45 | diag.error( 46 | `Cannot create baggage metadata from unknown type: ${typeof str}` 47 | ); 48 | str = ''; 49 | } 50 | 51 | return { 52 | __TYPE__: baggageEntryMetadataSymbol, 53 | toString() { 54 | return str; 55 | }, 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /src/common/Attributes.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Attributes is a map from string to attribute values. 19 | * 20 | * Note: only the own enumerable keys are counted as valid attribute keys. 21 | */ 22 | export interface Attributes { 23 | [attributeKey: string]: AttributeValue | undefined; 24 | } 25 | 26 | /** 27 | * Attribute values may be any non-nullish primitive value except an object. 28 | * 29 | * null or undefined attribute values are invalid and will result in undefined behavior. 30 | */ 31 | export type AttributeValue = 32 | | string 33 | | number 34 | | boolean 35 | | Array 36 | | Array 37 | | Array; 38 | -------------------------------------------------------------------------------- /src/common/Exception.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | interface ExceptionWithCode { 18 | code: string | number; 19 | name?: string; 20 | message?: string; 21 | stack?: string; 22 | } 23 | 24 | interface ExceptionWithMessage { 25 | code?: string | number; 26 | message: string; 27 | name?: string; 28 | stack?: string; 29 | } 30 | 31 | interface ExceptionWithName { 32 | code?: string | number; 33 | message?: string; 34 | name: string; 35 | stack?: string; 36 | } 37 | 38 | /** 39 | * Defines Exception. 40 | * 41 | * string or an object with one of (message or name or code) and optional stack 42 | */ 43 | export type Exception = 44 | | ExceptionWithCode 45 | | ExceptionWithMessage 46 | | ExceptionWithName 47 | | string; 48 | -------------------------------------------------------------------------------- /src/common/Time.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * Defines High-Resolution Time. 18 | * 19 | * The first number, HrTime[0], is UNIX Epoch time in seconds since 00:00:00 UTC on 1 January 1970. 20 | * The second number, HrTime[1], represents the partial second elapsed since Unix Epoch time represented by first number in nanoseconds. 21 | * For example, 2021-01-01T12:30:10.150Z in UNIX Epoch time in milliseconds is represented as 1609504210150. 22 | * The first number is calculated by converting and truncating the Epoch time in milliseconds to seconds: 23 | * HrTime[0] = Math.trunc(1609504210150 / 1000) = 1609504210. 24 | * The second number is calculated by converting the digits after the decimal point of the subtraction, (1609504210150 / 1000) - HrTime[0], to nanoseconds: 25 | * HrTime[1] = Number((1609504210.150 - HrTime[0]).toFixed(9)) * 1e9 = 150000000. 26 | * This is represented in HrTime format as [1609504210, 150000000]. 27 | */ 28 | export type HrTime = [number, number]; 29 | 30 | /** 31 | * Defines TimeInput. 32 | * 33 | * hrtime, epoch milliseconds, performance.now() or Date 34 | */ 35 | export type TimeInput = HrTime | number | Date; 36 | -------------------------------------------------------------------------------- /src/context/NoopContextManager.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { ROOT_CONTEXT } from './context'; 18 | import * as types from './types'; 19 | 20 | export class NoopContextManager implements types.ContextManager { 21 | active(): types.Context { 22 | return ROOT_CONTEXT; 23 | } 24 | 25 | with ReturnType>( 26 | _context: types.Context, 27 | fn: F, 28 | thisArg?: ThisParameterType, 29 | ...args: A 30 | ): ReturnType { 31 | return fn.call(thisArg, ...args); 32 | } 33 | 34 | bind(_context: types.Context, target: T): T { 35 | return target; 36 | } 37 | 38 | enable(): this { 39 | return this; 40 | } 41 | 42 | disable(): this { 43 | return this; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/context/context.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Context } from './types'; 18 | 19 | /** Get a key to uniquely identify a context value */ 20 | export function createContextKey(description: string) { 21 | // The specification states that for the same input, multiple calls should 22 | // return different keys. Due to the nature of the JS dependency management 23 | // system, this creates problems where multiple versions of some package 24 | // could hold different keys for the same property. 25 | // 26 | // Therefore, we use Symbol.for which returns the same key for the same input. 27 | return Symbol.for(description); 28 | } 29 | 30 | class BaseContext implements Context { 31 | private _currentContext!: Map; 32 | 33 | /** 34 | * Construct a new context which inherits values from an optional parent context. 35 | * 36 | * @param parentContext a context from which to inherit values 37 | */ 38 | constructor(parentContext?: Map) { 39 | // for minification 40 | const self = this; 41 | 42 | self._currentContext = parentContext ? new Map(parentContext) : new Map(); 43 | 44 | self.getValue = (key: symbol) => self._currentContext.get(key); 45 | 46 | self.setValue = (key: symbol, value: unknown): Context => { 47 | const context = new BaseContext(self._currentContext); 48 | context._currentContext.set(key, value); 49 | return context; 50 | }; 51 | 52 | self.deleteValue = (key: symbol): Context => { 53 | const context = new BaseContext(self._currentContext); 54 | context._currentContext.delete(key); 55 | return context; 56 | }; 57 | } 58 | 59 | /** 60 | * Get a value from the context. 61 | * 62 | * @param key key which identifies a context value 63 | */ 64 | public getValue!: (key: symbol) => unknown; 65 | 66 | /** 67 | * Create a new context which inherits from this context and has 68 | * the given key set to the given value. 69 | * 70 | * @param key context key for which to set the value 71 | * @param value value to set for the given key 72 | */ 73 | public setValue!: (key: symbol, value: unknown) => Context; 74 | 75 | /** 76 | * Return a new context which inherits from this context but does 77 | * not contain a value for the given key. 78 | * 79 | * @param key context key for which to clear a value 80 | */ 81 | public deleteValue!: (key: symbol) => Context; 82 | } 83 | 84 | /** The root context is used as the default parent context when there is no active context */ 85 | export const ROOT_CONTEXT: Context = new BaseContext(); 86 | -------------------------------------------------------------------------------- /src/context/types.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export interface Context { 18 | /** 19 | * Get a value from the context. 20 | * 21 | * @param key key which identifies a context value 22 | */ 23 | getValue(key: symbol): unknown; 24 | 25 | /** 26 | * Create a new context which inherits from this context and has 27 | * the given key set to the given value. 28 | * 29 | * @param key context key for which to set the value 30 | * @param value value to set for the given key 31 | */ 32 | setValue(key: symbol, value: unknown): Context; 33 | 34 | /** 35 | * Return a new context which inherits from this context but does 36 | * not contain a value for the given key. 37 | * 38 | * @param key context key for which to clear a value 39 | */ 40 | deleteValue(key: symbol): Context; 41 | } 42 | 43 | export interface ContextManager { 44 | /** 45 | * Get the current active context 46 | */ 47 | active(): Context; 48 | 49 | /** 50 | * Run the fn callback with object set as the current active context 51 | * @param context Any object to set as the current active context 52 | * @param fn A callback to be immediately run within a specific context 53 | * @param thisArg optional receiver to be used for calling fn 54 | * @param args optional arguments forwarded to fn 55 | */ 56 | with ReturnType>( 57 | context: Context, 58 | fn: F, 59 | thisArg?: ThisParameterType, 60 | ...args: A 61 | ): ReturnType; 62 | 63 | /** 64 | * Bind an object as the current context (or a specific one) 65 | * @param [context] Optionally specify the context which you want to assign 66 | * @param target Any object to which a context need to be set 67 | */ 68 | bind(context: Context, target: T): T; 69 | 70 | /** 71 | * Enable context management 72 | */ 73 | enable(): this; 74 | 75 | /** 76 | * Disable context management 77 | */ 78 | disable(): this; 79 | } 80 | -------------------------------------------------------------------------------- /src/diag/ComponentLogger.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { getGlobal } from '../internal/global-utils'; 18 | import { ComponentLoggerOptions, DiagLogger, DiagLogFunction } from './types'; 19 | 20 | /** 21 | * Component Logger which is meant to be used as part of any component which 22 | * will add automatically additional namespace in front of the log message. 23 | * It will then forward all message to global diag logger 24 | * @example 25 | * const cLogger = diag.createComponentLogger({ namespace: '@opentelemetry/instrumentation-http' }); 26 | * cLogger.debug('test'); 27 | * // @opentelemetry/instrumentation-http test 28 | */ 29 | export class DiagComponentLogger implements DiagLogger { 30 | private _namespace: string; 31 | 32 | constructor(props: ComponentLoggerOptions) { 33 | this._namespace = props.namespace || 'DiagComponentLogger'; 34 | } 35 | 36 | public debug(...args: any[]): void { 37 | return logProxy('debug', this._namespace, args); 38 | } 39 | 40 | public error(...args: any[]): void { 41 | return logProxy('error', this._namespace, args); 42 | } 43 | 44 | public info(...args: any[]): void { 45 | return logProxy('info', this._namespace, args); 46 | } 47 | 48 | public warn(...args: any[]): void { 49 | return logProxy('warn', this._namespace, args); 50 | } 51 | 52 | public verbose(...args: any[]): void { 53 | return logProxy('verbose', this._namespace, args); 54 | } 55 | } 56 | 57 | function logProxy( 58 | funcName: keyof DiagLogger, 59 | namespace: string, 60 | args: any 61 | ): void { 62 | const logger = getGlobal('diag'); 63 | // shortcut if logger not set 64 | if (!logger) { 65 | return; 66 | } 67 | 68 | args.unshift(namespace); 69 | return logger[funcName](...(args as Parameters)); 70 | } 71 | -------------------------------------------------------------------------------- /src/diag/consoleLogger.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { DiagLogger, DiagLogFunction } from './types'; 18 | 19 | type ConsoleMapKeys = 'error' | 'warn' | 'info' | 'debug' | 'trace'; 20 | const consoleMap: { n: keyof DiagLogger; c: ConsoleMapKeys }[] = [ 21 | { n: 'error', c: 'error' }, 22 | { n: 'warn', c: 'warn' }, 23 | { n: 'info', c: 'info' }, 24 | { n: 'debug', c: 'debug' }, 25 | { n: 'verbose', c: 'trace' }, 26 | ]; 27 | 28 | /** 29 | * A simple Immutable Console based diagnostic logger which will output any messages to the Console. 30 | * If you want to limit the amount of logging to a specific level or lower use the 31 | * {@link createLogLevelDiagLogger} 32 | */ 33 | export class DiagConsoleLogger implements DiagLogger { 34 | constructor() { 35 | function _consoleFunc(funcName: ConsoleMapKeys): DiagLogFunction { 36 | return function (...args) { 37 | if (console) { 38 | // Some environments only expose the console when the F12 developer console is open 39 | // eslint-disable-next-line no-console 40 | let theFunc = console[funcName]; 41 | if (typeof theFunc !== 'function') { 42 | // Not all environments support all functions 43 | // eslint-disable-next-line no-console 44 | theFunc = console.log; 45 | } 46 | 47 | // One last final check 48 | if (typeof theFunc === 'function') { 49 | return theFunc.apply(console, args); 50 | } 51 | } 52 | }; 53 | } 54 | 55 | for (let i = 0; i < consoleMap.length; i++) { 56 | this[consoleMap[i].n] = _consoleFunc(consoleMap[i].c); 57 | } 58 | } 59 | 60 | /** Log an error scenario that was not expected and caused the requested operation to fail. */ 61 | public error!: DiagLogFunction; 62 | 63 | /** 64 | * Log a warning scenario to inform the developer of an issues that should be investigated. 65 | * The requested operation may or may not have succeeded or completed. 66 | */ 67 | public warn!: DiagLogFunction; 68 | 69 | /** 70 | * Log a general informational message, this should not affect functionality. 71 | * This is also the default logging level so this should NOT be used for logging 72 | * debugging level information. 73 | */ 74 | public info!: DiagLogFunction; 75 | 76 | /** 77 | * Log a general debug message that can be useful for identifying a failure. 78 | * Information logged at this level may include diagnostic details that would 79 | * help identify a failure scenario. Useful scenarios would be to log the execution 80 | * order of async operations 81 | */ 82 | public debug!: DiagLogFunction; 83 | 84 | /** 85 | * Log a detailed (verbose) trace level logging that can be used to identify failures 86 | * where debug level logging would be insufficient, this level of tracing can include 87 | * input and output parameters and as such may include PII information passing through 88 | * the API. As such it is recommended that this level of tracing should not be enabled 89 | * in a production environment. 90 | */ 91 | public verbose!: DiagLogFunction; 92 | } 93 | -------------------------------------------------------------------------------- /src/diag/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export * from './consoleLogger'; 18 | export * from './types'; 19 | -------------------------------------------------------------------------------- /src/diag/internal/logLevelLogger.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { DiagLogFunction, DiagLogger, DiagLogLevel } from '../types'; 18 | 19 | export function createLogLevelDiagLogger( 20 | maxLevel: DiagLogLevel, 21 | logger: DiagLogger 22 | ): DiagLogger { 23 | if (maxLevel < DiagLogLevel.NONE) { 24 | maxLevel = DiagLogLevel.NONE; 25 | } else if (maxLevel > DiagLogLevel.ALL) { 26 | maxLevel = DiagLogLevel.ALL; 27 | } 28 | 29 | // In case the logger is null or undefined 30 | logger = logger || {}; 31 | 32 | function _filterFunc( 33 | funcName: keyof DiagLogger, 34 | theLevel: DiagLogLevel 35 | ): DiagLogFunction { 36 | const theFunc = logger[funcName]; 37 | 38 | if (typeof theFunc === 'function' && maxLevel >= theLevel) { 39 | return theFunc.bind(logger); 40 | } 41 | return function () {}; 42 | } 43 | 44 | return { 45 | error: _filterFunc('error', DiagLogLevel.ERROR), 46 | warn: _filterFunc('warn', DiagLogLevel.WARN), 47 | info: _filterFunc('info', DiagLogLevel.INFO), 48 | debug: _filterFunc('debug', DiagLogLevel.DEBUG), 49 | verbose: _filterFunc('verbose', DiagLogLevel.VERBOSE), 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /src/diag/internal/noopLogger.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { DiagLogger } from '../types'; 18 | 19 | function noopLogFunction() {} 20 | 21 | /** 22 | * Returns a No-Op Diagnostic logger where all messages do nothing. 23 | * @implements {@link DiagLogger} 24 | * @returns {DiagLogger} 25 | */ 26 | export function createNoopDiagLogger(): DiagLogger { 27 | return { 28 | verbose: noopLogFunction, 29 | debug: noopLogFunction, 30 | info: noopLogFunction, 31 | warn: noopLogFunction, 32 | error: noopLogFunction, 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/diag/types.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export type DiagLogFunction = (message: string, ...args: unknown[]) => void; 18 | 19 | /** 20 | * Defines an internal diagnostic logger interface which is used to log internal diagnostic 21 | * messages, you can set the default diagnostic logger via the {@link DiagAPI} setLogger function. 22 | * API provided implementations include :- 23 | * - a No-Op {@link createNoopDiagLogger} 24 | * - a {@link DiagLogLevel} filtering wrapper {@link createLogLevelDiagLogger} 25 | * - a general Console {@link DiagConsoleLogger} version. 26 | */ 27 | export interface DiagLogger { 28 | /** Log an error scenario that was not expected and caused the requested operation to fail. */ 29 | error: DiagLogFunction; 30 | 31 | /** 32 | * Log a warning scenario to inform the developer of an issues that should be investigated. 33 | * The requested operation may or may not have succeeded or completed. 34 | */ 35 | warn: DiagLogFunction; 36 | 37 | /** 38 | * Log a general informational message, this should not affect functionality. 39 | * This is also the default logging level so this should NOT be used for logging 40 | * debugging level information. 41 | */ 42 | info: DiagLogFunction; 43 | 44 | /** 45 | * Log a general debug message that can be useful for identifying a failure. 46 | * Information logged at this level may include diagnostic details that would 47 | * help identify a failure scenario. 48 | * For example: Logging the order of execution of async operations. 49 | */ 50 | debug: DiagLogFunction; 51 | 52 | /** 53 | * Log a detailed (verbose) trace level logging that can be used to identify failures 54 | * where debug level logging would be insufficient, this level of tracing can include 55 | * input and output parameters and as such may include PII information passing through 56 | * the API. As such it is recommended that this level of tracing should not be enabled 57 | * in a production environment. 58 | */ 59 | verbose: DiagLogFunction; 60 | } 61 | 62 | /** 63 | * Defines the available internal logging levels for the diagnostic logger, the numeric values 64 | * of the levels are defined to match the original values from the initial LogLevel to avoid 65 | * compatibility/migration issues for any implementation that assume the numeric ordering. 66 | */ 67 | export enum DiagLogLevel { 68 | /** Diagnostic Logging level setting to disable all logging (except and forced logs) */ 69 | NONE = 0, 70 | 71 | /** Identifies an error scenario */ 72 | ERROR = 30, 73 | 74 | /** Identifies a warning scenario */ 75 | WARN = 50, 76 | 77 | /** General informational log message */ 78 | INFO = 60, 79 | 80 | /** General debug log message */ 81 | DEBUG = 70, 82 | 83 | /** 84 | * Detailed trace level logging should only be used for development, should only be set 85 | * in a development environment. 86 | */ 87 | VERBOSE = 80, 88 | 89 | /** Used to set the logging level to include all logging */ 90 | ALL = 9999, 91 | } 92 | 93 | /** 94 | * Defines options for ComponentLogger 95 | */ 96 | export interface ComponentLoggerOptions { 97 | namespace: string; 98 | } 99 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export * from './baggage/types'; 18 | export { baggageEntryMetadataFromString } from './baggage/utils'; 19 | export * from './common/Exception'; 20 | export * from './common/Time'; 21 | export * from './common/Attributes'; 22 | export * from './diag'; 23 | export * from './propagation/TextMapPropagator'; 24 | export * from './trace/attributes'; 25 | export * from './trace/link'; 26 | export * from './trace/ProxyTracer'; 27 | export * from './trace/ProxyTracerProvider'; 28 | export * from './trace/Sampler'; 29 | export * from './trace/SamplingResult'; 30 | export * from './trace/span_context'; 31 | export * from './trace/span_kind'; 32 | export * from './trace/span'; 33 | export * from './trace/SpanOptions'; 34 | export * from './trace/status'; 35 | export * from './trace/trace_flags'; 36 | export * from './trace/trace_state'; 37 | export { createTraceState } from './trace/internal/utils'; 38 | export * from './trace/tracer_provider'; 39 | export * from './trace/tracer'; 40 | export * from './trace/tracer_options'; 41 | 42 | export { 43 | isSpanContextValid, 44 | isValidTraceId, 45 | isValidSpanId, 46 | } from './trace/spancontext-utils'; 47 | 48 | export { 49 | INVALID_SPANID, 50 | INVALID_TRACEID, 51 | INVALID_SPAN_CONTEXT, 52 | } from './trace/invalid-span-constants'; 53 | 54 | export * from './context/context'; 55 | export * from './context/types'; 56 | 57 | import { ContextAPI } from './api/context'; 58 | export type { ContextAPI } from './api/context'; 59 | /** Entrypoint for context API */ 60 | export const context = ContextAPI.getInstance(); 61 | 62 | import { TraceAPI } from './api/trace'; 63 | export type { TraceAPI } from './api/trace'; 64 | /** Entrypoint for trace API */ 65 | export const trace = TraceAPI.getInstance(); 66 | 67 | import { PropagationAPI } from './api/propagation'; 68 | export type { PropagationAPI } from './api/propagation'; 69 | /** Entrypoint for propagation API */ 70 | export const propagation = PropagationAPI.getInstance(); 71 | 72 | import { DiagAPI } from './api/diag'; 73 | export type { DiagAPI } from './api/diag'; 74 | 75 | /** 76 | * Entrypoint for Diag API. 77 | * Defines Diagnostic handler used for internal diagnostic logging operations. 78 | * The default provides a Noop DiagLogger implementation which may be changed via the 79 | * diag.setLogger(logger: DiagLogger) function. 80 | */ 81 | export const diag = DiagAPI.instance(); 82 | 83 | export default { 84 | trace, 85 | context, 86 | propagation, 87 | diag, 88 | }; 89 | -------------------------------------------------------------------------------- /src/internal/global-utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { ContextManager } from '../context/types'; 18 | import { DiagLogger } from '../diag'; 19 | import { _globalThis } from '../platform'; 20 | import { TextMapPropagator } from '../propagation/TextMapPropagator'; 21 | import type { TracerProvider } from '../trace/tracer_provider'; 22 | import { VERSION } from '../version'; 23 | import { isCompatible } from './semver'; 24 | 25 | const major = VERSION.split('.')[0]; 26 | const GLOBAL_OPENTELEMETRY_API_KEY = Symbol.for( 27 | `opentelemetry.js.api.${major}` 28 | ); 29 | 30 | const _global = _globalThis as OTelGlobal; 31 | 32 | export function registerGlobal( 33 | type: Type, 34 | instance: OTelGlobalAPI[Type], 35 | diag: DiagLogger, 36 | allowOverride = false 37 | ): boolean { 38 | const api = (_global[GLOBAL_OPENTELEMETRY_API_KEY] = _global[ 39 | GLOBAL_OPENTELEMETRY_API_KEY 40 | ] ?? { 41 | version: VERSION, 42 | }); 43 | 44 | if (!allowOverride && api[type]) { 45 | // already registered an API of this type 46 | const err = new Error( 47 | `@opentelemetry/api: Attempted duplicate registration of API: ${type}` 48 | ); 49 | diag.error(err.stack || err.message); 50 | return false; 51 | } 52 | 53 | if (api.version !== VERSION) { 54 | // All registered APIs must be of the same version exactly 55 | const err = new Error( 56 | '@opentelemetry/api: All API registration versions must match' 57 | ); 58 | diag.error(err.stack || err.message); 59 | return false; 60 | } 61 | 62 | api[type] = instance; 63 | diag.debug( 64 | `@opentelemetry/api: Registered a global for ${type} v${VERSION}.` 65 | ); 66 | 67 | return true; 68 | } 69 | 70 | export function getGlobal( 71 | type: Type 72 | ): OTelGlobalAPI[Type] | undefined { 73 | const globalVersion = _global[GLOBAL_OPENTELEMETRY_API_KEY]?.version; 74 | if (!globalVersion || !isCompatible(globalVersion)) { 75 | return; 76 | } 77 | return _global[GLOBAL_OPENTELEMETRY_API_KEY]?.[type]; 78 | } 79 | 80 | export function unregisterGlobal(type: keyof OTelGlobalAPI, diag: DiagLogger) { 81 | diag.debug( 82 | `@opentelemetry/api: Unregistering a global for ${type} v${VERSION}.` 83 | ); 84 | const api = _global[GLOBAL_OPENTELEMETRY_API_KEY]; 85 | 86 | if (api) { 87 | delete api[type]; 88 | } 89 | } 90 | 91 | type OTelGlobal = { 92 | [GLOBAL_OPENTELEMETRY_API_KEY]?: OTelGlobalAPI; 93 | }; 94 | 95 | type OTelGlobalAPI = { 96 | version: string; 97 | 98 | diag?: DiagLogger; 99 | trace?: TracerProvider; 100 | context?: ContextManager; 101 | propagation?: TextMapPropagator; 102 | }; 103 | -------------------------------------------------------------------------------- /src/internal/semver.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { VERSION } from '../version'; 18 | 19 | const re = /^(\d+)\.(\d+)\.(\d+)(-(.+))?$/; 20 | 21 | /** 22 | * Create a function to test an API version to see if it is compatible with the provided ownVersion. 23 | * 24 | * The returned function has the following semantics: 25 | * - Exact match is always compatible 26 | * - Major versions must match exactly 27 | * - 1.x package cannot use global 2.x package 28 | * - 2.x package cannot use global 1.x package 29 | * - The minor version of the API module requesting access to the global API must be less than or equal to the minor version of this API 30 | * - 1.3 package may use 1.4 global because the later global contains all functions 1.3 expects 31 | * - 1.4 package may NOT use 1.3 global because it may try to call functions which don't exist on 1.3 32 | * - If the major version is 0, the minor version is treated as the major and the patch is treated as the minor 33 | * - Patch and build tag differences are not considered at this time 34 | * 35 | * @param ownVersion version which should be checked against 36 | */ 37 | export function _makeCompatibilityCheck( 38 | ownVersion: string 39 | ): (globalVersion: string) => boolean { 40 | const acceptedVersions = new Set([ownVersion]); 41 | const rejectedVersions = new Set(); 42 | 43 | const myVersionMatch = ownVersion.match(re); 44 | if (!myVersionMatch) { 45 | // we cannot guarantee compatibility so we always return noop 46 | return () => false; 47 | } 48 | 49 | const ownVersionParsed = { 50 | major: +myVersionMatch[1], 51 | minor: +myVersionMatch[2], 52 | patch: +myVersionMatch[3], 53 | prerelease: myVersionMatch[4], 54 | }; 55 | 56 | // if ownVersion has a prerelease tag, versions must match exactly 57 | if (ownVersionParsed.prerelease != null) { 58 | return function isExactmatch(globalVersion: string): boolean { 59 | return globalVersion === ownVersion; 60 | }; 61 | } 62 | 63 | function _reject(v: string) { 64 | rejectedVersions.add(v); 65 | return false; 66 | } 67 | 68 | function _accept(v: string) { 69 | acceptedVersions.add(v); 70 | return true; 71 | } 72 | 73 | return function isCompatible(globalVersion: string): boolean { 74 | if (acceptedVersions.has(globalVersion)) { 75 | return true; 76 | } 77 | 78 | if (rejectedVersions.has(globalVersion)) { 79 | return false; 80 | } 81 | 82 | const globalVersionMatch = globalVersion.match(re); 83 | if (!globalVersionMatch) { 84 | // cannot parse other version 85 | // we cannot guarantee compatibility so we always noop 86 | return _reject(globalVersion); 87 | } 88 | 89 | const globalVersionParsed = { 90 | major: +globalVersionMatch[1], 91 | minor: +globalVersionMatch[2], 92 | patch: +globalVersionMatch[3], 93 | prerelease: globalVersionMatch[4], 94 | }; 95 | 96 | // if globalVersion has a prerelease tag, versions must match exactly 97 | if (globalVersionParsed.prerelease != null) { 98 | return _reject(globalVersion); 99 | } 100 | 101 | // major versions must match 102 | if (ownVersionParsed.major !== globalVersionParsed.major) { 103 | return _reject(globalVersion); 104 | } 105 | 106 | if (ownVersionParsed.major === 0) { 107 | if ( 108 | ownVersionParsed.minor === globalVersionParsed.minor && 109 | ownVersionParsed.patch <= globalVersionParsed.patch 110 | ) { 111 | return _accept(globalVersion); 112 | } 113 | 114 | return _reject(globalVersion); 115 | } 116 | 117 | if (ownVersionParsed.minor <= globalVersionParsed.minor) { 118 | return _accept(globalVersion); 119 | } 120 | 121 | return _reject(globalVersion); 122 | }; 123 | } 124 | 125 | /** 126 | * Test an API version to see if it is compatible with this API. 127 | * 128 | * - Exact match is always compatible 129 | * - Major versions must match exactly 130 | * - 1.x package cannot use global 2.x package 131 | * - 2.x package cannot use global 1.x package 132 | * - The minor version of the API module requesting access to the global API must be less than or equal to the minor version of this API 133 | * - 1.3 package may use 1.4 global because the later global contains all functions 1.3 expects 134 | * - 1.4 package may NOT use 1.3 global because it may try to call functions which don't exist on 1.3 135 | * - If the major version is 0, the minor version is treated as the major and the patch is treated as the minor 136 | * - Patch and build tag differences are not considered at this time 137 | * 138 | * @param version version of the API requesting an instance of the global API 139 | */ 140 | export const isCompatible = _makeCompatibilityCheck(VERSION); 141 | -------------------------------------------------------------------------------- /src/platform/browser/globalThis.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Updates to this file should also be replicated to @opentelemetry/api-metrics and 18 | // @opentelemetry/core too. 19 | 20 | /** 21 | * - globalThis (New standard) 22 | * - self (Will return the current window instance for supported browsers) 23 | * - window (fallback for older browser implementations) 24 | * - global (NodeJS implementation) 25 | * - (When all else fails) 26 | */ 27 | 28 | /** only globals that common to node and browsers are allowed */ 29 | // eslint-disable-next-line node/no-unsupported-features/es-builtins, no-undef 30 | export const _globalThis: typeof globalThis = 31 | typeof globalThis === 'object' ? globalThis : 32 | typeof self === 'object' ? self : 33 | typeof window === 'object' ? window : 34 | typeof global === 'object' ? global : 35 | {} as typeof globalThis; 36 | -------------------------------------------------------------------------------- /src/platform/browser/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export * from './globalThis'; 18 | -------------------------------------------------------------------------------- /src/platform/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export * from './node'; 18 | -------------------------------------------------------------------------------- /src/platform/node/globalThis.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** only globals that common to node and browsers are allowed */ 18 | // eslint-disable-next-line node/no-unsupported-features/es-builtins 19 | export const _globalThis = typeof globalThis === 'object' ? globalThis : global; 20 | -------------------------------------------------------------------------------- /src/platform/node/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export * from './globalThis'; 18 | -------------------------------------------------------------------------------- /src/propagation/NoopTextMapPropagator.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Context } from '../context/types'; 18 | import { TextMapPropagator } from './TextMapPropagator'; 19 | 20 | /** 21 | * No-op implementations of {@link TextMapPropagator}. 22 | */ 23 | export class NoopTextMapPropagator implements TextMapPropagator { 24 | /** Noop inject function does nothing */ 25 | inject(_context: Context, _carrier: unknown): void {} 26 | /** Noop extract function does nothing and returns the input context */ 27 | extract(context: Context, _carrier: unknown): Context { 28 | return context; 29 | } 30 | fields(): string[] { 31 | return []; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/propagation/TextMapPropagator.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Context } from '../context/types'; 18 | 19 | /** 20 | * Injects `Context` into and extracts it from carriers that travel 21 | * in-band across process boundaries. Encoding is expected to conform to the 22 | * HTTP Header Field semantics. Values are often encoded as RPC/HTTP request 23 | * headers. 24 | * 25 | * The carrier of propagated data on both the client (injector) and server 26 | * (extractor) side is usually an object such as http headers. Propagation is 27 | * usually implemented via library-specific request interceptors, where the 28 | * client-side injects values and the server-side extracts them. 29 | */ 30 | export interface TextMapPropagator { 31 | /** 32 | * Injects values from a given `Context` into a carrier. 33 | * 34 | * OpenTelemetry defines a common set of format values (TextMapPropagator), 35 | * and each has an expected `carrier` type. 36 | * 37 | * @param context the Context from which to extract values to transmit over 38 | * the wire. 39 | * @param carrier the carrier of propagation fields, such as http request 40 | * headers. 41 | * @param setter an optional {@link TextMapSetter}. If undefined, values will be 42 | * set by direct object assignment. 43 | */ 44 | inject( 45 | context: Context, 46 | carrier: Carrier, 47 | setter: TextMapSetter 48 | ): void; 49 | 50 | /** 51 | * Given a `Context` and a carrier, extract context values from a 52 | * carrier and return a new context, created from the old context, with the 53 | * extracted values. 54 | * 55 | * @param context the Context from which to extract values to transmit over 56 | * the wire. 57 | * @param carrier the carrier of propagation fields, such as http request 58 | * headers. 59 | * @param getter an optional {@link TextMapGetter}. If undefined, keys will be all 60 | * own properties, and keys will be accessed by direct object access. 61 | */ 62 | extract( 63 | context: Context, 64 | carrier: Carrier, 65 | getter: TextMapGetter 66 | ): Context; 67 | 68 | /** 69 | * Return a list of all fields which may be used by the propagator. 70 | */ 71 | fields(): string[]; 72 | } 73 | 74 | /** 75 | * A setter is specified by the caller to define a specific method 76 | * to set key/value pairs on the carrier within a propagator. 77 | */ 78 | export interface TextMapSetter { 79 | /** 80 | * Callback used to set a key/value pair on an object. 81 | * 82 | * Should be called by the propagator each time a key/value pair 83 | * should be set, and should set that key/value pair on the propagator. 84 | * 85 | * @param carrier object or class which carries key/value pairs 86 | * @param key string key to modify 87 | * @param value value to be set to the key on the carrier 88 | */ 89 | set(carrier: Carrier, key: string, value: string): void; 90 | } 91 | 92 | /** 93 | * A getter is specified by the caller to define a specific method 94 | * to get the value of a key from a carrier. 95 | */ 96 | export interface TextMapGetter { 97 | /** 98 | * Get a list of all keys available on the carrier. 99 | * 100 | * @param carrier 101 | */ 102 | keys(carrier: Carrier): string[]; 103 | 104 | /** 105 | * Get the value of a specific key from the carrier. 106 | * 107 | * @param carrier 108 | * @param key 109 | */ 110 | get(carrier: Carrier, key: string): undefined | string | string[]; 111 | } 112 | 113 | export const defaultTextMapGetter: TextMapGetter = { 114 | get(carrier, key) { 115 | if (carrier == null) { 116 | return undefined; 117 | } 118 | return carrier[key]; 119 | }, 120 | 121 | keys(carrier) { 122 | if (carrier == null) { 123 | return []; 124 | } 125 | return Object.keys(carrier); 126 | }, 127 | }; 128 | 129 | export const defaultTextMapSetter: TextMapSetter = { 130 | set(carrier, key, value) { 131 | if (carrier == null) { 132 | return; 133 | } 134 | 135 | carrier[key] = value; 136 | }, 137 | }; 138 | -------------------------------------------------------------------------------- /src/trace/NonRecordingSpan.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Exception } from '../common/Exception'; 18 | import { TimeInput } from '../common/Time'; 19 | import { SpanAttributes } from './attributes'; 20 | import { INVALID_SPAN_CONTEXT } from './invalid-span-constants'; 21 | import { Span } from './span'; 22 | import { SpanContext } from './span_context'; 23 | import { SpanStatus } from './status'; 24 | 25 | /** 26 | * The NonRecordingSpan is the default {@link Span} that is used when no Span 27 | * implementation is available. All operations are no-op including context 28 | * propagation. 29 | */ 30 | export class NonRecordingSpan implements Span { 31 | constructor( 32 | private readonly _spanContext: SpanContext = INVALID_SPAN_CONTEXT 33 | ) {} 34 | 35 | // Returns a SpanContext. 36 | spanContext(): SpanContext { 37 | return this._spanContext; 38 | } 39 | 40 | // By default does nothing 41 | setAttribute(_key: string, _value: unknown): this { 42 | return this; 43 | } 44 | 45 | // By default does nothing 46 | setAttributes(_attributes: SpanAttributes): this { 47 | return this; 48 | } 49 | 50 | // By default does nothing 51 | addEvent(_name: string, _attributes?: SpanAttributes): this { 52 | return this; 53 | } 54 | 55 | // By default does nothing 56 | setStatus(_status: SpanStatus): this { 57 | return this; 58 | } 59 | 60 | // By default does nothing 61 | updateName(_name: string): this { 62 | return this; 63 | } 64 | 65 | // By default does nothing 66 | end(_endTime?: TimeInput): void {} 67 | 68 | // isRecording always returns false for NonRecordingSpan. 69 | isRecording(): boolean { 70 | return false; 71 | } 72 | 73 | // By default does nothing 74 | recordException(_exception: Exception, _time?: TimeInput): void {} 75 | } 76 | -------------------------------------------------------------------------------- /src/trace/NoopTracer.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { ContextAPI } from '../api/context'; 18 | import { Context } from '../context/types'; 19 | import { getSpanContext, setSpan } from '../trace/context-utils'; 20 | import { NonRecordingSpan } from './NonRecordingSpan'; 21 | import { Span } from './span'; 22 | import { isSpanContextValid } from './spancontext-utils'; 23 | import { SpanOptions } from './SpanOptions'; 24 | import { SpanContext } from './span_context'; 25 | import { Tracer } from './tracer'; 26 | 27 | const context = ContextAPI.getInstance(); 28 | 29 | /** 30 | * No-op implementations of {@link Tracer}. 31 | */ 32 | export class NoopTracer implements Tracer { 33 | // startSpan starts a noop span. 34 | startSpan(name: string, options?: SpanOptions, context?: Context): Span { 35 | const root = Boolean(options?.root); 36 | if (root) { 37 | return new NonRecordingSpan(); 38 | } 39 | 40 | const parentFromContext = context && getSpanContext(context); 41 | 42 | if ( 43 | isSpanContext(parentFromContext) && 44 | isSpanContextValid(parentFromContext) 45 | ) { 46 | return new NonRecordingSpan(parentFromContext); 47 | } else { 48 | return new NonRecordingSpan(); 49 | } 50 | } 51 | 52 | startActiveSpan ReturnType>( 53 | name: string, 54 | fn: F 55 | ): ReturnType; 56 | startActiveSpan ReturnType>( 57 | name: string, 58 | opts: SpanOptions | undefined, 59 | fn: F 60 | ): ReturnType; 61 | startActiveSpan ReturnType>( 62 | name: string, 63 | opts: SpanOptions | undefined, 64 | ctx: Context | undefined, 65 | fn: F 66 | ): ReturnType; 67 | startActiveSpan ReturnType>( 68 | name: string, 69 | arg2?: F | SpanOptions, 70 | arg3?: F | Context, 71 | arg4?: F 72 | ): ReturnType | undefined { 73 | let opts: SpanOptions | undefined; 74 | let ctx: Context | undefined; 75 | let fn: F; 76 | 77 | if (arguments.length < 2) { 78 | return; 79 | } else if (arguments.length === 2) { 80 | fn = arg2 as F; 81 | } else if (arguments.length === 3) { 82 | opts = arg2 as SpanOptions | undefined; 83 | fn = arg3 as F; 84 | } else { 85 | opts = arg2 as SpanOptions | undefined; 86 | ctx = arg3 as Context | undefined; 87 | fn = arg4 as F; 88 | } 89 | 90 | const parentContext = ctx ?? context.active(); 91 | const span = this.startSpan(name, opts, parentContext); 92 | const contextWithSpanSet = setSpan(parentContext, span); 93 | 94 | return context.with(contextWithSpanSet, fn, undefined, span); 95 | } 96 | } 97 | 98 | function isSpanContext(spanContext: any): spanContext is SpanContext { 99 | return ( 100 | typeof spanContext === 'object' && 101 | typeof spanContext['spanId'] === 'string' && 102 | typeof spanContext['traceId'] === 'string' && 103 | typeof spanContext['traceFlags'] === 'number' 104 | ); 105 | } 106 | -------------------------------------------------------------------------------- /src/trace/NoopTracerProvider.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { NoopTracer } from './NoopTracer'; 18 | import { Tracer } from './tracer'; 19 | import { TracerOptions } from './tracer_options'; 20 | import { TracerProvider } from './tracer_provider'; 21 | 22 | /** 23 | * An implementation of the {@link TracerProvider} which returns an impotent 24 | * Tracer for all calls to `getTracer`. 25 | * 26 | * All operations are no-op. 27 | */ 28 | export class NoopTracerProvider implements TracerProvider { 29 | getTracer( 30 | _name?: string, 31 | _version?: string, 32 | _options?: TracerOptions 33 | ): Tracer { 34 | return new NoopTracer(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/trace/ProxyTracer.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Context } from '../context/types'; 18 | import { NoopTracer } from './NoopTracer'; 19 | import { Span } from './span'; 20 | import { SpanOptions } from './SpanOptions'; 21 | import { Tracer } from './tracer'; 22 | import { TracerOptions } from './tracer_options'; 23 | 24 | const NOOP_TRACER = new NoopTracer(); 25 | 26 | /** 27 | * Proxy tracer provided by the proxy tracer provider 28 | */ 29 | export class ProxyTracer implements Tracer { 30 | // When a real implementation is provided, this will be it 31 | private _delegate?: Tracer; 32 | 33 | constructor( 34 | private _provider: TracerDelegator, 35 | public readonly name: string, 36 | public readonly version?: string, 37 | public readonly options?: TracerOptions 38 | ) {} 39 | 40 | startSpan(name: string, options?: SpanOptions, context?: Context): Span { 41 | return this._getTracer().startSpan(name, options, context); 42 | } 43 | 44 | startActiveSpan unknown>( 45 | _name: string, 46 | _options: F | SpanOptions, 47 | _context?: F | Context, 48 | _fn?: F 49 | ): ReturnType { 50 | const tracer = this._getTracer(); 51 | return Reflect.apply(tracer.startActiveSpan, tracer, arguments); 52 | } 53 | 54 | /** 55 | * Try to get a tracer from the proxy tracer provider. 56 | * If the proxy tracer provider has no delegate, return a noop tracer. 57 | */ 58 | private _getTracer() { 59 | if (this._delegate) { 60 | return this._delegate; 61 | } 62 | 63 | const tracer = this._provider.getDelegateTracer(this.name, this.version, this.options); 64 | 65 | if (!tracer) { 66 | return NOOP_TRACER; 67 | } 68 | 69 | this._delegate = tracer; 70 | return this._delegate; 71 | } 72 | } 73 | 74 | export interface TracerDelegator { 75 | getDelegateTracer(name: string, version?: string, options?: TracerOptions): Tracer | undefined; 76 | } 77 | -------------------------------------------------------------------------------- /src/trace/ProxyTracerProvider.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Tracer } from './tracer'; 18 | import { TracerProvider } from './tracer_provider'; 19 | import { ProxyTracer } from './ProxyTracer'; 20 | import { NoopTracerProvider } from './NoopTracerProvider'; 21 | import { TracerOptions } from './tracer_options'; 22 | 23 | const NOOP_TRACER_PROVIDER = new NoopTracerProvider(); 24 | 25 | /** 26 | * Tracer provider which provides {@link ProxyTracer}s. 27 | * 28 | * Before a delegate is set, tracers provided are NoOp. 29 | * When a delegate is set, traces are provided from the delegate. 30 | * When a delegate is set after tracers have already been provided, 31 | * all tracers already provided will use the provided delegate implementation. 32 | */ 33 | export class ProxyTracerProvider implements TracerProvider { 34 | private _delegate?: TracerProvider; 35 | 36 | /** 37 | * Get a {@link ProxyTracer} 38 | */ 39 | getTracer(name: string, version?: string, options?: TracerOptions): Tracer { 40 | return ( 41 | this.getDelegateTracer(name, version, options) ?? 42 | new ProxyTracer(this, name, version, options) 43 | ); 44 | } 45 | 46 | getDelegate(): TracerProvider { 47 | return this._delegate ?? NOOP_TRACER_PROVIDER; 48 | } 49 | 50 | /** 51 | * Set the delegate tracer provider 52 | */ 53 | setDelegate(delegate: TracerProvider) { 54 | this._delegate = delegate; 55 | } 56 | 57 | getDelegateTracer( 58 | name: string, 59 | version?: string, 60 | options?: TracerOptions 61 | ): Tracer | undefined { 62 | return this._delegate?.getTracer(name, version, options); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/trace/Sampler.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Context } from '../context/types'; 18 | import { SpanAttributes } from './attributes'; 19 | import { Link } from './link'; 20 | import { SamplingResult } from './SamplingResult'; 21 | import { SpanKind } from './span_kind'; 22 | 23 | /** 24 | * @deprecated use the one declared in @opentelemetry/sdk-trace-base instead. 25 | * This interface represent a sampler. Sampling is a mechanism to control the 26 | * noise and overhead introduced by OpenTelemetry by reducing the number of 27 | * samples of traces collected and sent to the backend. 28 | */ 29 | export interface Sampler { 30 | /** 31 | * Checks whether span needs to be created and tracked. 32 | * 33 | * @param context Parent Context which may contain a span. 34 | * @param traceId of the span to be created. It can be different from the 35 | * traceId in the {@link SpanContext}. Typically in situations when the 36 | * span to be created starts a new trace. 37 | * @param spanName of the span to be created. 38 | * @param spanKind of the span to be created. 39 | * @param attributes Initial set of SpanAttributes for the Span being constructed. 40 | * @param links Collection of links that will be associated with the Span to 41 | * be created. Typically useful for batch operations. 42 | * @returns a {@link SamplingResult}. 43 | */ 44 | shouldSample( 45 | context: Context, 46 | traceId: string, 47 | spanName: string, 48 | spanKind: SpanKind, 49 | attributes: SpanAttributes, 50 | links: Link[] 51 | ): SamplingResult; 52 | 53 | /** Returns the sampler name or short description with the configuration. */ 54 | toString(): string; 55 | } 56 | -------------------------------------------------------------------------------- /src/trace/SamplingResult.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { SpanAttributes } from './attributes'; 18 | 19 | /** 20 | * @deprecated use the one declared in @opentelemetry/sdk-trace-base instead. 21 | * A sampling decision that determines how a {@link Span} will be recorded 22 | * and collected. 23 | */ 24 | export enum SamplingDecision { 25 | /** 26 | * `Span.isRecording() === false`, span will not be recorded and all events 27 | * and attributes will be dropped. 28 | */ 29 | NOT_RECORD, 30 | /** 31 | * `Span.isRecording() === true`, but `Sampled` flag in {@link TraceFlags} 32 | * MUST NOT be set. 33 | */ 34 | RECORD, 35 | /** 36 | * `Span.isRecording() === true` AND `Sampled` flag in {@link TraceFlags} 37 | * MUST be set. 38 | */ 39 | RECORD_AND_SAMPLED, 40 | } 41 | 42 | /** 43 | * @deprecated use the one declared in @opentelemetry/sdk-trace-base instead. 44 | * A sampling result contains a decision for a {@link Span} and additional 45 | * attributes the sampler would like to added to the Span. 46 | */ 47 | export interface SamplingResult { 48 | /** 49 | * A sampling decision, refer to {@link SamplingDecision} for details. 50 | */ 51 | decision: SamplingDecision; 52 | /** 53 | * The list of attributes returned by SamplingResult MUST be immutable. 54 | * Caller may call {@link Sampler}.shouldSample any number of times and 55 | * can safely cache the returned value. 56 | */ 57 | attributes?: Readonly; 58 | } 59 | -------------------------------------------------------------------------------- /src/trace/SpanOptions.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { TimeInput } from '../common/Time'; 18 | import { SpanAttributes } from './attributes'; 19 | import { Link } from './link'; 20 | import { SpanKind } from './span_kind'; 21 | 22 | /** 23 | * Options needed for span creation 24 | */ 25 | export interface SpanOptions { 26 | /** 27 | * The SpanKind of a span 28 | * @default {@link SpanKind.INTERNAL} 29 | */ 30 | kind?: SpanKind; 31 | 32 | /** A span's attributes */ 33 | attributes?: SpanAttributes; 34 | 35 | /** {@link Link}s span to other spans */ 36 | links?: Link[]; 37 | 38 | /** A manually specified start time for the created `Span` object. */ 39 | startTime?: TimeInput; 40 | 41 | /** The new span should be a root span. (Ignore parent from context). */ 42 | root?: boolean; 43 | } 44 | -------------------------------------------------------------------------------- /src/trace/attributes.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Attributes, AttributeValue } from '../common/Attributes'; 18 | 19 | /** 20 | * @deprecated please use {@link Attributes} 21 | */ 22 | export type SpanAttributes = Attributes; 23 | 24 | /** 25 | * @deprecated please use {@link AttributeValue} 26 | */ 27 | export type SpanAttributeValue = AttributeValue; 28 | -------------------------------------------------------------------------------- /src/trace/context-utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { createContextKey } from '../context/context'; 18 | import { Context } from '../context/types'; 19 | import { Span } from './span'; 20 | import { SpanContext } from './span_context'; 21 | import { NonRecordingSpan } from './NonRecordingSpan'; 22 | import { ContextAPI } from '../api/context'; 23 | 24 | /** 25 | * span key 26 | */ 27 | const SPAN_KEY = createContextKey('OpenTelemetry Context Key SPAN'); 28 | 29 | /** 30 | * Return the span if one exists 31 | * 32 | * @param context context to get span from 33 | */ 34 | export function getSpan(context: Context): Span | undefined { 35 | return (context.getValue(SPAN_KEY) as Span) || undefined; 36 | } 37 | 38 | /** 39 | * Gets the span from the current context, if one exists. 40 | */ 41 | export function getActiveSpan(): Span | undefined { 42 | return getSpan(ContextAPI.getInstance().active()); 43 | } 44 | 45 | /** 46 | * Set the span on a context 47 | * 48 | * @param context context to use as parent 49 | * @param span span to set active 50 | */ 51 | export function setSpan(context: Context, span: Span): Context { 52 | return context.setValue(SPAN_KEY, span); 53 | } 54 | 55 | /** 56 | * Remove current span stored in the context 57 | * 58 | * @param context context to delete span from 59 | */ 60 | export function deleteSpan(context: Context): Context { 61 | return context.deleteValue(SPAN_KEY); 62 | } 63 | 64 | /** 65 | * Wrap span context in a NoopSpan and set as span in a new 66 | * context 67 | * 68 | * @param context context to set active span on 69 | * @param spanContext span context to be wrapped 70 | */ 71 | export function setSpanContext( 72 | context: Context, 73 | spanContext: SpanContext 74 | ): Context { 75 | return setSpan(context, new NonRecordingSpan(spanContext)); 76 | } 77 | 78 | /** 79 | * Get the span context of the span if it exists. 80 | * 81 | * @param context context to get values from 82 | */ 83 | export function getSpanContext(context: Context): SpanContext | undefined { 84 | return getSpan(context)?.spanContext(); 85 | } 86 | -------------------------------------------------------------------------------- /src/trace/internal/tracestate-impl.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { TraceState } from '../trace_state'; 18 | import { validateKey, validateValue } from './tracestate-validators'; 19 | 20 | const MAX_TRACE_STATE_ITEMS = 32; 21 | const MAX_TRACE_STATE_LEN = 512; 22 | const LIST_MEMBERS_SEPARATOR = ','; 23 | const LIST_MEMBER_KEY_VALUE_SPLITTER = '='; 24 | 25 | /** 26 | * TraceState must be a class and not a simple object type because of the spec 27 | * requirement (https://www.w3.org/TR/trace-context/#tracestate-field). 28 | * 29 | * Here is the list of allowed mutations: 30 | * - New key-value pair should be added into the beginning of the list 31 | * - The value of any key can be updated. Modified keys MUST be moved to the 32 | * beginning of the list. 33 | */ 34 | export class TraceStateImpl implements TraceState { 35 | private _internalState: Map = new Map(); 36 | 37 | constructor(rawTraceState?: string) { 38 | if (rawTraceState) this._parse(rawTraceState); 39 | } 40 | 41 | set(key: string, value: string): TraceStateImpl { 42 | // TODO: Benchmark the different approaches(map vs list) and 43 | // use the faster one. 44 | const traceState = this._clone(); 45 | if (traceState._internalState.has(key)) { 46 | traceState._internalState.delete(key); 47 | } 48 | traceState._internalState.set(key, value); 49 | return traceState; 50 | } 51 | 52 | unset(key: string): TraceStateImpl { 53 | const traceState = this._clone(); 54 | traceState._internalState.delete(key); 55 | return traceState; 56 | } 57 | 58 | get(key: string): string | undefined { 59 | return this._internalState.get(key); 60 | } 61 | 62 | serialize(): string { 63 | return this._keys() 64 | .reduce((agg: string[], key) => { 65 | agg.push(key + LIST_MEMBER_KEY_VALUE_SPLITTER + this.get(key)); 66 | return agg; 67 | }, []) 68 | .join(LIST_MEMBERS_SEPARATOR); 69 | } 70 | 71 | private _parse(rawTraceState: string) { 72 | if (rawTraceState.length > MAX_TRACE_STATE_LEN) return; 73 | this._internalState = rawTraceState 74 | .split(LIST_MEMBERS_SEPARATOR) 75 | .reverse() // Store in reverse so new keys (.set(...)) will be placed at the beginning 76 | .reduce((agg: Map, part: string) => { 77 | const listMember = part.trim(); // Optional Whitespace (OWS) handling 78 | const i = listMember.indexOf(LIST_MEMBER_KEY_VALUE_SPLITTER); 79 | if (i !== -1) { 80 | const key = listMember.slice(0, i); 81 | const value = listMember.slice(i + 1, part.length); 82 | if (validateKey(key) && validateValue(value)) { 83 | agg.set(key, value); 84 | } else { 85 | // TODO: Consider to add warning log 86 | } 87 | } 88 | return agg; 89 | }, new Map()); 90 | 91 | // Because of the reverse() requirement, trunc must be done after map is created 92 | if (this._internalState.size > MAX_TRACE_STATE_ITEMS) { 93 | this._internalState = new Map( 94 | Array.from(this._internalState.entries()) 95 | .reverse() // Use reverse same as original tracestate parse chain 96 | .slice(0, MAX_TRACE_STATE_ITEMS) 97 | ); 98 | } 99 | } 100 | 101 | private _keys(): string[] { 102 | return Array.from(this._internalState.keys()).reverse(); 103 | } 104 | 105 | private _clone(): TraceStateImpl { 106 | const traceState = new TraceStateImpl(); 107 | traceState._internalState = new Map(this._internalState); 108 | return traceState; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/trace/internal/tracestate-validators.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const VALID_KEY_CHAR_RANGE = '[_0-9a-z-*/]'; 18 | const VALID_KEY = `[a-z]${VALID_KEY_CHAR_RANGE}{0,255}`; 19 | const VALID_VENDOR_KEY = `[a-z0-9]${VALID_KEY_CHAR_RANGE}{0,240}@[a-z]${VALID_KEY_CHAR_RANGE}{0,13}`; 20 | const VALID_KEY_REGEX = new RegExp(`^(?:${VALID_KEY}|${VALID_VENDOR_KEY})$`); 21 | const VALID_VALUE_BASE_REGEX = /^[ -~]{0,255}[!-~]$/; 22 | const INVALID_VALUE_COMMA_EQUAL_REGEX = /,|=/; 23 | 24 | /** 25 | * Key is opaque string up to 256 characters printable. It MUST begin with a 26 | * lowercase letter, and can only contain lowercase letters a-z, digits 0-9, 27 | * underscores _, dashes -, asterisks *, and forward slashes /. 28 | * For multi-tenant vendor scenarios, an at sign (@) can be used to prefix the 29 | * vendor name. Vendors SHOULD set the tenant ID at the beginning of the key. 30 | * see https://www.w3.org/TR/trace-context/#key 31 | */ 32 | export function validateKey(key: string): boolean { 33 | return VALID_KEY_REGEX.test(key); 34 | } 35 | 36 | /** 37 | * Value is opaque string up to 256 characters printable ASCII RFC0020 38 | * characters (i.e., the range 0x20 to 0x7E) except comma , and =. 39 | */ 40 | export function validateValue(value: string): boolean { 41 | return ( 42 | VALID_VALUE_BASE_REGEX.test(value) && 43 | !INVALID_VALUE_COMMA_EQUAL_REGEX.test(value) 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /src/trace/internal/utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { TraceState } from '../trace_state'; 18 | import { TraceStateImpl } from './tracestate-impl'; 19 | 20 | 21 | export function createTraceState(rawTraceState?: string): TraceState { 22 | return new TraceStateImpl(rawTraceState); 23 | } 24 | -------------------------------------------------------------------------------- /src/trace/invalid-span-constants.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { SpanContext } from './span_context'; 18 | import { TraceFlags } from './trace_flags'; 19 | 20 | export const INVALID_SPANID = '0000000000000000'; 21 | export const INVALID_TRACEID = '00000000000000000000000000000000'; 22 | export const INVALID_SPAN_CONTEXT: SpanContext = { 23 | traceId: INVALID_TRACEID, 24 | spanId: INVALID_SPANID, 25 | traceFlags: TraceFlags.NONE, 26 | }; 27 | -------------------------------------------------------------------------------- /src/trace/link.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { SpanAttributes } from './attributes'; 18 | import { SpanContext } from './span_context'; 19 | 20 | /** 21 | * A pointer from the current {@link Span} to another span in the same trace or 22 | * in a different trace. 23 | * Few examples of Link usage. 24 | * 1. Batch Processing: A batch of elements may contain elements associated 25 | * with one or more traces/spans. Since there can only be one parent 26 | * SpanContext, Link is used to keep reference to SpanContext of all 27 | * elements in the batch. 28 | * 2. Public Endpoint: A SpanContext in incoming client request on a public 29 | * endpoint is untrusted from service provider perspective. In such case it 30 | * is advisable to start a new trace with appropriate sampling decision. 31 | * However, it is desirable to associate incoming SpanContext to new trace 32 | * initiated on service provider side so two traces (from Client and from 33 | * Service Provider) can be correlated. 34 | */ 35 | export interface Link { 36 | /** The {@link SpanContext} of a linked span. */ 37 | context: SpanContext; 38 | /** A set of {@link SpanAttributes} on the link. */ 39 | attributes?: SpanAttributes; 40 | } 41 | -------------------------------------------------------------------------------- /src/trace/span.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Exception } from '../common/Exception'; 18 | import { TimeInput } from '../common/Time'; 19 | import { SpanAttributes, SpanAttributeValue } from './attributes'; 20 | import { SpanContext } from './span_context'; 21 | import { SpanStatus } from './status'; 22 | 23 | /** 24 | * An interface that represents a span. A span represents a single operation 25 | * within a trace. Examples of span might include remote procedure calls or a 26 | * in-process function calls to sub-components. A Trace has a single, top-level 27 | * "root" Span that in turn may have zero or more child Spans, which in turn 28 | * may have children. 29 | * 30 | * Spans are created by the {@link Tracer.startSpan} method. 31 | */ 32 | export interface Span { 33 | /** 34 | * Returns the {@link SpanContext} object associated with this Span. 35 | * 36 | * Get an immutable, serializable identifier for this span that can be used 37 | * to create new child spans. Returned SpanContext is usable even after the 38 | * span ends. 39 | * 40 | * @returns the SpanContext object associated with this Span. 41 | */ 42 | spanContext(): SpanContext; 43 | 44 | /** 45 | * Sets an attribute to the span. 46 | * 47 | * Sets a single Attribute with the key and value passed as arguments. 48 | * 49 | * @param key the key for this attribute. 50 | * @param value the value for this attribute. Setting a value null or 51 | * undefined is invalid and will result in undefined behavior. 52 | */ 53 | setAttribute(key: string, value: SpanAttributeValue): this; 54 | 55 | /** 56 | * Sets attributes to the span. 57 | * 58 | * @param attributes the attributes that will be added. 59 | * null or undefined attribute values 60 | * are invalid and will result in undefined behavior. 61 | */ 62 | setAttributes(attributes: SpanAttributes): this; 63 | 64 | /** 65 | * Adds an event to the Span. 66 | * 67 | * @param name the name of the event. 68 | * @param [attributesOrStartTime] the attributes that will be added; these are 69 | * associated with this event. Can be also a start time 70 | * if type is {@type TimeInput} and 3rd param is undefined 71 | * @param [startTime] start time of the event. 72 | */ 73 | addEvent( 74 | name: string, 75 | attributesOrStartTime?: SpanAttributes | TimeInput, 76 | startTime?: TimeInput 77 | ): this; 78 | 79 | /** 80 | * Sets a status to the span. If used, this will override the default Span 81 | * status. Default is {@link SpanStatusCode.UNSET}. SetStatus overrides the value 82 | * of previous calls to SetStatus on the Span. 83 | * 84 | * @param status the SpanStatus to set. 85 | */ 86 | setStatus(status: SpanStatus): this; 87 | 88 | /** 89 | * Updates the Span name. 90 | * 91 | * This will override the name provided via {@link Tracer.startSpan}. 92 | * 93 | * Upon this update, any sampling behavior based on Span name will depend on 94 | * the implementation. 95 | * 96 | * @param name the Span name. 97 | */ 98 | updateName(name: string): this; 99 | 100 | /** 101 | * Marks the end of Span execution. 102 | * 103 | * Call to End of a Span MUST not have any effects on child spans. Those may 104 | * still be running and can be ended later. 105 | * 106 | * Do not return `this`. The Span generally should not be used after it 107 | * is ended so chaining is not desired in this context. 108 | * 109 | * @param [endTime] the time to set as Span's end time. If not provided, 110 | * use the current time as the span's end time. 111 | */ 112 | end(endTime?: TimeInput): void; 113 | 114 | /** 115 | * Returns the flag whether this span will be recorded. 116 | * 117 | * @returns true if this Span is active and recording information like events 118 | * with the `AddEvent` operation and attributes using `setAttributes`. 119 | */ 120 | isRecording(): boolean; 121 | 122 | /** 123 | * Sets exception as a span event 124 | * @param exception the exception the only accepted values are string or Error 125 | * @param [time] the time to set as Span's event time. If not provided, 126 | * use the current time. 127 | */ 128 | recordException(exception: Exception, time?: TimeInput): void; 129 | } 130 | -------------------------------------------------------------------------------- /src/trace/span_context.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { TraceState } from './trace_state'; 18 | 19 | /** 20 | * A SpanContext represents the portion of a {@link Span} which must be 21 | * serialized and propagated along side of a {@link Baggage}. 22 | */ 23 | export interface SpanContext { 24 | /** 25 | * The ID of the trace that this span belongs to. It is worldwide unique 26 | * with practically sufficient probability by being made as 16 randomly 27 | * generated bytes, encoded as a 32 lowercase hex characters corresponding to 28 | * 128 bits. 29 | */ 30 | traceId: string; 31 | /** 32 | * The ID of the Span. It is globally unique with practically sufficient 33 | * probability by being made as 8 randomly generated bytes, encoded as a 16 34 | * lowercase hex characters corresponding to 64 bits. 35 | */ 36 | spanId: string; 37 | /** 38 | * Only true if the SpanContext was propagated from a remote parent. 39 | */ 40 | isRemote?: boolean; 41 | /** 42 | * Trace flags to propagate. 43 | * 44 | * It is represented as 1 byte (bitmap). Bit to represent whether trace is 45 | * sampled or not. When set, the least significant bit documents that the 46 | * caller may have recorded trace data. A caller who does not record trace 47 | * data out-of-band leaves this flag unset. 48 | * 49 | * see {@link TraceFlags} for valid flag values. 50 | */ 51 | traceFlags: number; 52 | /** 53 | * Tracing-system-specific info to propagate. 54 | * 55 | * The tracestate field value is a `list` as defined below. The `list` is a 56 | * series of `list-members` separated by commas `,`, and a list-member is a 57 | * key/value pair separated by an equals sign `=`. Spaces and horizontal tabs 58 | * surrounding `list-members` are ignored. There can be a maximum of 32 59 | * `list-members` in a `list`. 60 | * More Info: https://www.w3.org/TR/trace-context/#tracestate-field 61 | * 62 | * Examples: 63 | * Single tracing system (generic format): 64 | * tracestate: rojo=00f067aa0ba902b7 65 | * Multiple tracing systems (with different formatting): 66 | * tracestate: rojo=00f067aa0ba902b7,congo=t61rcWkgMzE 67 | */ 68 | traceState?: TraceState; 69 | } 70 | -------------------------------------------------------------------------------- /src/trace/span_kind.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export enum SpanKind { 17 | /** Default value. Indicates that the span is used internally. */ 18 | INTERNAL = 0, 19 | 20 | /** 21 | * Indicates that the span covers server-side handling of an RPC or other 22 | * remote request. 23 | */ 24 | SERVER = 1, 25 | 26 | /** 27 | * Indicates that the span covers the client-side wrapper around an RPC or 28 | * other remote request. 29 | */ 30 | CLIENT = 2, 31 | 32 | /** 33 | * Indicates that the span describes producer sending a message to a 34 | * broker. Unlike client and server, there is no direct critical path latency 35 | * relationship between producer and consumer spans. 36 | */ 37 | PRODUCER = 3, 38 | 39 | /** 40 | * Indicates that the span describes consumer receiving a message from a 41 | * broker. Unlike client and server, there is no direct critical path latency 42 | * relationship between producer and consumer spans. 43 | */ 44 | CONSUMER = 4, 45 | } 46 | -------------------------------------------------------------------------------- /src/trace/spancontext-utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { INVALID_SPANID, INVALID_TRACEID } from './invalid-span-constants'; 17 | import { NonRecordingSpan } from './NonRecordingSpan'; 18 | import { Span } from './span'; 19 | import { SpanContext } from './span_context'; 20 | 21 | const VALID_TRACEID_REGEX = /^([0-9a-f]{32})$/i; 22 | const VALID_SPANID_REGEX = /^[0-9a-f]{16}$/i; 23 | 24 | export function isValidTraceId(traceId: string): boolean { 25 | return VALID_TRACEID_REGEX.test(traceId) && traceId !== INVALID_TRACEID; 26 | } 27 | 28 | export function isValidSpanId(spanId: string): boolean { 29 | return VALID_SPANID_REGEX.test(spanId) && spanId !== INVALID_SPANID; 30 | } 31 | 32 | /** 33 | * Returns true if this {@link SpanContext} is valid. 34 | * @return true if this {@link SpanContext} is valid. 35 | */ 36 | export function isSpanContextValid(spanContext: SpanContext): boolean { 37 | return ( 38 | isValidTraceId(spanContext.traceId) && isValidSpanId(spanContext.spanId) 39 | ); 40 | } 41 | 42 | /** 43 | * Wrap the given {@link SpanContext} in a new non-recording {@link Span} 44 | * 45 | * @param spanContext span context to be wrapped 46 | * @returns a new non-recording {@link Span} with the provided context 47 | */ 48 | export function wrapSpanContext(spanContext: SpanContext): Span { 49 | return new NonRecordingSpan(spanContext); 50 | } 51 | -------------------------------------------------------------------------------- /src/trace/status.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export interface SpanStatus { 17 | /** The status code of this message. */ 18 | code: SpanStatusCode; 19 | /** A developer-facing error message. */ 20 | message?: string; 21 | } 22 | 23 | /** 24 | * An enumeration of status codes. 25 | */ 26 | export enum SpanStatusCode { 27 | /** 28 | * The default status. 29 | */ 30 | UNSET = 0, 31 | /** 32 | * The operation has been validated by an Application developer or 33 | * Operator to have completed successfully. 34 | */ 35 | OK = 1, 36 | /** 37 | * The operation contains an error. 38 | */ 39 | ERROR = 2, 40 | } 41 | -------------------------------------------------------------------------------- /src/trace/trace_flags.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export enum TraceFlags { 17 | /** Represents no flag set. */ 18 | NONE = 0x0, 19 | /** Bit to represent whether trace is sampled in trace flags. */ 20 | SAMPLED = 0x1 << 0, 21 | } 22 | -------------------------------------------------------------------------------- /src/trace/trace_state.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export interface TraceState { 18 | /** 19 | * Create a new TraceState which inherits from this TraceState and has the 20 | * given key set. 21 | * The new entry will always be added in the front of the list of states. 22 | * 23 | * @param key key of the TraceState entry. 24 | * @param value value of the TraceState entry. 25 | */ 26 | set(key: string, value: string): TraceState; 27 | 28 | /** 29 | * Return a new TraceState which inherits from this TraceState but does not 30 | * contain the given key. 31 | * 32 | * @param key the key for the TraceState entry to be removed. 33 | */ 34 | unset(key: string): TraceState; 35 | 36 | /** 37 | * Returns the value to which the specified key is mapped, or `undefined` if 38 | * this map contains no mapping for the key. 39 | * 40 | * @param key with which the specified value is to be associated. 41 | * @returns the value to which the specified key is mapped, or `undefined` if 42 | * this map contains no mapping for the key. 43 | */ 44 | get(key: string): string | undefined; 45 | 46 | // TODO: Consider to add support for merging an object as well by also 47 | // accepting a single internalTraceState argument similar to the constructor. 48 | 49 | /** 50 | * Serializes the TraceState to a `list` as defined below. The `list` is a 51 | * series of `list-members` separated by commas `,`, and a list-member is a 52 | * key/value pair separated by an equals sign `=`. Spaces and horizontal tabs 53 | * surrounding `list-members` are ignored. There can be a maximum of 32 54 | * `list-members` in a `list`. 55 | * 56 | * @returns the serialized string. 57 | */ 58 | serialize(): string; 59 | } 60 | -------------------------------------------------------------------------------- /src/trace/tracer.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Context } from '../context/types'; 18 | import { Span } from './span'; 19 | import { SpanOptions } from './SpanOptions'; 20 | 21 | /** 22 | * Tracer provides an interface for creating {@link Span}s. 23 | */ 24 | export interface Tracer { 25 | /** 26 | * Starts a new {@link Span}. Start the span without setting it on context. 27 | * 28 | * This method do NOT modify the current Context. 29 | * 30 | * @param name The name of the span 31 | * @param [options] SpanOptions used for span creation 32 | * @param [context] Context to use to extract parent 33 | * @returns Span The newly created span 34 | * @example 35 | * const span = tracer.startSpan('op'); 36 | * span.setAttribute('key', 'value'); 37 | * span.end(); 38 | */ 39 | startSpan(name: string, options?: SpanOptions, context?: Context): Span; 40 | 41 | /** 42 | * Starts a new {@link Span} and calls the given function passing it the 43 | * created span as first argument. 44 | * Additionally the new span gets set in context and this context is activated 45 | * for the duration of the function call. 46 | * 47 | * @param name The name of the span 48 | * @param [options] SpanOptions used for span creation 49 | * @param [context] Context to use to extract parent 50 | * @param fn function called in the context of the span and receives the newly created span as an argument 51 | * @returns return value of fn 52 | * @example 53 | * const something = tracer.startActiveSpan('op', span => { 54 | * try { 55 | * do some work 56 | * span.setStatus({code: SpanStatusCode.OK}); 57 | * return something; 58 | * } catch (err) { 59 | * span.setStatus({ 60 | * code: SpanStatusCode.ERROR, 61 | * message: err.message, 62 | * }); 63 | * throw err; 64 | * } finally { 65 | * span.end(); 66 | * } 67 | * }); 68 | * 69 | * @example 70 | * const span = tracer.startActiveSpan('op', span => { 71 | * try { 72 | * do some work 73 | * return span; 74 | * } catch (err) { 75 | * span.setStatus({ 76 | * code: SpanStatusCode.ERROR, 77 | * message: err.message, 78 | * }); 79 | * throw err; 80 | * } 81 | * }); 82 | * do some more work 83 | * span.end(); 84 | */ 85 | startActiveSpan unknown>( 86 | name: string, 87 | fn: F 88 | ): ReturnType; 89 | startActiveSpan unknown>( 90 | name: string, 91 | options: SpanOptions, 92 | fn: F 93 | ): ReturnType; 94 | startActiveSpan unknown>( 95 | name: string, 96 | options: SpanOptions, 97 | context: Context, 98 | fn: F 99 | ): ReturnType; 100 | } 101 | -------------------------------------------------------------------------------- /src/trace/tracer_options.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * An interface describes additional metadata of a tracer. 19 | */ 20 | export interface TracerOptions { 21 | /** 22 | * The schemaUrl of the tracer or instrumentation library 23 | */ 24 | schemaUrl?: string; 25 | } 26 | -------------------------------------------------------------------------------- /src/trace/tracer_provider.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Tracer } from './tracer'; 18 | import { TracerOptions } from './tracer_options'; 19 | 20 | /** 21 | * A registry for creating named {@link Tracer}s. 22 | */ 23 | export interface TracerProvider { 24 | /** 25 | * Returns a Tracer, creating one if one with the given name and version is 26 | * not already created. 27 | * 28 | * This function may return different Tracer types (e.g. 29 | * {@link NoopTracerProvider} vs. a functional tracer). 30 | * 31 | * @param name The name of the tracer or instrumentation library. 32 | * @param version The version of the tracer or instrumentation library. 33 | * @param options The options of the tracer or instrumentation library. 34 | * @returns Tracer A Tracer with the given name and version 35 | */ 36 | getTracer(name: string, version?: string, options?: TracerOptions): Tracer; 37 | } 38 | -------------------------------------------------------------------------------- /test/baggage/Baggage.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { 19 | ROOT_CONTEXT, 20 | propagation, 21 | baggageEntryMetadataFromString, 22 | } from '../../src'; 23 | 24 | describe('Baggage', () => { 25 | describe('create', () => { 26 | it('should create an empty bag', () => { 27 | const bag = propagation.createBaggage(); 28 | 29 | assert.deepStrictEqual(bag.getAllEntries(), []); 30 | }); 31 | 32 | it('should create a bag with entries', () => { 33 | const meta = baggageEntryMetadataFromString('opaque string'); 34 | const bag = propagation.createBaggage({ 35 | key1: { value: 'value1' }, 36 | key2: { value: 'value2', metadata: meta }, 37 | }); 38 | 39 | assert.deepStrictEqual(bag.getAllEntries(), [ 40 | ['key1', { value: 'value1' }], 41 | ['key2', { value: 'value2', metadata: meta }], 42 | ]); 43 | }); 44 | }); 45 | 46 | describe('get', () => { 47 | it('should not allow modification of returned entries', () => { 48 | const bag = propagation 49 | .createBaggage() 50 | .setEntry('key', { value: 'value' }); 51 | 52 | const entry = bag.getEntry('key'); 53 | assert.ok(entry); 54 | entry.value = 'mutated'; 55 | 56 | assert.strictEqual(bag.getEntry('key')?.value, 'value'); 57 | }); 58 | }); 59 | 60 | describe('set', () => { 61 | it('should create a new bag when an entry is added', () => { 62 | const bag = propagation.createBaggage(); 63 | 64 | const bag2 = bag.setEntry('key', { value: 'value' }); 65 | 66 | assert.notStrictEqual(bag, bag2); 67 | assert.deepStrictEqual(bag.getAllEntries(), []); 68 | assert.deepStrictEqual(bag2.getAllEntries(), [ 69 | ['key', { value: 'value' }], 70 | ]); 71 | }); 72 | }); 73 | 74 | describe('remove', () => { 75 | it('should create a new bag when an entry is removed', () => { 76 | const bag = propagation.createBaggage({ 77 | key: { value: 'value' }, 78 | }); 79 | 80 | const bag2 = bag.removeEntry('key'); 81 | 82 | assert.deepStrictEqual(bag.getAllEntries(), [ 83 | ['key', { value: 'value' }], 84 | ]); 85 | 86 | assert.deepStrictEqual(bag2.getAllEntries(), []); 87 | }); 88 | 89 | it('should create an empty bag multiple keys are removed', () => { 90 | const bag = propagation.createBaggage({ 91 | key: { value: 'value' }, 92 | key1: { value: 'value1' }, 93 | key2: { value: 'value2' }, 94 | }); 95 | 96 | const bag2 = bag.removeEntries('key', 'key1'); 97 | 98 | assert.deepStrictEqual(bag.getAllEntries(), [ 99 | ['key', { value: 'value' }], 100 | ['key1', { value: 'value1' }], 101 | ['key2', { value: 'value2' }], 102 | ]); 103 | 104 | assert.deepStrictEqual(bag2.getAllEntries(), [ 105 | ['key2', { value: 'value2' }], 106 | ]); 107 | }); 108 | 109 | it('should create an empty bag when it cleared', () => { 110 | const bag = propagation.createBaggage({ 111 | key: { value: 'value' }, 112 | key1: { value: 'value1' }, 113 | }); 114 | 115 | const bag2 = bag.clear(); 116 | 117 | assert.deepStrictEqual(bag.getAllEntries(), [ 118 | ['key', { value: 'value' }], 119 | ['key1', { value: 'value1' }], 120 | ]); 121 | 122 | assert.deepStrictEqual(bag2.getAllEntries(), []); 123 | }); 124 | }); 125 | 126 | describe('context', () => { 127 | it('should set and get a baggage from a context', () => { 128 | const bag = propagation.createBaggage(); 129 | 130 | const ctx = propagation.setBaggage(ROOT_CONTEXT, bag); 131 | 132 | assert.strictEqual(bag, propagation.getBaggage(ctx)); 133 | }); 134 | }); 135 | 136 | describe('metadata', () => { 137 | it('should create an opaque object which returns the string unchanged', () => { 138 | const meta = baggageEntryMetadataFromString('this is a string'); 139 | 140 | assert.strictEqual(meta.toString(), 'this is a string'); 141 | }); 142 | 143 | it('should return an empty string if input is invalid', () => { 144 | //@ts-expect-error only accepts string values 145 | const meta = baggageEntryMetadataFromString(1); 146 | 147 | assert.strictEqual(meta.toString(), ''); 148 | }); 149 | 150 | it('should retain metadata', () => { 151 | const bag = propagation.createBaggage({ 152 | key: { 153 | value: 'value', 154 | metadata: baggageEntryMetadataFromString('meta'), 155 | }, 156 | }); 157 | 158 | assert.deepStrictEqual(bag.getEntry('key')?.metadata?.toString(), 'meta'); 159 | }); 160 | }); 161 | }); 162 | -------------------------------------------------------------------------------- /test/context/NoopContextManager.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { createContextKey, ROOT_CONTEXT } from '../../src/context/context'; 19 | import { NoopContextManager } from '../../src/context/NoopContextManager'; 20 | 21 | describe('NoopContextManager', () => { 22 | let contextManager: NoopContextManager; 23 | 24 | describe('.enable()', () => { 25 | it('should work', () => { 26 | assert.doesNotThrow(() => { 27 | contextManager = new NoopContextManager(); 28 | assert( 29 | contextManager.enable() === contextManager, 30 | 'should return this' 31 | ); 32 | }); 33 | }); 34 | }); 35 | 36 | describe('.disable()', () => { 37 | it('should work', () => { 38 | assert.doesNotThrow(() => { 39 | assert( 40 | contextManager.disable() === contextManager, 41 | 'should return this' 42 | ); 43 | }); 44 | contextManager.enable(); 45 | }); 46 | }); 47 | 48 | describe('.with()', () => { 49 | it('should run the callback (ROOT_CONTEXT as target)', done => { 50 | contextManager.with(ROOT_CONTEXT, done); 51 | }); 52 | 53 | it('should run the callback (object as target)', done => { 54 | const key = createContextKey('test key 1'); 55 | const test = ROOT_CONTEXT.setValue(key, 1); 56 | contextManager.with(test, () => { 57 | assert.strictEqual( 58 | contextManager.active(), 59 | ROOT_CONTEXT, 60 | 'should not have context' 61 | ); 62 | return done(); 63 | }); 64 | }); 65 | 66 | it('should run the callback (when disabled)', done => { 67 | contextManager.disable(); 68 | contextManager.with(ROOT_CONTEXT, () => { 69 | contextManager.enable(); 70 | return done(); 71 | }); 72 | }); 73 | 74 | it('should forward this, arguments and return value', () => { 75 | function fnWithThis(this: string, a: string, b: number): string { 76 | assert.strictEqual(this, 'that'); 77 | assert.strictEqual(arguments.length, 2); 78 | assert.strictEqual(a, 'one'); 79 | assert.strictEqual(b, 2); 80 | return 'done'; 81 | } 82 | 83 | const res = contextManager.with( 84 | ROOT_CONTEXT, 85 | fnWithThis, 86 | 'that', 87 | 'one', 88 | 2 89 | ); 90 | assert.strictEqual(res, 'done'); 91 | 92 | assert.strictEqual( 93 | contextManager.with(ROOT_CONTEXT, () => 3.14), 94 | 3.14 95 | ); 96 | }); 97 | }); 98 | 99 | describe('.active()', () => { 100 | it('should always return ROOT_CONTEXT (when enabled)', () => { 101 | assert.strictEqual( 102 | contextManager.active(), 103 | ROOT_CONTEXT, 104 | 'should not have context' 105 | ); 106 | }); 107 | 108 | it('should always return ROOT_CONTEXT (when disabled)', () => { 109 | contextManager.disable(); 110 | assert.strictEqual( 111 | contextManager.active(), 112 | ROOT_CONTEXT, 113 | 'should not have context' 114 | ); 115 | contextManager.enable(); 116 | }); 117 | }); 118 | 119 | describe('.bind()', () => { 120 | it('should return the same target (when enabled)', () => { 121 | const test = { a: 1 }; 122 | assert.deepStrictEqual( 123 | contextManager.bind(contextManager.active(), test), 124 | test 125 | ); 126 | }); 127 | 128 | it('should return the same target (when disabled)', () => { 129 | contextManager.disable(); 130 | const test = { a: 1 }; 131 | assert.deepStrictEqual( 132 | contextManager.bind(contextManager.active(), test), 133 | test 134 | ); 135 | contextManager.enable(); 136 | }); 137 | }); 138 | }); 139 | -------------------------------------------------------------------------------- /test/diag/ComponentLogger.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import * as sinon from 'sinon'; 19 | import { diag, DiagLogger, DiagLogLevel } from '../../src'; 20 | 21 | class SpyLogger implements DiagLogger { 22 | debug() {} 23 | error() {} 24 | info() {} 25 | warn() {} 26 | verbose() {} 27 | } 28 | 29 | const loggerFunctions = ['verbose', 'debug', 'info', 'warn', 'error']; 30 | 31 | describe('ComponentLogger', () => { 32 | let logger: DiagLogger; 33 | 34 | const sandbox = sinon.createSandbox(); 35 | 36 | beforeEach(() => { 37 | logger = new SpyLogger(); 38 | sandbox.spy(logger); 39 | diag.setLogger(logger, DiagLogLevel.ALL); 40 | // clean any messages up that might be there from the registration 41 | sandbox.reset(); 42 | }); 43 | 44 | afterEach(() => { 45 | sandbox.restore(); 46 | }); 47 | 48 | loggerFunctions.forEach(name => { 49 | const fName = name as keyof SpyLogger; 50 | it(`should call global logger function "${name}" with namespace as first param`, () => { 51 | const componentLogger = diag.createComponentLogger({ namespace: 'foo' }); 52 | componentLogger[fName]('test'); 53 | 54 | assert.strictEqual((logger[fName] as sinon.SinonSpy).callCount, 1); 55 | assert.deepStrictEqual((logger[fName] as sinon.SinonSpy).args[0], [ 56 | 'foo', 57 | 'test', 58 | ]); 59 | }); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /test/diag/consoleLogger.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable no-console */ 18 | 19 | import * as assert from 'assert'; 20 | import { DiagConsoleLogger } from '../../src/diag/consoleLogger'; 21 | 22 | export const diagLoggerFunctions = [ 23 | 'verbose', 24 | 'debug', 25 | 'info', 26 | 'warn', 27 | 'error', 28 | ] as const; 29 | 30 | const consoleFuncs: Array = [ 31 | 'debug', 32 | 'info', 33 | 'warn', 34 | 'error', 35 | 'log', 36 | 'trace', 37 | ]; 38 | 39 | const expectedConsoleMap: { [n: string]: keyof Console } = { 40 | error: 'error', 41 | warn: 'warn', 42 | info: 'info', 43 | debug: 'debug', 44 | verbose: 'trace', 45 | }; 46 | 47 | describe('DiagConsoleLogger', () => { 48 | const origConsole = console; 49 | const orig: any = {}; 50 | const calledArgs: any = {}; 51 | 52 | // Save original functions 53 | consoleFuncs.forEach(fName => { 54 | orig[fName] = console[fName]; 55 | calledArgs[fName] = null; 56 | }); 57 | 58 | let canMockConsole = true; 59 | 60 | try { 61 | // eslint-disable-next-line no-global-assign 62 | console = origConsole; 63 | } catch (ex) { 64 | // Not supported on CI pipeline (works locally) 65 | canMockConsole = false; 66 | } 67 | 68 | beforeEach(() => { 69 | // mock Console 70 | consoleFuncs.forEach(fName => { 71 | console[fName] = (...args: unknown[]) => { 72 | calledArgs[fName] = args; 73 | }; 74 | }); 75 | }); 76 | 77 | afterEach(() => { 78 | // restore 79 | if (canMockConsole) { 80 | try { 81 | // eslint-disable-next-line no-global-assign 82 | console = origConsole; 83 | } catch (ex) { 84 | // Not supported on CI pipeline 85 | canMockConsole = false; 86 | } 87 | } 88 | 89 | consoleFuncs.forEach(fName => { 90 | calledArgs[fName] = null; 91 | console[fName] = orig[fName]; 92 | }); 93 | }); 94 | 95 | describe('constructor', () => { 96 | diagLoggerFunctions.forEach(fName => { 97 | it(`console logger should provide ${fName} function`, () => { 98 | const consoleLogger: any = new DiagConsoleLogger(); 99 | consoleLogger[fName](`${fName} called %s`, 'param1'); 100 | assert.ok( 101 | typeof consoleLogger[fName] === 'function', 102 | `Must have a ${fName} function` 103 | ); 104 | }); 105 | 106 | it(`should log ${expectedConsoleMap[fName]} message with ${fName} call only`, () => { 107 | const consoleLogger: any = new DiagConsoleLogger(); 108 | consoleLogger[fName](`${fName} called %s`, 'param1'); 109 | 110 | // Make sure only gets logged once 111 | let matches = 0; 112 | consoleFuncs.forEach(cName => { 113 | if (cName !== expectedConsoleMap[fName]) { 114 | assert.deepStrictEqual(calledArgs[cName], null); 115 | } else { 116 | assert.deepStrictEqual(calledArgs[expectedConsoleMap[fName]], [ 117 | `${fName} called %s`, 118 | 'param1', 119 | ]); 120 | matches++; 121 | } 122 | }); 123 | 124 | assert.deepStrictEqual(calledArgs.log, null); 125 | assert.strictEqual(matches, 1, 'should log at least once'); 126 | }); 127 | 128 | consoleFuncs.forEach(cName => { 129 | it(`should log ${fName} message even when console doesn't support ${cName} call before construction`, () => { 130 | console[cName] = undefined; 131 | const consoleLogger: any = new DiagConsoleLogger(); 132 | consoleLogger[fName](`${fName} called %s`, 'param1'); 133 | if (cName !== expectedConsoleMap[fName]) { 134 | assert.deepStrictEqual(calledArgs[cName], null); 135 | } else { 136 | assert.deepStrictEqual(calledArgs.log, [ 137 | `${fName} called %s`, 138 | 'param1', 139 | ]); 140 | } 141 | }); 142 | 143 | it(`should log ${fName} message even when console doesn't support ${cName} call after construction`, () => { 144 | const consoleLogger: any = new DiagConsoleLogger(); 145 | console[cName] = undefined; 146 | consoleLogger[fName](`${fName} called %s`, 'param1'); 147 | if (cName !== expectedConsoleMap[fName]) { 148 | assert.deepStrictEqual(calledArgs[cName], null); 149 | } else { 150 | assert.deepStrictEqual(calledArgs.log, [ 151 | `${fName} called %s`, 152 | 'param1', 153 | ]); 154 | } 155 | }); 156 | }); 157 | }); 158 | 159 | if (canMockConsole) { 160 | diagLoggerFunctions.forEach(fName => { 161 | const cName = expectedConsoleMap[fName]; 162 | it(`should not throw even when console is not supported for ${fName} call`, () => { 163 | // eslint-disable-next-line no-global-assign 164 | (console as any) = undefined; 165 | const consoleLogger: any = new DiagConsoleLogger(); 166 | consoleLogger[fName](`${fName} called %s`, 'param1'); 167 | assert.deepStrictEqual(calledArgs[cName], null); 168 | assert.deepStrictEqual(calledArgs.log, null); 169 | }); 170 | 171 | it(`should not throw even when console is disabled after construction for ${fName} call`, () => { 172 | const consoleLogger: any = new DiagConsoleLogger(); 173 | // eslint-disable-next-line no-global-assign 174 | (console as any) = undefined; 175 | consoleLogger[fName](`${fName} called %s`, 'param1'); 176 | assert.deepStrictEqual(calledArgs[expectedConsoleMap[fName]], null); 177 | assert.deepStrictEqual(calledArgs.log, null); 178 | }); 179 | 180 | it(`should not throw even when console is invalid after construction for ${fName} call`, () => { 181 | const invalidConsole = { 182 | debug: 1, 183 | warn: 2, 184 | error: 3, 185 | trace: 4, 186 | info: 5, 187 | log: 6, 188 | }; 189 | 190 | const consoleLogger = new DiagConsoleLogger(); 191 | // eslint-disable-next-line no-global-assign 192 | (console as any) = invalidConsole; 193 | consoleLogger[fName](`${fName} called %s`, 'param1'); 194 | assert.deepStrictEqual(calledArgs[expectedConsoleMap[fName]], null); 195 | assert.deepStrictEqual(calledArgs.log, null); 196 | }); 197 | 198 | it(`should not throw even when console is invalid before construction for ${fName} call`, () => { 199 | const invalidConsole = { 200 | debug: 1, 201 | warn: 2, 202 | error: 3, 203 | trace: 4, 204 | info: 5, 205 | log: 6, 206 | }; 207 | 208 | // eslint-disable-next-line no-global-assign 209 | (console as any) = invalidConsole; 210 | const consoleLogger = new DiagConsoleLogger(); 211 | consoleLogger[fName](`${fName} called %s`, 'param1'); 212 | assert.deepStrictEqual(calledArgs[expectedConsoleMap[fName]], null); 213 | assert.deepStrictEqual(calledArgs.log, null); 214 | }); 215 | }); 216 | } 217 | }); 218 | }); 219 | -------------------------------------------------------------------------------- /test/diag/logger.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import sinon = require('sinon'); 19 | import { diag, DiagLogLevel } from '../../src'; 20 | import { createNoopDiagLogger } from '../../src/diag/internal/noopLogger'; 21 | import { DiagLogger } from '../../src/diag/types'; 22 | 23 | export const diagLoggerFunctions = [ 24 | 'verbose', 25 | 'debug', 26 | 'info', 27 | 'warn', 28 | 'error', 29 | ] as const; 30 | describe('DiagLogger functions', () => { 31 | const calledArgs: any = { 32 | error: null, 33 | warn: null, 34 | info: null, 35 | debug: null, 36 | verbose: null, 37 | }; 38 | 39 | let dummyLogger: DiagLogger; 40 | 41 | const restoreCallHistory = () => { 42 | diagLoggerFunctions.forEach(fName => { 43 | calledArgs[fName] = null; 44 | }); 45 | }; 46 | 47 | beforeEach(() => { 48 | // mock 49 | dummyLogger = {} as DiagLogger; 50 | diagLoggerFunctions.forEach(fName => { 51 | dummyLogger[fName] = (...args: unknown[]) => { 52 | calledArgs[fName] = args; 53 | }; 54 | }); 55 | }); 56 | 57 | afterEach(() => { 58 | restoreCallHistory(); 59 | diag.disable(); 60 | }); 61 | 62 | describe('constructor', () => { 63 | diagLoggerFunctions.forEach(fName => { 64 | it(`should log with ${fName} message`, () => { 65 | const testLogger = dummyLogger; 66 | testLogger[fName](`${fName} called %s`, 'param1'); 67 | diagLoggerFunctions.forEach(lName => { 68 | if (fName === lName) { 69 | assert.deepStrictEqual(calledArgs[fName], [ 70 | `${fName} called %s`, 71 | 'param1', 72 | ]); 73 | } else { 74 | assert.strictEqual(calledArgs[lName], null); 75 | } 76 | }); 77 | }); 78 | 79 | it(`diag should log with ${fName} message`, () => { 80 | diag.setLogger(dummyLogger, DiagLogLevel.ALL); 81 | restoreCallHistory(); 82 | diag[fName](`${fName} called %s`, 'param1'); 83 | diagLoggerFunctions.forEach(lName => { 84 | if (fName === lName) { 85 | assert.deepStrictEqual(calledArgs[fName], [ 86 | `${fName} called %s`, 87 | 'param1', 88 | ]); 89 | } else { 90 | assert.strictEqual(calledArgs[lName], null); 91 | } 92 | }); 93 | }); 94 | 95 | it(`NoopLogger should implement all functions and not throw when ${fName} called`, () => { 96 | const testLogger = createNoopDiagLogger(); 97 | 98 | assert.ok(typeof testLogger[fName], 'function'); 99 | testLogger[fName](`${fName} called %s`, 'param1'); 100 | }); 101 | }); 102 | }); 103 | 104 | describe('diag is used as the diag logger in setLogger', () => { 105 | it('should not throw', () => { 106 | diag.setLogger(diag); 107 | }); 108 | 109 | it('should use the previously registered logger to log the error', () => { 110 | const error = sinon.stub(); 111 | diag.setLogger({ 112 | verbose: () => {}, 113 | debug: () => {}, 114 | info: () => {}, 115 | warn: () => {}, 116 | error, 117 | }); 118 | 119 | sinon.assert.notCalled(error); 120 | 121 | diag.setLogger(diag); 122 | 123 | sinon.assert.calledOnce(error); 124 | }); 125 | }); 126 | }); 127 | -------------------------------------------------------------------------------- /test/index-webpack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | const testsContext = require.context('.', true, /test$/); 17 | testsContext.keys().forEach(testsContext); 18 | 19 | const srcContext = require.context('.', true, /src$/); 20 | srcContext.keys().forEach(srcContext); 21 | -------------------------------------------------------------------------------- /test/internal/global.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { getGlobal } from '../../src/internal/global-utils'; 19 | import { _globalThis } from '../../src/platform'; 20 | import { NoopContextManager } from '../../src/context/NoopContextManager'; 21 | import { DiagLogLevel } from '../../src/diag/types'; 22 | import sinon = require('sinon'); 23 | 24 | const api1 = require('../../src') as typeof import('../../src'); 25 | 26 | // clear cache and load a second instance of the api 27 | for (const key of Object.keys(require.cache)) { 28 | delete require.cache[key]; 29 | } 30 | const api2 = require('../../src') as typeof import('../../src'); 31 | 32 | // This will need to be changed manually on major version changes. 33 | // It is intentionally not autogenerated to ensure the author of the change is aware of what they are doing. 34 | const GLOBAL_API_SYMBOL_KEY = 'opentelemetry.js.api.1'; 35 | 36 | const getMockLogger = () => ({ 37 | verbose: sinon.spy(), 38 | debug: sinon.spy(), 39 | info: sinon.spy(), 40 | warn: sinon.spy(), 41 | error: sinon.spy(), 42 | }); 43 | 44 | describe('Global Utils', () => { 45 | // prove they are separate instances 46 | assert.notEqual(api1, api2); 47 | // that return separate noop instances to start 48 | assert.notStrictEqual( 49 | api1.context['_getContextManager'](), 50 | api2.context['_getContextManager']() 51 | ); 52 | 53 | beforeEach(() => { 54 | api1.context.disable(); 55 | api1.propagation.disable(); 56 | api1.trace.disable(); 57 | api1.diag.disable(); 58 | // @ts-expect-error we are modifying internals for testing purposes here 59 | delete _globalThis[Symbol.for(GLOBAL_API_SYMBOL_KEY)]; 60 | }); 61 | 62 | it('should change the global context manager', () => { 63 | const original = api1.context['_getContextManager'](); 64 | const newContextManager = new NoopContextManager(); 65 | api1.context.setGlobalContextManager(newContextManager); 66 | assert.notStrictEqual(api1.context['_getContextManager'](), original); 67 | assert.strictEqual(api1.context['_getContextManager'](), newContextManager); 68 | }); 69 | 70 | it('should load an instance from one which was set in the other', () => { 71 | api1.context.setGlobalContextManager(new NoopContextManager()); 72 | assert.strictEqual( 73 | api1.context['_getContextManager'](), 74 | api2.context['_getContextManager']() 75 | ); 76 | }); 77 | 78 | it('should disable both if one is disabled', () => { 79 | const manager = new NoopContextManager(); 80 | api1.context.setGlobalContextManager(manager); 81 | 82 | assert.strictEqual(manager, api1.context['_getContextManager']()); 83 | api2.context.disable(); 84 | assert.notStrictEqual(manager, api1.context['_getContextManager']()); 85 | }); 86 | 87 | it('should return the module NoOp implementation if the version is a mismatch', () => { 88 | const newContextManager = new NoopContextManager(); 89 | api1.context.setGlobalContextManager(newContextManager); 90 | 91 | // ensure new context manager is returned 92 | assert.strictEqual(api1.context['_getContextManager'](), newContextManager); 93 | 94 | const globalInstance = getGlobal('context'); 95 | assert.ok(globalInstance); 96 | // @ts-expect-error we are modifying internals for testing purposes here 97 | _globalThis[Symbol.for(GLOBAL_API_SYMBOL_KEY)].version = '0.0.1'; 98 | 99 | // ensure new context manager is not returned because version above is incompatible 100 | assert.notStrictEqual( 101 | api1.context['_getContextManager'](), 102 | newContextManager 103 | ); 104 | }); 105 | 106 | it('should debug log registrations', () => { 107 | const logger = getMockLogger(); 108 | api1.diag.setLogger(logger, DiagLogLevel.DEBUG); 109 | 110 | const newContextManager = new NoopContextManager(); 111 | api1.context.setGlobalContextManager(newContextManager); 112 | 113 | sinon.assert.calledWith(logger.debug, sinon.match(/global for context/)); 114 | sinon.assert.calledWith(logger.debug, sinon.match(/global for diag/)); 115 | sinon.assert.calledTwice(logger.debug); 116 | }); 117 | 118 | it('should log an error if there is a duplicate registration', () => { 119 | const logger = getMockLogger(); 120 | api1.diag.setLogger(logger); 121 | 122 | api1.context.setGlobalContextManager(new NoopContextManager()); 123 | api1.context.setGlobalContextManager(new NoopContextManager()); 124 | 125 | sinon.assert.calledOnce(logger.error); 126 | assert.strictEqual(logger.error.firstCall.args.length, 1); 127 | assert.ok( 128 | logger.error.firstCall.args[0].startsWith( 129 | 'Error: @opentelemetry/api: Attempted duplicate registration of API: context' 130 | ) 131 | ); 132 | }); 133 | 134 | it('should allow duplicate registration of the diag logger', () => { 135 | const logger1 = getMockLogger(); 136 | const logger2 = getMockLogger(); 137 | 138 | api1.diag.setLogger(logger1); 139 | api1.diag.setLogger(logger2); 140 | 141 | const MSG = '__log message__'; 142 | api1.diag.info(MSG); 143 | 144 | sinon.assert.notCalled(logger1.error); 145 | sinon.assert.notCalled(logger1.info); 146 | sinon.assert.calledOnce(logger1.warn); 147 | sinon.assert.calledWith(logger1.warn, sinon.match(/will be overwritten/i)); 148 | 149 | sinon.assert.notCalled(logger2.error); 150 | sinon.assert.calledOnce(logger2.warn); 151 | sinon.assert.calledWith(logger2.warn, sinon.match(/will overwrite/i)); 152 | sinon.assert.calledOnce(logger2.info); 153 | sinon.assert.calledWith(logger2.info, MSG); 154 | }); 155 | }); 156 | -------------------------------------------------------------------------------- /test/internal/semver.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { 19 | isCompatible, 20 | _makeCompatibilityCheck, 21 | } from '../../src/internal/semver'; 22 | import { VERSION } from '../../src/version'; 23 | 24 | describe('semver', () => { 25 | it('should be compatible if versions are equal', () => { 26 | assert.ok(isCompatible(VERSION)); 27 | }); 28 | 29 | it('returns false if own version cannot be parsed', () => { 30 | const check = _makeCompatibilityCheck('this is not semver'); 31 | assert.ok(!check('1.0.0')); 32 | }); 33 | 34 | it('incompatible if other version cannot be parsed', () => { 35 | const check = _makeCompatibilityCheck('0.1.2'); 36 | assert.ok(!check('this is not semver')); 37 | }); 38 | 39 | describe('>= 1.0.0', () => { 40 | const globalVersion = '5.5.5'; 41 | const vers: [string, boolean][] = [ 42 | // same major/minor run should be compatible 43 | ['5.5.5', true], 44 | ['5.5.6', true], 45 | ['5.5.4', true], 46 | 47 | // prerelease version should not be compatible 48 | ['5.5.5-rc.0', false], 49 | 50 | // if our version has a minor version increase, we may try to call methods which don't exist on the global 51 | ['5.6.5', false], 52 | ['5.6.6', false], 53 | ['5.6.4', false], 54 | 55 | // if the global version is ahead of us by a minor revision, it has at least the methods we know about 56 | ['5.4.5', true], 57 | ['5.4.6', true], 58 | ['5.4.4', true], 59 | 60 | // major version mismatch is always incompatible 61 | ['6.5.5', false], 62 | ['6.5.6', false], 63 | ['6.5.4', false], 64 | ['6.6.5', false], 65 | ['6.6.6', false], 66 | ['6.6.4', false], 67 | ['6.4.5', false], 68 | ['6.4.6', false], 69 | ['6.4.4', false], 70 | ['4.5.5', false], 71 | ['4.5.6', false], 72 | ['4.5.4', false], 73 | ['4.6.5', false], 74 | ['4.6.6', false], 75 | ['4.6.4', false], 76 | ['4.4.5', false], 77 | ['4.4.6', false], 78 | ['4.4.4', false], 79 | ]; 80 | 81 | test(globalVersion, vers); 82 | }); 83 | 84 | describe('< 1.0.0', () => { 85 | const globalVersion = '0.5.5'; 86 | const vers: [string, boolean][] = [ 87 | // same minor/patch should be compatible 88 | ['0.5.5', true], 89 | 90 | // prerelease version should not be compatible 91 | ['0.5.5-rc.0', false], 92 | 93 | // if our version has a patch version increase, we may try to call methods which don't exist on the global 94 | ['0.5.6', false], 95 | 96 | // if the global version is ahead of us by a patch revision, it has at least the methods we know about 97 | ['0.5.4', true], 98 | 99 | // minor version mismatch is always incompatible 100 | ['0.6.5', false], 101 | ['0.6.6', false], 102 | ['0.6.4', false], 103 | ['0.4.5', false], 104 | ['0.4.6', false], 105 | ['0.4.4', false], 106 | 107 | // major version mismatch is always incompatible 108 | ['1.5.5', false], 109 | ['1.5.6', false], 110 | ['1.5.4', false], 111 | ['1.6.5', false], 112 | ['1.6.6', false], 113 | ['1.6.4', false], 114 | ['1.4.5', false], 115 | ['1.4.6', false], 116 | ['1.4.4', false], 117 | ]; 118 | 119 | test(globalVersion, vers); 120 | }); 121 | 122 | describe('global version is prerelease', () => { 123 | const globalVersion = '1.0.0-rc.3'; 124 | const vers: [string, boolean][] = [ 125 | // must match exactly 126 | ['1.0.0', false], 127 | ['1.0.0-rc.2', false], 128 | ['1.0.0-rc.4', false], 129 | 130 | ['1.0.0-rc.3', true], 131 | ]; 132 | 133 | test(globalVersion, vers); 134 | }); 135 | }); 136 | 137 | function test(globalVersion: string, vers: [string, boolean][]) { 138 | describe(`global version is ${globalVersion}`, () => { 139 | for (const [version, compatible] of vers) { 140 | it(`API version ${version} ${ 141 | compatible ? 'should' : 'should not' 142 | } be able to access global`, () => { 143 | const check = _makeCompatibilityCheck(version); 144 | assert.strictEqual(check(globalVersion), compatible); 145 | }); 146 | } 147 | }); 148 | } 149 | -------------------------------------------------------------------------------- /test/internal/version.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { VERSION } from '../../src/version'; 19 | 20 | describe('version', () => { 21 | it('should have generated VERSION.ts', () => { 22 | const pjson = require('../../package.json'); 23 | assert.strictEqual(pjson.version, VERSION); 24 | }); 25 | 26 | it('prerelease tag versions are banned', () => { 27 | // see https://github.com/open-telemetry/opentelemetry-js-api/issues/74 28 | assert.ok(VERSION.match(/^\d+\.\d+\.\d+$/)); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/noop-implementations/noop-span.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { 19 | SpanStatusCode, 20 | INVALID_SPANID, 21 | INVALID_TRACEID, 22 | TraceFlags, 23 | } from '../../src'; 24 | import { NonRecordingSpan } from '../../src/trace/NonRecordingSpan'; 25 | 26 | describe('NonRecordingSpan', () => { 27 | it('do not crash', () => { 28 | const span = new NonRecordingSpan(); 29 | span.setAttribute('my_string_attribute', 'foo'); 30 | span.setAttribute('my_number_attribute', 123); 31 | span.setAttribute('my_boolean_attribute', false); 32 | span.setAttribute('my_obj_attribute', { a: true }); 33 | span.setAttribute('my_sym_attribute', Symbol('a')); 34 | span.setAttributes({ 35 | my_string_attribute: 'foo', 36 | my_number_attribute: 123, 37 | }); 38 | 39 | span.addEvent('sent'); 40 | span.addEvent('sent', { id: '42', key: 'value' }); 41 | 42 | span.setStatus({ code: SpanStatusCode.ERROR }); 43 | 44 | span.updateName('my-span'); 45 | 46 | assert.ok(!span.isRecording()); 47 | assert.deepStrictEqual(span.spanContext(), { 48 | traceId: INVALID_TRACEID, 49 | spanId: INVALID_SPANID, 50 | traceFlags: TraceFlags.NONE, 51 | }); 52 | span.end(); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /test/noop-implementations/noop-tracer-provider.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { NoopTracer } from '../../src/trace/NoopTracer'; 19 | import { NoopTracerProvider } from '../../src/trace/NoopTracerProvider'; 20 | 21 | describe('NoopTracerProvider', () => { 22 | it('should not crash', () => { 23 | const tracerProvider = new NoopTracerProvider(); 24 | 25 | assert.ok(tracerProvider.getTracer('tracer-name') instanceof NoopTracer); 26 | assert.ok(tracerProvider.getTracer('tracer-name', 'v1') instanceof NoopTracer); 27 | assert.ok(tracerProvider.getTracer('tracer-name', 'v1', { 28 | schemaUrl: 'https://opentelemetry.io/schemas/1.7.0' 29 | }) instanceof NoopTracer); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/noop-implementations/noop-tracer.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { 19 | context, 20 | Span, 21 | SpanContext, 22 | SpanKind, 23 | trace, 24 | TraceFlags, 25 | } from '../../src'; 26 | import { NonRecordingSpan } from '../../src/trace/NonRecordingSpan'; 27 | import { NoopTracer } from '../../src/trace/NoopTracer'; 28 | 29 | describe('NoopTracer', () => { 30 | it('should not crash', () => { 31 | const tracer = new NoopTracer(); 32 | 33 | assert.ok(tracer.startSpan('span-name') instanceof NonRecordingSpan); 34 | assert.ok( 35 | tracer.startSpan('span-name1', { kind: SpanKind.CLIENT }) instanceof 36 | NonRecordingSpan 37 | ); 38 | assert.ok( 39 | tracer.startSpan('span-name2', { kind: SpanKind.CLIENT }) instanceof 40 | NonRecordingSpan 41 | ); 42 | }); 43 | 44 | it('should propagate valid spanContext on the span (from context)', () => { 45 | const tracer = new NoopTracer(); 46 | const parent: SpanContext = { 47 | traceId: 'd4cda95b652f4a1592b449dd92ffda3b', 48 | spanId: '6e0c63ffe4e34c42', 49 | traceFlags: TraceFlags.NONE, 50 | }; 51 | const span = tracer.startSpan( 52 | 'test-1', 53 | {}, 54 | trace.setSpanContext(context.active(), parent) 55 | ); 56 | assert(span.spanContext().traceId === parent.traceId); 57 | assert(span.spanContext().spanId === parent.spanId); 58 | assert(span.spanContext().traceFlags === parent.traceFlags); 59 | }); 60 | 61 | it('should accept 2 to 4 args and start an active span', () => { 62 | const tracer = new NoopTracer(); 63 | const name = 'span-name'; 64 | const fn = (span: Span) => { 65 | try { 66 | return 1; 67 | } finally { 68 | span.end(); 69 | } 70 | }; 71 | const opts = { attributes: { foo: 'bar' } }; 72 | 73 | assert.strictEqual((tracer as any).startActiveSpan(name), undefined); 74 | 75 | assert.strictEqual(tracer.startActiveSpan(name, fn), 1); 76 | 77 | assert.strictEqual(tracer.startActiveSpan(name, opts, fn), 1); 78 | 79 | assert.strictEqual( 80 | tracer.startActiveSpan(name, opts, context.active(), fn), 81 | 1 82 | ); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /test/proxy-implementations/proxy-tracer.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import * as sinon from 'sinon'; 19 | import { 20 | context, 21 | ProxyTracer, 22 | ProxyTracerProvider, 23 | ROOT_CONTEXT, 24 | Span, 25 | SpanKind, 26 | SpanOptions, 27 | Tracer, 28 | TracerProvider, 29 | } from '../../src'; 30 | import { NonRecordingSpan } from '../../src/trace/NonRecordingSpan'; 31 | import { NoopTracer } from '../../src/trace/NoopTracer'; 32 | 33 | describe('ProxyTracer', () => { 34 | let provider: ProxyTracerProvider; 35 | const sandbox = sinon.createSandbox(); 36 | 37 | beforeEach(() => { 38 | provider = new ProxyTracerProvider(); 39 | }); 40 | 41 | afterEach(() => { 42 | sandbox.restore(); 43 | }); 44 | 45 | describe('when no delegate is set', () => { 46 | it('should return proxy tracers', () => { 47 | const tracer = provider.getTracer('test'); 48 | 49 | assert.ok(tracer instanceof ProxyTracer); 50 | }); 51 | 52 | it('startSpan should return Noop Spans', () => { 53 | const tracer = provider.getTracer('test'); 54 | 55 | assert.ok(tracer.startSpan('span-name') instanceof NonRecordingSpan); 56 | assert.ok( 57 | tracer.startSpan('span-name1', { kind: SpanKind.CLIENT }) instanceof 58 | NonRecordingSpan 59 | ); 60 | assert.ok( 61 | tracer.startSpan('span-name2', { kind: SpanKind.CLIENT }) instanceof 62 | NonRecordingSpan 63 | ); 64 | }); 65 | }); 66 | 67 | describe('when delegate is set before getTracer', () => { 68 | let delegate: TracerProvider; 69 | let getTracerStub: sinon.SinonStub; 70 | 71 | beforeEach(() => { 72 | getTracerStub = sandbox.stub().returns(new NoopTracer()); 73 | delegate = { 74 | getTracer: getTracerStub, 75 | }; 76 | provider.setDelegate(delegate); 77 | }); 78 | 79 | it('should return tracers directly from the delegate', () => { 80 | const tracer = provider.getTracer('test', 'v0'); 81 | 82 | sandbox.assert.calledOnce(getTracerStub); 83 | assert.strictEqual(getTracerStub.firstCall.returnValue, tracer); 84 | assert.deepStrictEqual(getTracerStub.firstCall.args, [ 85 | 'test', 86 | 'v0', 87 | undefined, 88 | ]); 89 | }); 90 | 91 | it('should return tracers directly from the delegate with schema url', () => { 92 | const tracer = provider.getTracer('test', 'v0', { 93 | schemaUrl: 'https://opentelemetry.io/schemas/1.7.0', 94 | }); 95 | 96 | sandbox.assert.calledOnce(getTracerStub); 97 | assert.strictEqual(getTracerStub.firstCall.returnValue, tracer); 98 | assert.deepStrictEqual(getTracerStub.firstCall.args, [ 99 | 'test', 100 | 'v0', 101 | { schemaUrl: 'https://opentelemetry.io/schemas/1.7.0' }, 102 | ]); 103 | }); 104 | }); 105 | 106 | describe('when delegate is set after getTracer', () => { 107 | let tracer: Tracer; 108 | let delegate: TracerProvider; 109 | let delegateSpan: Span; 110 | let delegateTracer: Tracer; 111 | 112 | beforeEach(() => { 113 | delegateSpan = new NonRecordingSpan(); 114 | delegateTracer = { 115 | startSpan() { 116 | return delegateSpan; 117 | }, 118 | 119 | startActiveSpan() { 120 | // stubbed 121 | }, 122 | }; 123 | 124 | tracer = provider.getTracer('test'); 125 | 126 | delegate = { 127 | getTracer() { 128 | return delegateTracer; 129 | }, 130 | }; 131 | provider.setDelegate(delegate); 132 | }); 133 | 134 | it('should create spans using the delegate tracer', () => { 135 | const span = tracer.startSpan('test'); 136 | 137 | assert.strictEqual(span, delegateSpan); 138 | }); 139 | 140 | it('should create active spans using the delegate tracer', () => { 141 | // sinon types are broken with overloads, hence the any 142 | // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/36436 143 | const startActiveSpanStub = sinon.stub( 144 | delegateTracer, 145 | 'startActiveSpan' 146 | ); 147 | 148 | const name = 'span-name'; 149 | const fn = (span: Span) => { 150 | try { 151 | return 1; 152 | } finally { 153 | span.end(); 154 | } 155 | }; 156 | const opts = { attributes: { foo: 'bar' } }; 157 | const ctx = context.active(); 158 | 159 | startActiveSpanStub.withArgs(name, fn).returns(1); 160 | startActiveSpanStub.withArgs(name, opts, fn).returns(2); 161 | startActiveSpanStub.withArgs(name, opts, ctx, fn).returns(3); 162 | 163 | assert.strictEqual(tracer.startActiveSpan(name, fn), 1); 164 | assert.strictEqual(tracer.startActiveSpan(name, opts, fn), 2); 165 | assert.strictEqual(tracer.startActiveSpan(name, opts, ctx, fn), 3); 166 | }); 167 | 168 | it('should pass original arguments to DelegateTracer#startSpan', () => { 169 | const startSpanStub = sandbox.stub(delegateTracer, 'startSpan'); 170 | 171 | const name = 'name1'; 172 | const options: SpanOptions = {}; 173 | const ctx = ROOT_CONTEXT.setValue(Symbol('test'), 1); 174 | tracer.startSpan(name, options, ctx); 175 | 176 | // Assert the proxy tracer has the full API of the NoopTracer 177 | assert.strictEqual( 178 | NoopTracer.prototype.startSpan.length, 179 | ProxyTracer.prototype.startSpan.length 180 | ); 181 | assert.deepStrictEqual(Object.getOwnPropertyNames(NoopTracer.prototype), [ 182 | 'constructor', 183 | 'startSpan', 184 | 'startActiveSpan', 185 | ]); 186 | sandbox.assert.calledOnceWithExactly(startSpanStub, name, options, ctx); 187 | }); 188 | }); 189 | }); 190 | -------------------------------------------------------------------------------- /test/trace/spancontext-utils.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import * as context from '../../src/trace/spancontext-utils'; 19 | import { INVALID_SPANID, INVALID_TRACEID, TraceFlags } from '../../src'; 20 | 21 | describe('spancontext-utils', () => { 22 | it('should return true for valid spancontext', () => { 23 | const spanContext = { 24 | traceId: 'd4cda95b652f4a1592b449d5929fda1b', 25 | spanId: '6e0c63257de34c92', 26 | traceFlags: TraceFlags.NONE, 27 | }; 28 | assert.ok(context.isSpanContextValid(spanContext)); 29 | }); 30 | 31 | it('should return false when traceId is invalid', () => { 32 | const spanContext = { 33 | traceId: INVALID_TRACEID, 34 | spanId: '6e0c63257de34c92', 35 | traceFlags: TraceFlags.NONE, 36 | }; 37 | assert.ok(!context.isSpanContextValid(spanContext)); 38 | }); 39 | 40 | it('should return false when spanId is invalid', () => { 41 | const spanContext = { 42 | traceId: 'd4cda95b652f4a1592b449d5929fda1b', 43 | spanId: INVALID_SPANID, 44 | traceFlags: TraceFlags.NONE, 45 | }; 46 | assert.ok(!context.isSpanContextValid(spanContext)); 47 | }); 48 | 49 | it('should return false when traceId & spanId is invalid', () => { 50 | const spanContext = { 51 | traceId: INVALID_TRACEID, 52 | spanId: INVALID_SPANID, 53 | traceFlags: TraceFlags.NONE, 54 | }; 55 | assert.ok(!context.isSpanContextValid(spanContext)); 56 | }); 57 | 58 | it('should wrap a SpanContext in a non-recording span', () => { 59 | const spanContext = { 60 | traceId: 'd4cda95b652f4a1592b449d5929fda1b', 61 | spanId: '6e0c63257de34c92', 62 | traceFlags: TraceFlags.NONE, 63 | }; 64 | 65 | const span = context.wrapSpanContext(spanContext); 66 | 67 | assert.deepStrictEqual(span.spanContext(), spanContext); 68 | assert.strictEqual(span.isRecording(), false); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /test/trace/tracestate-validators.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { validateKey, validateValue } from '../../src/trace/internal/tracestate-validators'; 19 | 20 | describe('validators', () => { 21 | describe('validateKey', () => { 22 | const validKeysTestCases = [ 23 | 'abcdefghijklmnopqrstuvwxyz0123456789-_*/', 24 | 'baz-', 25 | 'baz_', 26 | 'baz*', 27 | 'baz*bar', 28 | 'baz/', 29 | 'tracestate', 30 | 'fw529a3039@dt', 31 | '6cab5bb-29a@dt', 32 | ]; 33 | validKeysTestCases.forEach(testCase => 34 | it(`returns true when key contains valid chars ${testCase}`, () => { 35 | assert.ok(validateKey(testCase), `${testCase} should be valid`); 36 | }) 37 | ); 38 | 39 | const invalidKeysTestCases = [ 40 | '1_key', 41 | 'kEy_1', 42 | 'k'.repeat(257), 43 | 'key,', 44 | 'TrAcEsTaTE', 45 | 'TRACESTATE', 46 | '', 47 | '6num', 48 | ]; 49 | invalidKeysTestCases.forEach(testCase => 50 | it(`returns true when key contains invalid chars ${testCase}`, () => { 51 | assert.ok(!validateKey(testCase), `${testCase} should be invalid`); 52 | }) 53 | ); 54 | }); 55 | 56 | describe('validateValue', () => { 57 | const validValuesTestCases = [ 58 | 'first second', 59 | 'baz*', 60 | 'baz$', 61 | 'baz@', 62 | 'first-second', 63 | 'baz~bar', 64 | 'test-v1:120', 65 | '-second', 66 | 'first.second', 67 | 'TrAcEsTaTE', 68 | 'TRACESTATE', 69 | ]; 70 | validValuesTestCases.forEach(testCase => 71 | it(`returns true when value contains valid chars ${testCase}`, () => { 72 | assert.ok(validateValue(testCase)); 73 | }) 74 | ); 75 | 76 | const invalidValuesTestCases = [ 77 | 'my_value=5', 78 | 'first,second', 79 | 'first ', 80 | 'k'.repeat(257), 81 | ',baz', 82 | 'baz,', 83 | 'baz=', 84 | '', 85 | ]; 86 | invalidValuesTestCases.forEach(testCase => 87 | it(`returns true when value contains invalid chars ${testCase}`, () => { 88 | assert.ok(!validateValue(testCase)); 89 | }) 90 | ); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /test/trace/tracestate.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { createTraceState } from '../../src/trace/internal/utils'; 19 | import { TraceStateImpl } from '../../src/trace/internal/tracestate-impl'; 20 | 21 | describe('TraceState', () => { 22 | describe('.serialize()', () => { 23 | it('returns serialize string', () => { 24 | const state = createTraceState('a=1,b=2'); 25 | assert.deepStrictEqual(state.serialize(), 'a=1,b=2'); 26 | }); 27 | 28 | it('must create a createTraceState and move updated keys to the front', () => { 29 | const orgState = createTraceState('a=1,b=2'); 30 | const state = orgState.set('b', '3'); 31 | assert.deepStrictEqual(orgState.serialize(), 'a=1,b=2'); 32 | assert.deepStrictEqual(state.serialize(), 'b=3,a=1'); 33 | }); 34 | 35 | it('must create a createTraceState and add new keys to the front', () => { 36 | let state = createTraceState().set('vendorname1', 'opaqueValue1'); 37 | assert.deepStrictEqual(state.serialize(), 'vendorname1=opaqueValue1'); 38 | 39 | state = state.set('vendorname2', 'opaqueValue2'); 40 | assert.deepStrictEqual( 41 | state.serialize(), 42 | 'vendorname2=opaqueValue2,vendorname1=opaqueValue1' 43 | ); 44 | }); 45 | 46 | it('must create a createTraceState and unset the entries', () => { 47 | const orgState = createTraceState('c=4,b=3,a=1'); 48 | let state = orgState.unset('b'); 49 | assert.deepStrictEqual(state.serialize(), 'c=4,a=1'); 50 | state = state.unset('c').unset('A'); 51 | assert.deepStrictEqual(state.serialize(), 'a=1'); 52 | assert.strictEqual(orgState.serialize(), 'c=4,b=3,a=1'); 53 | }); 54 | }); 55 | 56 | describe('.parse()', () => { 57 | it('must successfully parse valid state value', () => { 58 | const state = createTraceState( 59 | 'vendorname2=opaqueValue2,vendorname1=opaqueValue1' 60 | ); 61 | assert.deepStrictEqual(state.get('vendorname1'), 'opaqueValue1'); 62 | assert.deepStrictEqual(state.get('vendorname2'), 'opaqueValue2'); 63 | assert.deepStrictEqual( 64 | state.serialize(), 65 | 'vendorname2=opaqueValue2,vendorname1=opaqueValue1' 66 | ); 67 | }); 68 | 69 | it('must drop states when the items are too long', () => { 70 | const state = createTraceState('a=' + 'b'.repeat(512)); 71 | assert.deepStrictEqual(state.get('a'), undefined); 72 | assert.deepStrictEqual(state.serialize(), ''); 73 | }); 74 | 75 | it('must drop states which cannot be parsed', () => { 76 | const state = createTraceState('a=1,b,c=3'); 77 | assert.deepStrictEqual(state.get('a'), '1'); 78 | assert.deepStrictEqual(state.get('b'), undefined); 79 | assert.deepStrictEqual(state.get('c'), '3'); 80 | assert.deepStrictEqual(state.serialize(), 'a=1,c=3'); 81 | }); 82 | 83 | it('must skip states that only have a single value with an equal sign', () => { 84 | const state = createTraceState('a=1='); 85 | assert.deepStrictEqual(state.get('a'), undefined); 86 | }); 87 | 88 | it('must successfully parse valid state keys', () => { 89 | const state = createTraceState('a-b=1,c/d=2,p*q=3,x_y=4'); 90 | assert.deepStrictEqual(state.get('a-b'), '1'); 91 | assert.deepStrictEqual(state.get('c/d'), '2'); 92 | assert.deepStrictEqual(state.get('p*q'), '3'); 93 | assert.deepStrictEqual(state.get('x_y'), '4'); 94 | }); 95 | 96 | it('must successfully parse valid state value with spaces in between', () => { 97 | const state = createTraceState('a=1,foo=bar baz'); 98 | assert.deepStrictEqual(state.get('foo'), 'bar baz'); 99 | assert.deepStrictEqual(state.serialize(), 'a=1,foo=bar baz'); 100 | }); 101 | 102 | it('must truncate states with too many items', () => { 103 | const state = createTraceState( 104 | new Array(33) 105 | .fill(0) 106 | .map((_: null, num: number) => `a${num}=${num}`) 107 | .join(',') 108 | ) as TraceStateImpl; 109 | assert.deepStrictEqual(state['_keys']().length, 32); 110 | assert.deepStrictEqual(state.get('a0'), '0'); 111 | assert.deepStrictEqual(state.get('a31'), '31'); 112 | assert.deepStrictEqual( 113 | state.get('a32'), 114 | undefined, 115 | 'should truncate from the tail' 116 | ); 117 | }); 118 | 119 | it('should not count invalid items towards max limit', () => { 120 | const tracestate = new Array(32) 121 | .fill(0) 122 | .map((_: null, num: number) => `a${num}=${num}`) 123 | .concat('invalid.suffix.key=1'); // add invalid key to beginning 124 | tracestate.unshift('invalid.prefix.key=1'); 125 | tracestate.splice(15, 0, 'invalid.middle.key.a=1'); 126 | tracestate.splice(15, 0, 'invalid.middle.key.b=2'); 127 | tracestate.splice(15, 0, 'invalid.middle.key.c=3'); 128 | 129 | const state = createTraceState(tracestate.join(',')) as TraceStateImpl; 130 | 131 | assert.deepStrictEqual(state['_keys']().length, 32); 132 | assert.deepStrictEqual(state.get('a0'), '0'); 133 | assert.deepStrictEqual(state.get('a31'), '31'); 134 | assert.deepStrictEqual(state.get('invalid.middle.key.a'), undefined); 135 | assert.deepStrictEqual(state.get('invalid.middle.key.b'), undefined); 136 | assert.deepStrictEqual(state.get('invalid.middle.key.c'), undefined); 137 | }); 138 | }); 139 | }); 140 | -------------------------------------------------------------------------------- /tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "ES6", 5 | "moduleResolution": "node", 6 | "outDir": "build/esm", 7 | "rootDir": "src", 8 | "tsBuildInfoFile": "build/esm/tsconfig.esm.tsbuildinfo" 9 | }, 10 | "include": [ 11 | "src/**/*.ts" 12 | ], 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowUnreachableCode": false, 4 | "allowUnusedLabels": false, 5 | "declaration": true, 6 | "declarationMap": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "module": "commonjs", 9 | "noEmitOnError": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noImplicitOverride": true, 14 | "outDir": "build", 15 | "pretty": true, 16 | "rootDir": ".", 17 | "sourceMap": true, 18 | "strict": true, 19 | "strictNullChecks": true, 20 | "target": "es5", 21 | "incremental": true, 22 | "newLine": "LF", 23 | "inlineSources": true 24 | }, 25 | "include": [ 26 | "src/**/*.ts", 27 | "test/**/*.ts" 28 | ], 29 | "exclude": [ 30 | "node_modules" 31 | ], 32 | "typedocOptions": { 33 | "name": "OpenTelemetry API for JavaScript", 34 | "out": "docs/out", 35 | "entryPoints": ["./src/index.ts"], 36 | "excludePrivate": true, 37 | "hideGenerator": true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /webpack.node-polyfills.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Enable the assert library polyfill because that is used in tests 3 | assert: true, 4 | // The assert polyfill from github.com/browserify/commonjs-assert 5 | // also requires the `global` polyfill. 6 | global: true, 7 | 8 | // Turn off all other Node.js API polyfills for the browser tests to 9 | // make sure that we are not attempting to use Node-specific APIs in 10 | // the browser code. Instead, we will write browser specific 11 | // implementations of platform functionality we need under the 12 | // `./src/platform/browser` folder. This allows for writing browser 13 | // optimized implementations of the specific needed functionality 14 | // rather than bringing in (sometimes large) polyfills for the 15 | // corresponding Node APIs. 16 | Buffer: false, 17 | __dirname: false, 18 | __filename: false, 19 | buffer: false, 20 | child_process: false, 21 | cluster: false, 22 | console: false, 23 | constants: false, 24 | crypto: false, 25 | dgram: false, 26 | dns: false, 27 | domain: false, 28 | events: false, 29 | fs: false, 30 | http: false, 31 | https: false, 32 | module: false, 33 | net: false, 34 | os: false, 35 | path: false, 36 | process: false, 37 | punycode: false, 38 | querystring: false, 39 | readline: false, 40 | repl: false, 41 | setImmediate: false, 42 | stream: false, 43 | string_decoder: false, 44 | sys: false, 45 | timers: false, 46 | tls: false, 47 | tty: false, 48 | url: false, 49 | util: false, 50 | vm: false, 51 | zlib: false 52 | }; 53 | --------------------------------------------------------------------------------