├── .editorconfig ├── .eslintrc.json ├── .github └── workflows │ ├── npm-ci.yml │ └── npm-publish.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── TODO.md ├── angular.json ├── collector ├── docker-compose.yaml └── otel-collector-config.yaml ├── cypress.config.ts ├── cypress ├── e2e │ ├── post-backend.cy.ts │ └── view-backend.cy.ts ├── fixtures │ └── example.json ├── plugins │ └── index.js ├── support │ ├── commands.js │ └── e2e.js └── tsconfig.json ├── docs ├── changelog.html ├── components │ └── OtelWebTracerComponent.html ├── coverage.html ├── dependencies.html ├── fonts │ ├── ionicons.eot │ ├── ionicons.svg │ ├── ionicons.ttf │ ├── ionicons.woff │ ├── ionicons.woff2 │ ├── roboto-v15-latin-300.eot │ ├── roboto-v15-latin-300.svg │ ├── roboto-v15-latin-300.ttf │ ├── roboto-v15-latin-300.woff │ ├── roboto-v15-latin-300.woff2 │ ├── roboto-v15-latin-700.eot │ ├── roboto-v15-latin-700.svg │ ├── roboto-v15-latin-700.ttf │ ├── roboto-v15-latin-700.woff │ ├── roboto-v15-latin-700.woff2 │ ├── roboto-v15-latin-italic.eot │ ├── roboto-v15-latin-italic.svg │ ├── roboto-v15-latin-italic.ttf │ ├── roboto-v15-latin-italic.woff │ ├── roboto-v15-latin-italic.woff2 │ ├── roboto-v15-latin-regular.eot │ ├── roboto-v15-latin-regular.svg │ ├── roboto-v15-latin-regular.ttf │ ├── roboto-v15-latin-regular.woff │ └── roboto-v15-latin-regular.woff2 ├── graph │ └── dependencies.svg ├── images │ ├── compodoc-vectorise-inverted.png │ ├── compodoc-vectorise-inverted.svg │ ├── compodoc-vectorise.png │ ├── compodoc-vectorise.svg │ ├── coverage-badge-documentation.svg │ └── favicon.ico ├── index.html ├── injectables │ ├── AwsXrayPropagatorService.html │ ├── B3PropagatorService.html │ ├── CompositePropagatorService.html │ ├── ConsoleSpanExporterService.html │ ├── HttpTraceContextPropagatorService.html │ ├── InstrumentationService.html │ ├── JaegerHttpTracePropagatorService.html │ ├── NoopSpanExporterService.html │ ├── NoopTextMapPropagatorService.html │ ├── OtelcolExporterService.html │ ├── W3CTraceContextPropagatorService.html │ └── ZipkinExporterService.html ├── interceptors │ └── OpenTelemetryHttpInterceptor.html ├── interfaces │ ├── B3PropagatorConfig.html │ ├── BatchSpanProcessorConfig.html │ ├── CommonCollectorConfig.html │ ├── CustomSpan.html │ ├── IExporter.html │ ├── IPropagator.html │ ├── IgnoreUrlsConfig.html │ ├── InstrumentationConfig.html │ ├── JaegerPropagatorConfig.html │ ├── OpenTelemetryConfig.html │ ├── OtelCollectorConfig.html │ └── ZipkinCollectorConfig.html ├── js │ ├── compodoc.js │ ├── lazy-load-graphs.js │ ├── libs │ │ ├── EventDispatcher.js │ │ ├── bootstrap-native.js │ │ ├── clipboard.min.js │ │ ├── custom-elements-es5-adapter.js │ │ ├── custom-elements.min.js │ │ ├── d3.v3.min.js │ │ ├── deep-iterator.js │ │ ├── es6-shim.min.js │ │ ├── htmlparser.js │ │ ├── innersvg.js │ │ ├── lit-html.js │ │ ├── prism.js │ │ ├── promise.min.js │ │ ├── svg-pan-zoom.min.js │ │ ├── tablesort.min.js │ │ ├── tablesort.number.min.js │ │ ├── vis.min.js │ │ └── zepto.min.js │ ├── menu-wc.js │ ├── menu-wc_es5.js │ ├── menu.js │ ├── routes.js │ ├── search │ │ ├── lunr.min.js │ │ ├── search-lunr.js │ │ ├── search.js │ │ └── search_index.js │ ├── sourceCode.js │ ├── svg-pan-zoom.controls.js │ ├── tabs.js │ └── tree.js ├── license.html ├── miscellaneous │ └── variables.html ├── modules.html ├── modules │ ├── AwsXrayPropagatorModule.html │ ├── B3PropagatorModule.html │ ├── CompositePropagatorModule.html │ ├── ConsoleSpanExporterModule.html │ ├── HttpTraceContextPropagatorModule.html │ ├── JaegerHttpTracePropagatorModule.html │ ├── NoopSpanExporterModule.html │ ├── NoopTextMapPropagatorModule.html │ ├── OpenTelemetryInterceptorModule.html │ ├── OtelColExporterModule.html │ ├── OtelWebTracerModule.html │ ├── OtelWebTracerModule │ │ └── dependencies.svg │ ├── W3CTraceContextPropagatorModule.html │ └── ZipkinExporterModule.html ├── overview.html ├── properties.html ├── styles │ ├── bootstrap-card.css │ ├── bootstrap.min.css │ ├── compodoc.css │ ├── dark.css │ ├── ionicons.min.css │ ├── laravel.css │ ├── material.css │ ├── original.css │ ├── postmark.css │ ├── prism.css │ ├── readthedocs.css │ ├── reset.css │ ├── stripe.css │ ├── style.css │ ├── tablesort.css │ └── vagrant.css └── todo.html ├── jest.config.js ├── package-lock.json ├── package.json ├── projects ├── instrumentation-example │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── proxy.conf.json │ ├── src │ │ ├── app │ │ │ ├── app-routing.module.ts │ │ │ ├── app.component.css │ │ │ ├── app.component.html │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── example.service.ts │ │ │ ├── jsonp-backend │ │ │ │ ├── jsonp-backend.component.css │ │ │ │ ├── jsonp-backend.component.html │ │ │ │ └── jsonp-backend.component.ts │ │ │ ├── post-backend │ │ │ │ ├── post-backend.component.css │ │ │ │ ├── post-backend.component.html │ │ │ │ └── post-backend.component.ts │ │ │ ├── result.ts │ │ │ └── view-backend │ │ │ │ ├── view-backend.component.css │ │ │ │ ├── view-backend.component.html │ │ │ │ └── view-backend.component.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── backend-api.js │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.css │ │ └── test.ts │ ├── tsconfig.app.json │ └── tsconfig.spec.json ├── interceptor-example │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── proxy.conf.json │ ├── src │ │ ├── app │ │ │ ├── app-routing.module.ts │ │ │ ├── app.component.css │ │ │ ├── app.component.html │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── custom-span-impl.ts │ │ │ ├── example.service.ts │ │ │ ├── jsonp-backend │ │ │ │ ├── jsonp-backend.component.css │ │ │ │ ├── jsonp-backend.component.html │ │ │ │ └── jsonp-backend.component.ts │ │ │ ├── post-backend │ │ │ │ ├── post-backend.component.css │ │ │ │ ├── post-backend.component.html │ │ │ │ └── post-backend.component.ts │ │ │ ├── result.ts │ │ │ └── view-backend │ │ │ │ ├── view-backend.component.css │ │ │ │ ├── view-backend.component.html │ │ │ │ └── view-backend.component.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── backend-api.js │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.css │ │ └── test.ts │ ├── tsconfig.app.json │ └── tsconfig.spec.json └── opentelemetry-interceptor │ ├── .eslintrc.json │ ├── LICENSE │ ├── __mocks__ │ └── data │ │ └── config.mock.ts │ ├── ng-package.json │ ├── ngcc.config.js │ ├── package-lock.json │ ├── package.json │ ├── setupJest.ts │ ├── src │ ├── lib │ │ ├── configuration │ │ │ └── opentelemetry-config.ts │ │ ├── interceptor │ │ │ ├── custom-span.interface.ts │ │ │ ├── opentelemetry-http.interceptor.spec.ts │ │ │ └── opentelemetry-http.interceptor.ts │ │ ├── opentelemetry-interceptor.module.spec.ts │ │ ├── opentelemetry-interceptor.module.ts │ │ ├── otel-webtracer.module.spec.ts │ │ ├── otel-webtracer.module.ts │ │ └── services │ │ │ ├── exporter │ │ │ ├── console │ │ │ │ ├── console-span-exporter.module.ts │ │ │ │ ├── console-span-exporter.service.spec.ts │ │ │ │ └── console-span-exporter.service.ts │ │ │ ├── exporter.interface.ts │ │ │ ├── noop-exporter │ │ │ │ ├── noop-span-exporter.module.ts │ │ │ │ ├── noop-span-exporter.service.spec.ts │ │ │ │ └── noop-span-exporter.service.ts │ │ │ ├── otelcol │ │ │ │ ├── otelcol-exporter.module.ts │ │ │ │ ├── otelcol-exporter.service.spec.ts │ │ │ │ └── otelcol-exporter.service.ts │ │ │ └── zipkin │ │ │ │ ├── zipkin-exporter.module.ts │ │ │ │ ├── zipkin-exporter.service.spec.ts │ │ │ │ └── zipkin-exporter.service.ts │ │ │ ├── instrumentation │ │ │ ├── instrumentation.service.spec.ts │ │ │ └── instrumentation.service.ts │ │ │ └── propagator │ │ │ ├── aws-xray-propagator │ │ │ ├── aws-xray-propagator.module.ts │ │ │ ├── aws-xray-propagator.service.spec.ts │ │ │ └── aws-xray-propagator.service.ts │ │ │ ├── b3-propagator │ │ │ ├── b3-propagator.module.ts │ │ │ ├── b3-propagator.service.spec.ts │ │ │ └── b3-propagator.service.ts │ │ │ ├── composite-propagator │ │ │ ├── composite-propagator.module.ts │ │ │ ├── composite-propagator.service.spec.ts │ │ │ └── composite-propagator.service.ts │ │ │ ├── jaeger-http-trace-propagator │ │ │ ├── jaeger-http-trace-propagator.module.ts │ │ │ ├── jaeger-http-trace-propagator.service.spec.ts │ │ │ └── jaeger-http-trace-propagator.service.ts │ │ │ ├── noop-http-text-propagator │ │ │ ├── noop-text-map-propagator.module.ts │ │ │ ├── noop-text-map-propagator.service.spec.ts │ │ │ └── noop-text-map-propagator.service.ts │ │ │ ├── propagator.interface.ts │ │ │ └── w3c-trace-context-propagator │ │ │ ├── w3c-trace-context-propagator.module.ts │ │ │ ├── w3c-trace-context-propagator.service.spec.ts │ │ │ └── w3c-trace-context-propagator.service.ts │ ├── public-api.ts │ └── version.json │ ├── tsconfig.lib.json │ ├── tsconfig.lib.prod.json │ └── tsconfig.spec.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": [ 4 | "projects/**/*" 5 | ], 6 | "overrides": [ 7 | { 8 | "files": [ 9 | "*.ts" 10 | ], 11 | "parserOptions": { 12 | "project": [ 13 | "tsconfig.json" 14 | ], 15 | "createDefaultProgram": true 16 | }, 17 | "extends": [ 18 | "plugin:@angular-eslint/ng-cli-compat", 19 | "plugin:@angular-eslint/ng-cli-compat--formatting-add-on", 20 | "plugin:@angular-eslint/template/process-inline-templates" 21 | ], 22 | "rules": {} 23 | }, 24 | { 25 | "files": [ 26 | "*.html" 27 | ], 28 | "extends": [ 29 | "plugin:@angular-eslint/template/recommended" 30 | ], 31 | "rules": {} 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.github/workflows/npm-ci.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages 3 | 4 | name: ci push 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | pull_request: 11 | branches: 12 | - main 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: actions/setup-node@v4 20 | with: 21 | node-version: 18 22 | cache: npm 23 | - run: npm ci 24 | - run: npm test 25 | - uses: dorny/test-reporter@v2 26 | with: 27 | reporter: 'jest-junit' 28 | name: 'Jest tests results' 29 | path: 'jest-report/jest-junit.xml' 30 | - uses: actions/upload-artifact@v4 31 | with: 32 | name: jest-report 33 | path: jest-report 34 | if-no-files-found: ignore 35 | - uses: codecov/codecov-action@v5 36 | with: 37 | token: ${{ secrets.CODECOV_TOKEN }} 38 | cypress-interceptor: 39 | runs-on: ubuntu-latest 40 | steps: 41 | - uses: actions/checkout@v4 42 | - uses: actions/setup-node@v4 43 | with: 44 | node-version: 18 45 | cache: npm 46 | - run: npm ci 47 | - name: Cypress interceptor run 48 | uses: cypress-io/github-action@v5 49 | with: 50 | start: npm run start:complete-interceptor-example 51 | wait-on: 'http://localhost:4200' 52 | wait-on-timeout: 180 53 | install: false 54 | - uses: actions/upload-artifact@v4 55 | if: failure() 56 | with: 57 | name: cypress-screenshots 58 | path: cypress/screenshots 59 | if-no-files-found: warn 60 | cypress-instrumentation: 61 | runs-on: ubuntu-latest 62 | steps: 63 | - uses: actions/checkout@v4 64 | - uses: actions/setup-node@v4 65 | with: 66 | node-version: 18 67 | cache: npm 68 | - run: npm ci 69 | - name: Cypress instrumentation run 70 | uses: cypress-io/github-action@v5 71 | with: 72 | start: npm run start:complete-instrumentation-example 73 | wait-on: 'http://localhost:4200' 74 | wait-on-timeout: 180 75 | install: false 76 | - uses: actions/upload-artifact@v4 77 | if: failure() 78 | with: 79 | name: cypress-screenshots 80 | path: cypress/screenshots 81 | if-no-files-found: warn 82 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: publish package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | publish-npm: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | with: 14 | node-version: 18 15 | cache: npm 16 | registry-url: https://registry.npmjs.org/ 17 | - run: npm ci 18 | - run: npm test 19 | - run: npm run build:prod 20 | - run: cd dist/opentelemetry-interceptor && npm publish --access public 21 | env: 22 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | /documentation 4 | 5 | # compiled output 6 | /dist 7 | /tmp 8 | /out-tsc 9 | # Only exists if Bazel was run 10 | /bazel-out 11 | 12 | # dependencies 13 | /node_modules 14 | 15 | # profiling files 16 | chrome-profiler-events*.json 17 | speed-measure-plugin*.json 18 | 19 | # IDEs and editors 20 | /.idea 21 | .project 22 | .classpath 23 | .c9/ 24 | *.launch 25 | .settings/ 26 | *.sublime-workspace 27 | 28 | # IDE - VSCode 29 | /.vscode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | .history/* 36 | 37 | # misc 38 | /.angular/cache 39 | /.sass-cache 40 | /connect.lock 41 | /coverage 42 | /jest-report 43 | /libpeerconnection.log 44 | npm-debug.log 45 | yarn-error.log 46 | testem.log 47 | /typings 48 | 49 | # System Files 50 | .DS_Store 51 | Thumbs.db 52 | 53 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | Julien Fabre. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Task for opentelemetry-angular-interceptor 2 | 3 | Todo in project... 4 | 5 | ### Todo 6 | 7 | - [ ] Add more configuration for OpenTelemetry-collector : See [here](https://github.com/open-telemetry/opentelemetry-js/blob/master/packages/opentelemetry-exporter-collector/src/types.ts) 8 | - [ ] Jaeger 9 | - [ ] Add Jaeger exporter (when it's available) 10 | - [ ] Add more configuration for Jaeger : [here](https://github.com/open-telemetry/opentelemetry-js/blob/master/packages/opentelemetry-exporter-jaeger/src/types.ts) 11 | - [ ] Prepare baggage [here](https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-core/src/correlation-context) 12 | 13 | ### In Progress 14 | 15 | 16 | ### Done ✓ 17 | 18 | 19 | -------------------------------------------------------------------------------- /collector/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | jaeger: 3 | image: jaegertracing/all-in-one:latest 4 | networks: 5 | - otelcol 6 | ports: 7 | - "16686:16686" 8 | - "4317" 9 | zipkin: 10 | image: openzipkin/zipkin-slim:latest 11 | networks: 12 | - otelcol 13 | ports: 14 | - "9411:9411" 15 | otel-collector: 16 | image: otel/opentelemetry-collector-contrib:0.115.1 17 | networks: 18 | - otelcol 19 | command: ["--config=/etc/otel-collector-config.yaml"] 20 | volumes: 21 | - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml 22 | ports: 23 | - "4318:4318" 24 | - "55679:55679" 25 | depends_on: 26 | - jaeger 27 | 28 | networks: 29 | otelcol: 30 | -------------------------------------------------------------------------------- /collector/otel-collector-config.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | http: 5 | endpoint: "0.0.0.0:4318" 6 | cors: 7 | allowed_origins: 8 | - http://* 9 | - https://* 10 | exporters: 11 | zipkin: 12 | endpoint: "http://zipkin:9411/api/v2/spans" 13 | debug: 14 | verbosity: detailed 15 | otlp/jaeger: 16 | endpoint: jaeger:4317 17 | tls: 18 | insecure: true 19 | extensions: 20 | zpages: 21 | endpoint: "0.0.0.0:55679" 22 | service: 23 | telemetry: 24 | logs: 25 | level: "debug" 26 | extensions : [zpages] 27 | pipelines: 28 | traces: 29 | receivers: [otlp] 30 | exporters: [otlp/jaeger,zipkin,debug] 31 | -------------------------------------------------------------------------------- /cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | 3 | export default defineConfig<>({ 4 | video: false, 5 | screenshot: false, 6 | e2e: { 7 | // We've imported your old cypress plugins here. 8 | // You may want to clean this up later by importing these. 9 | setupNodeEvents(on, config) { 10 | return require('./cypress/plugins/index.js')(on, config) 11 | }, 12 | baseUrl: 'http://localhost:4200', 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /cypress/e2e/post-backend.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Post Page', () => { 2 | beforeEach(() => { 3 | cy.visit('http://localhost:4200/post'); 4 | }); 5 | it('don\'t call the backend', () => { 6 | cy.get('i').contains('result call :'); 7 | }); 8 | it('have a trace span in console after post in the form', () => { 9 | cy.get('input[name="avalue"]').as('avalue').type('test'); 10 | cy.get('button[type="submit"]').click(); 11 | cy.wait(1000); 12 | cy.get('i').contains('result call : test').should(() => { 13 | const value = JSON.parse(localStorage.getItem('consoleDir')); 14 | expect(value.traceId).to.be.not.undefined; 15 | expect(value.name).to.eq('POST'); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /cypress/e2e/view-backend.cy.ts: -------------------------------------------------------------------------------- 1 | describe('View Page', () => { 2 | beforeEach(() => { 3 | cy.visit('http://localhost:4200/view'); 4 | }); 5 | it('call the backend', () => { 6 | cy.get('i').contains('result call : ok'); 7 | }); 8 | it('have a trace span in console', () => { 9 | cy.wait(500); 10 | cy.get('i').should(() => { 11 | const value = JSON.parse(localStorage.getItem('consoleDir')); 12 | expect(value.traceId).to.be.not.undefined; 13 | expect(value.name).to.eq('GET'); 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | module.exports = (on, config) => { 19 | // `on` is used to hook into various events Cypress emits 20 | // `config` is the resolved Cypress config 21 | } 22 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /cypress/support/e2e.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | Cypress.on('window:before:load',(win) => { 22 | cy.stub(win.console, 'log', msg => localStorage.setItem('consoleLog', JSON.stringify(msg))).as('globalStubLog'); 23 | cy.stub(win.console, 'dir', msg => localStorage.setItem('consoleDir', JSON.stringify(msg))).as('globalStubDir'); 24 | }); 25 | -------------------------------------------------------------------------------- /cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "types": ["cypress"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/ionicons.eot -------------------------------------------------------------------------------- /docs/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/ionicons.ttf -------------------------------------------------------------------------------- /docs/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/ionicons.woff -------------------------------------------------------------------------------- /docs/fonts/ionicons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/ionicons.woff2 -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-300.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-300.eot -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-300.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-300.ttf -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-300.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-300.woff -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-300.woff2 -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-700.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-700.eot -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-700.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-700.ttf -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-700.woff -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-700.woff2 -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-italic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-italic.eot -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-italic.ttf -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-italic.woff -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-italic.woff2 -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-regular.eot -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-regular.ttf -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-regular.woff -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/fonts/roboto-v15-latin-regular.woff2 -------------------------------------------------------------------------------- /docs/graph/dependencies.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | dependencies 11 | 12 | Legend 13 | 14 |  Declarations 15 | 16 |  Module 17 | 18 |  Bootstrap 19 | 20 |  Providers 21 | 22 |  Exports 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/images/compodoc-vectorise-inverted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/images/compodoc-vectorise-inverted.png -------------------------------------------------------------------------------- /docs/images/compodoc-vectorise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/images/compodoc-vectorise.png -------------------------------------------------------------------------------- /docs/images/coverage-badge-documentation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | documentation 7 | 90% 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/docs/images/favicon.ico -------------------------------------------------------------------------------- /docs/js/compodoc.js: -------------------------------------------------------------------------------- 1 | var compodoc = { 2 | EVENTS: { 3 | READY: 'compodoc.ready', 4 | SEARCH_READY: 'compodoc.search.ready' 5 | } 6 | }; 7 | 8 | Object.assign( compodoc, EventDispatcher.prototype ); 9 | 10 | document.addEventListener('DOMContentLoaded', function() { 11 | compodoc.dispatchEvent({ 12 | type: compodoc.EVENTS.READY 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /docs/js/lazy-load-graphs.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | var lazyGraphs = [].slice.call(document.querySelectorAll('[lazy]')); 3 | var active = false; 4 | 5 | var lazyLoad = function() { 6 | if (active === false) { 7 | active = true; 8 | 9 | setTimeout(function() { 10 | lazyGraphs.forEach(function(lazyGraph) { 11 | if ( 12 | lazyGraph.getBoundingClientRect().top <= window.innerHeight && 13 | lazyGraph.getBoundingClientRect().bottom >= 0 && 14 | getComputedStyle(lazyGraph).display !== 'none' 15 | ) { 16 | lazyGraph.data = lazyGraph.getAttribute('lazy'); 17 | lazyGraph.removeAttribute('lazy'); 18 | 19 | lazyGraphs = lazyGraphs.filter(function(image) { return image !== lazyGraph}); 20 | 21 | if (lazyGraphs.length === 0) { 22 | document.removeEventListener('scroll', lazyLoad); 23 | window.removeEventListener('resize', lazyLoad); 24 | window.removeEventListener('orientationchange', lazyLoad); 25 | } 26 | } 27 | }); 28 | 29 | active = false; 30 | }, 200); 31 | } 32 | }; 33 | 34 | // initial load 35 | lazyLoad(); 36 | 37 | var container = document.querySelector('.container-fluid.modules'); 38 | if (container) { 39 | container.addEventListener('scroll', lazyLoad); 40 | window.addEventListener('resize', lazyLoad); 41 | window.addEventListener('orientationchange', lazyLoad); 42 | } 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /docs/js/libs/EventDispatcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | var EventDispatcher=function(){};Object.assign(EventDispatcher.prototype,{addEventListener:function(i,t){void 0===this._listeners&&(this._listeners={});var e=this._listeners;void 0===e[i]&&(e[i]=[]),-1===e[i].indexOf(t)&&e[i].push(t)},hasEventListener:function(i,t){if(void 0===this._listeners)return!1;var e=this._listeners;return void 0!==e[i]&&-1!==e[i].indexOf(t)},removeEventListener:function(i,t){if(void 0!==this._listeners){var e=this._listeners[i];if(void 0!==e){var s=e.indexOf(t);-1!==s&&e.splice(s,1)}}},dispatchEvent:function(i){if(void 0!==this._listeners){var t=this._listeners[i.type];if(void 0!==t){i.target=this;var e=[],s=0,n=t.length;for(s=0;s",">"));else if(1==i){if(r.push("<",e.tagName),e.hasAttributes())for(var n=e.attributes,s=0,o=n.length;s");for(var h=e.childNodes,s=0,o=h.length;s")}else r.push("/>")}else{if(8!=i)throw"Error serializing XML. Unhandled node of type: "+i;r.push("\x3c!--",e.nodeValue,"--\x3e")}};Object.defineProperty(e.prototype,"innerHTML",{get:function(){for(var e=[],r=this.firstChild;r;)t(r,e),r=r.nextSibling;return e.join("")},set:function(e){for(;this.firstChild;)this.removeChild(this.firstChild);try{var t=new DOMParser;t.async=!1,sXML=""+e+"";for(var r=t.parseFromString(sXML,"text/xml").documentElement.firstChild;r;)this.appendChild(this.ownerDocument.importNode(r,!0)),r=r.nextSibling}catch(e){throw new Error("Error parsing XML string")}}})}}((0,eval)("this").SVGElement); -------------------------------------------------------------------------------- /docs/js/libs/promise.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 (c) Pierre Duquesne 3 | * Licensed under the New BSD License. 4 | * https://github.com/stackp/promisejs 5 | */ 6 | (function(a){function b(){this._callbacks=[];}b.prototype.then=function(a,c){var d;if(this._isdone)d=a.apply(c,this.result);else{d=new b();this._callbacks.push(function(){var b=a.apply(c,arguments);if(b&&typeof b.then==='function')b.then(d.done,d);});}return d;};b.prototype.done=function(){this.result=arguments;this._isdone=true;for(var a=0;a=300)&&j.status!==304);h.done(a,j.responseText,j);}};j.send(k);return h;}function h(a){return function(b,c,d){return g(a,b,c,d);};}var i={Promise:b,join:c,chain:d,ajax:g,get:h('GET'),post:h('POST'),put:h('PUT'),del:h('DELETE'),ENOXHR:1,ETIMEOUT:2,ajaxTimeout:0};if(typeof define==='function'&&define.amd)define(function(){return i;});else a.promise=i;})(this); -------------------------------------------------------------------------------- /docs/js/libs/tablesort.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * tablesort v5.2.1 (2021-10-30) 3 | * http://tristen.ca/tablesort/demo/ 4 | * Copyright (c) 2021 ; Licensed MIT 5 | */ 6 | !function(){function a(b,c){if(!(this instanceof a))return new a(b,c);if(!b||"TABLE"!==b.tagName)throw new Error("Element must be a table");this.init(b,c||{})}var b=[],c=function(a){var b;return window.CustomEvent&&"function"==typeof window.CustomEvent?b=new CustomEvent(a):(b=document.createEvent("CustomEvent"),b.initCustomEvent(a,!1,!1,void 0)),b},d=function(a,b){return a.getAttribute(b.sortAttribute||"data-sort")||a.textContent||a.innerText||""},e=function(a,b){return a=a.trim().toLowerCase(),b=b.trim().toLowerCase(),a===b?0:a0)if(a.tHead&&a.tHead.rows.length>0){for(e=0;e0&&n.push(m),o++;if(!n)return}for(o=0;o 0) { 9 | tabs = tabs[0].querySelectorAll('li'); 10 | for (var i = 0; i < tabs.length; i++) { 11 | tabs[i].addEventListener('click', updateAddress); 12 | var linkTag = tabs[i].querySelector('a'); 13 | if (location.hash !== '') { 14 | var currentHash = location.hash.substr(1); 15 | if (currentHash === linkTag.dataset.link) { 16 | linkTag.click(); 17 | } 18 | } 19 | } 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /docs/js/tree.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | var tabs = document.getElementsByClassName('nav-tabs')[0], 3 | tabsCollection = tabs.getElementsByTagName('A'), 4 | treeTab; 5 | var len = tabsCollection.length; 6 | for(var i = 0; i < len; i++) { 7 | if (tabsCollection[i].getAttribute('id') === 'tree-tab') { 8 | treeTab = tabsCollection[i]; 9 | } 10 | } 11 | 12 | // short-circuit if no tree tab 13 | if (!treeTab) return; 14 | 15 | var handler = new Tautologistics.NodeHtmlParser.HtmlBuilder(function(error, dom) { 16 | if (error) { 17 | console.log('handler ko'); 18 | } 19 | }), 20 | parser = new Tautologistics.NodeHtmlParser.Parser(handler), 21 | currentLocation = window.location; 22 | parser.parseComplete(COMPONENT_TEMPLATE); 23 | 24 | var newNodes = [], 25 | newEdges = [], 26 | parsedHtml = handler.dom[0], 27 | nodeCount = 0, 28 | nodeLevel = 0; 29 | 30 | newNodes.push({ 31 | _id: 0, 32 | label: parsedHtml.name, 33 | type: parsedHtml.type 34 | }) 35 | //Add id for nodes 36 | var traverseIds = function(o) { 37 | for (i in o) { 38 | if (!!o[i] && typeof(o[i]) == "object") { 39 | if (!o[i].length && o[i].type === 'tag') { 40 | nodeCount += 1; 41 | o[i]._id = nodeCount; 42 | } 43 | traverseIds(o[i]); 44 | } 45 | } 46 | } 47 | parsedHtml._id = 0; 48 | traverseIds(parsedHtml); 49 | 50 | 51 | var DeepIterator = deepIterator.default, 52 | it = DeepIterator(parsedHtml); 53 | for (let { 54 | value, 55 | parent, 56 | parentNode, 57 | key, 58 | type 59 | } of it) { 60 | if (type === 'NonIterableObject' && typeof key !== 'undefined' && value.type === 'tag') { 61 | var newNode = { 62 | id: value._id, 63 | label: value.name, 64 | type: value.type 65 | }; 66 | for(var i = 0; i < COMPONENTS.length; i++) { 67 | if (COMPONENTS[i].selector === value.name) { 68 | newNode.font = { 69 | multi: 'html' 70 | }; 71 | newNode.label = '' + newNode.label + ''; 72 | newNode.color = '#FB7E81'; 73 | newNode.name = COMPONENTS[i].name; 74 | } 75 | } 76 | for(var i = 0; i < DIRECTIVES.length; i++) { 77 | if (value.attributes) { 78 | for(attr in value.attributes) { 79 | if (DIRECTIVES[i].selector.indexOf(attr) !== -1) { 80 | newNode.font = { 81 | multi: 'html' 82 | }; 83 | newNode.label = '' + newNode.label + ''; 84 | newNode.color = '#FF9800'; 85 | newNode.name = DIRECTIVES[i].name; 86 | } 87 | } 88 | } 89 | } 90 | newNodes.push(newNode); 91 | newEdges.push({ 92 | from: parentNode._parent._id, 93 | to: value._id, 94 | arrows: 'to' 95 | }); 96 | } 97 | } 98 | 99 | newNodes.shift(); 100 | 101 | var container = document.getElementById('tree-container'), 102 | data = { 103 | nodes: newNodes, 104 | edges: newEdges 105 | }, 106 | options = { 107 | layout: { 108 | hierarchical: { 109 | sortMethod: 'directed', 110 | enabled: true 111 | } 112 | }, 113 | nodes: { 114 | shape: 'ellipse', 115 | fixed: true 116 | } 117 | }, 118 | 119 | handleClickNode = function(params) { 120 | var clickeNodeId; 121 | if (params.nodes.length > 0) { 122 | clickeNodeId = params.nodes[0]; 123 | for(var i = 0; i < newNodes.length; i++) { 124 | if (newNodes[i].id === clickeNodeId) { 125 | for(var j = 0; j < COMPONENTS.length; j++) { 126 | if (COMPONENTS[j].name === newNodes[i].name) { 127 | document.location.href = currentLocation.origin + currentLocation.pathname.replace(ACTUAL_COMPONENT.name, newNodes[i].name); 128 | } 129 | } 130 | } 131 | } 132 | } 133 | }, 134 | 135 | loadTree = function () { 136 | setTimeout(function() { 137 | container.style.height = document.getElementsByClassName('content')[0].offsetHeight - 140 + 'px'; 138 | var network = new vis.Network(container, data, options); 139 | network.on('click', handleClickNode); 140 | }, 200); // Fade is 0.150 141 | }; 142 | 143 | loadTree(); 144 | treeTab.addEventListener('click', function() { 145 | loadTree(); 146 | }); 147 | }); 148 | -------------------------------------------------------------------------------- /docs/modules/HttpTraceContextPropagatorModule.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | OpenTelemetry Angular Interceptor 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 25 | 26 |
27 |
28 | 31 | 32 |
33 |
34 | 35 | 36 | 37 | 41 | 42 | 43 | 51 | 52 |
53 |
54 | 55 |

56 |

File

57 |

58 |

59 | projects/opentelemetry-interceptor/src/lib/services/propagator/http-trace-context-propagator/http-trace-context-propagator.module.ts 60 |

61 | 62 | 63 | 64 | 65 | 66 |
67 |
68 |
69 |
70 | 71 | 72 |
73 | 74 | 75 |
76 |
import { NgModule } from '@angular/core';
 77 | import { CommonModule } from '@angular/common';
 78 | import { HttpTraceContextPropagatorService } from './http-trace-context-propagator.service';
 79 | import { OTELCOL_PROPAGATOR } from '../propagator.interface';
 80 | 
 81 | 
 82 | 
 83 | @NgModule({
 84 |   declarations: [],
 85 |   imports: [
 86 |     CommonModule,
 87 |   ],
 88 |   providers: [
 89 |     { provide: OTELCOL_PROPAGATOR, useClass: HttpTraceContextPropagatorService }
 90 |   ]
 91 | })
 92 | export class  HttpTraceContextPropagatorModule {
 93 | }
 94 | 
95 |
96 |
97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
113 |
114 |

results matching ""

115 |
    116 |
    117 |
    118 |

    No results matching ""

    119 |
    120 |
    121 |
    122 | 123 |
    124 |
    125 | 126 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /docs/modules/OtelWebTracerModule/dependencies.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | dependencies 11 | 12 | Legend 13 | 14 |  Declarations 15 | 16 |  Module 17 | 18 |  Bootstrap 19 | 20 |  Providers 21 | 22 |  Exports 23 | 24 | cluster_OtelWebTracerModule 25 | 26 | 27 | 28 | cluster_OtelWebTracerModule_declarations 29 | 30 | 31 | 32 | cluster_OtelWebTracerModule_exports 33 | 34 | 35 | 36 | 37 | OtelWebTracerComponent 38 | 39 | OtelWebTracerComponent 40 | 41 | 42 | 43 | OtelWebTracerModule 44 | 45 | OtelWebTracerModule 46 | 47 | 48 | 49 | OtelWebTracerComponent->OtelWebTracerModule 50 | 51 | 52 | 53 | 54 | 55 | OtelWebTracerComponent 56 | 57 | OtelWebTracerComponent 58 | 59 | 60 | 61 | OtelWebTracerModule->OtelWebTracerComponent 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/styles/bootstrap-card.css: -------------------------------------------------------------------------------- 1 | .card { 2 | position: relative; 3 | display: block; 4 | margin-bottom: 20px; 5 | background-color: #fff; 6 | border: 1px solid #ddd; 7 | border-radius: 4px; 8 | } 9 | 10 | .card-block { 11 | padding: 15px; 12 | } 13 | .card-block:before, .card-block:after { 14 | content: " "; 15 | display: table; 16 | } 17 | .card-block:after { 18 | clear: both; 19 | } 20 | 21 | .card-title { 22 | margin: 5px; 23 | margin-bottom: 2px; 24 | text-align: center; 25 | } 26 | 27 | .card-subtitle { 28 | margin-top: -10px; 29 | margin-bottom: 0; 30 | } 31 | 32 | .card-text:last-child { 33 | margin-bottom: 0; 34 | margin-top: 10px; 35 | } 36 | 37 | .card-link:hover { 38 | text-decoration: none; 39 | } 40 | .card-link + .card-link { 41 | margin-left: 15px; 42 | } 43 | 44 | .card > .list-group:first-child .list-group-item:first-child { 45 | border-top-right-radius: 4px; 46 | border-top-left-radius: 4px; 47 | } 48 | .card > .list-group:last-child .list-group-item:last-child { 49 | border-bottom-right-radius: 4px; 50 | border-bottom-left-radius: 4px; 51 | } 52 | 53 | .card-header { 54 | padding: 10px 15px; 55 | background-color: #f5f5f5; 56 | border-bottom: 1px solid #ddd; 57 | } 58 | .card-header:before, .card-header:after { 59 | content: " "; 60 | display: table; 61 | } 62 | .card-header:after { 63 | clear: both; 64 | } 65 | .card-header:first-child { 66 | border-radius: 4px 4px 0 0; 67 | } 68 | 69 | .card-footer { 70 | padding: 10px 15px; 71 | background-color: #f5f5f5; 72 | border-top: 1px solid #ddd; 73 | } 74 | .card-footer:before, .card-footer:after { 75 | content: " "; 76 | display: table; 77 | } 78 | .card-footer:after { 79 | clear: both; 80 | } 81 | .card-footer:last-child { 82 | border-radius: 0 0 4px 4px; 83 | } 84 | 85 | .card-header-tabs { 86 | margin-right: -5px; 87 | margin-bottom: -10px; 88 | margin-left: -5px; 89 | border-bottom: 0; 90 | } 91 | 92 | .card-header-pills { 93 | margin-right: -5px; 94 | margin-left: -5px; 95 | } 96 | 97 | .card-primary { 98 | background-color: #337ab7; 99 | border-color: #337ab7; 100 | } 101 | .card-primary .card-header, 102 | .card-primary .card-footer { 103 | background-color: transparent; 104 | } 105 | 106 | .card-success { 107 | background-color: #5cb85c; 108 | border-color: #5cb85c; 109 | } 110 | .card-success .card-header, 111 | .card-success .card-footer { 112 | background-color: transparent; 113 | } 114 | 115 | .card-info { 116 | background-color: #5bc0de; 117 | border-color: #5bc0de; 118 | } 119 | .card-info .card-header, 120 | .card-info .card-footer { 121 | background-color: transparent; 122 | } 123 | 124 | .card-warning { 125 | background-color: #f0ad4e; 126 | border-color: #f0ad4e; 127 | } 128 | .card-warning .card-header, 129 | .card-warning .card-footer { 130 | background-color: transparent; 131 | } 132 | 133 | .card-danger { 134 | background-color: #d9534f; 135 | border-color: #d9534f; 136 | } 137 | .card-danger .card-header, 138 | .card-danger .card-footer { 139 | background-color: transparent; 140 | } 141 | 142 | .card-outline-primary { 143 | background-color: transparent; 144 | border-color: #337ab7; 145 | } 146 | 147 | .card-outline-secondary { 148 | background-color: transparent; 149 | border-color: #ccc; 150 | } 151 | 152 | .card-outline-info { 153 | background-color: transparent; 154 | border-color: #5bc0de; 155 | } 156 | 157 | .card-outline-success { 158 | background-color: transparent; 159 | border-color: #5cb85c; 160 | } 161 | 162 | .card-outline-warning { 163 | background-color: transparent; 164 | border-color: #f0ad4e; 165 | } 166 | 167 | .card-outline-danger { 168 | background-color: transparent; 169 | border-color: #d9534f; 170 | } 171 | 172 | .card-inverse .card-header, 173 | .card-inverse .card-footer { 174 | border-color: rgba(255, 255, 255, 0.2); 175 | } 176 | .card-inverse .card-header, 177 | .card-inverse .card-footer, 178 | .card-inverse .card-title, 179 | .card-inverse .card-blockquote { 180 | color: #fff; 181 | } 182 | .card-inverse .card-link, 183 | .card-inverse .card-text, 184 | .card-inverse .card-subtitle, 185 | .card-inverse .card-blockquote .blockquote-footer { 186 | color: rgba(255, 255, 255, 0.65); 187 | } 188 | .card-inverse .card-link:hover, .card-inverse .card-link:focus { 189 | color: #fff; 190 | } 191 | 192 | .card-blockquote { 193 | padding: 0; 194 | margin-bottom: 0; 195 | border-left: 0; 196 | } 197 | 198 | .card-img { 199 | border-radius: .25em; 200 | } 201 | 202 | .card-img-overlay { 203 | position: absolute; 204 | top: 0; 205 | right: 0; 206 | bottom: 0; 207 | left: 0; 208 | padding: 15px; 209 | } 210 | 211 | .card-img-top { 212 | border-top-right-radius: 4px; 213 | border-top-left-radius: 4px; 214 | } 215 | 216 | .card-img-bottom { 217 | border-bottom-right-radius: 4px; 218 | border-bottom-left-radius: 4px; 219 | } 220 | -------------------------------------------------------------------------------- /docs/styles/dark.css: -------------------------------------------------------------------------------- 1 | body.dark { 2 | background: #212121; 3 | color: #fafafa; 4 | } 5 | 6 | .dark code { 7 | color: #e09393; 8 | } 9 | 10 | .dark a, 11 | .dark .menu ul.list li a.active { 12 | color: #7fc9ff; 13 | } 14 | 15 | .dark .menu { 16 | background: #212121; 17 | border-right: 1px solid #444; 18 | } 19 | 20 | .dark .menu ul.list li a { 21 | color: #fafafa; 22 | } 23 | 24 | .dark .menu ul.list li.divider { 25 | background: #444; 26 | } 27 | 28 | .dark .xs-menu ul.list li:nth-child(2) { 29 | margin: 0; 30 | background: none; 31 | } 32 | 33 | .dark .menu ul.list li:nth-child(2) { 34 | margin: 0; 35 | background: none; 36 | } 37 | 38 | .dark #book-search-input { 39 | background: #212121; 40 | border-top: 1px solid #444; 41 | border-bottom: 1px solid #444; 42 | color: #fafafa; 43 | } 44 | 45 | .dark .table.metadata > tbody > tr:hover { 46 | color: #555; 47 | } 48 | 49 | .dark .table-bordered { 50 | border: 1px solid #444; 51 | } 52 | 53 | .dark .table-bordered > tbody > tr > td, 54 | .dark .table-bordered > tbody > tr > th, 55 | .dark .table-bordered > tfoot > tr > td, 56 | .dark .table-bordered > tfoot > tr > th, 57 | .dark .table-bordered > thead > tr > td, 58 | .dark .table-bordered > thead > tr > th { 59 | border: 1px solid #444; 60 | } 61 | 62 | .dark .coverage a, 63 | .dark .coverage-count { 64 | color: #fafafa; 65 | } 66 | 67 | .dark .coverage-header { 68 | color: black; 69 | } 70 | 71 | .dark .routes svg text, 72 | .dark .routes svg a { 73 | fill: white; 74 | } 75 | .dark .routes svg rect { 76 | fill: #212121 !important; 77 | } 78 | 79 | .dark .navbar-default, 80 | .dark .btn-default { 81 | background-color: black; 82 | border-color: #444; 83 | color: #fafafa; 84 | } 85 | 86 | .dark .navbar-default .navbar-brand { 87 | color: #fafafa; 88 | } 89 | 90 | .dark .overview .card, 91 | .dark .modules .card { 92 | background: #171717; 93 | color: #fafafa; 94 | border: 1px solid #444; 95 | } 96 | .dark .overview .card a { 97 | color: #fafafa; 98 | } 99 | 100 | .dark .modules .card-header { 101 | background: none; 102 | border-bottom: 1px solid #444; 103 | } 104 | 105 | .dark .module .list-group-item { 106 | background: none; 107 | border: 1px solid #444; 108 | } 109 | 110 | .dark .container-fluid.module h3 a { 111 | color: #337ab7; 112 | } 113 | 114 | .dark table.params thead { 115 | background: #484848; 116 | color: #fafafa; 117 | } 118 | 119 | .dark .content table { 120 | --bs-table-color: #fafafa; 121 | } 122 | -------------------------------------------------------------------------------- /docs/styles/laravel.css: -------------------------------------------------------------------------------- 1 | .nav-tabs > li > a { 2 | text-decoration: none; 3 | } 4 | 5 | .navbar-default .navbar-brand { 6 | color: #f4645f; 7 | text-decoration: none; 8 | font-size: 16px; 9 | } 10 | 11 | .menu ul.list li a[data-type='chapter-link'], 12 | .menu ul.list li.chapter .simple { 13 | color: #525252; 14 | border-bottom: 1px dashed rgba(0, 0, 0, 0.1); 15 | } 16 | 17 | .content h1, 18 | .content h2, 19 | .content h3, 20 | .content h4, 21 | .content h5 { 22 | color: #292e31; 23 | font-weight: normal; 24 | } 25 | 26 | .content { 27 | color: #4c555a; 28 | } 29 | 30 | a { 31 | color: #f4645f; 32 | text-decoration: underline; 33 | } 34 | a:hover { 35 | color: #f1362f; 36 | } 37 | 38 | .menu ul.list li:nth-child(2) { 39 | margin-top: 0; 40 | } 41 | 42 | .menu ul.list li.title a { 43 | color: #f4645f; 44 | text-decoration: none; 45 | font-size: 16px; 46 | } 47 | 48 | .menu ul.list li a { 49 | color: #f4645f; 50 | text-decoration: none; 51 | } 52 | .menu ul.list li a.active { 53 | color: #f4645f; 54 | font-weight: bold; 55 | } 56 | 57 | code { 58 | box-sizing: border-box; 59 | display: inline-block; 60 | padding: 0 5px; 61 | background: #f0f2f1; 62 | border-radius: 3px; 63 | color: #b93d6a; 64 | font-size: 13px; 65 | line-height: 20px; 66 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.125); 67 | } 68 | 69 | pre { 70 | margin: 0; 71 | padding: 12px 12px; 72 | background: rgba(238, 238, 238, 0.35); 73 | border-radius: 3px; 74 | font-size: 13px; 75 | line-height: 1.5em; 76 | font-weight: 500; 77 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.125); 78 | } 79 | 80 | .dark body { 81 | color: #fafafa; 82 | } 83 | .dark .content h1, 84 | .dark .content h2, 85 | .dark .content h3, 86 | .dark .content h4, 87 | .dark .content h5 { 88 | color: #fafafa; 89 | } 90 | 91 | .dark code { 92 | background: none; 93 | } 94 | 95 | .dark .content { 96 | color: #fafafa; 97 | } 98 | 99 | .dark .menu ul.list li a[data-type='chapter-link'], 100 | .dark .menu ul.list li.chapter .simple { 101 | color: #fafafa; 102 | } 103 | 104 | .dark .menu ul.list li.title a { 105 | color: #fafafa; 106 | } 107 | 108 | .dark .menu ul.list li a { 109 | color: #fafafa; 110 | } 111 | .dark .menu ul.list li a.active { 112 | color: #7fc9ff; 113 | } 114 | -------------------------------------------------------------------------------- /docs/styles/material.css: -------------------------------------------------------------------------------- 1 | .menu { 2 | background: none; 3 | } 4 | 5 | a:hover { 6 | text-decoration: none; 7 | } 8 | 9 | /** LINK **/ 10 | 11 | .menu ul.list li a { 12 | text-decoration: none; 13 | } 14 | 15 | .menu ul.list li a:hover, 16 | .menu ul.list li.chapter .simple:hover { 17 | background-color: #f8f9fa; 18 | text-decoration: none; 19 | } 20 | 21 | #book-search-input { 22 | margin-bottom: 0; 23 | } 24 | 25 | .menu ul.list li.divider { 26 | margin-top: 0; 27 | background: #e9ecef; 28 | } 29 | 30 | .menu .title:hover { 31 | background-color: #f8f9fa; 32 | } 33 | 34 | /** CARD **/ 35 | 36 | .card { 37 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 38 | 0 1px 5px 0 rgba(0, 0, 0, 0.12); 39 | border-radius: 0.125rem; 40 | border: 0; 41 | margin-top: 1px; 42 | } 43 | 44 | .card-header { 45 | background: none; 46 | } 47 | 48 | /** BUTTON **/ 49 | 50 | .btn { 51 | border-radius: 0.125rem; 52 | } 53 | 54 | /** NAV BAR **/ 55 | 56 | .nav { 57 | border: 0; 58 | } 59 | .nav-tabs > li > a { 60 | border: 0; 61 | border-bottom: 0.214rem solid transparent; 62 | color: rgba(0, 0, 0, 0.54); 63 | margin-right: 0; 64 | } 65 | .nav-tabs > li.active > a, 66 | .nav-tabs > li.active > a:focus, 67 | .nav-tabs > li.active > a:hover { 68 | color: rgba(0, 0, 0, 0.87); 69 | border-top: 0; 70 | border-left: 0; 71 | border-right: 0; 72 | border-bottom: 0.214rem solid transparent; 73 | border-color: #008cff; 74 | font-weight: bold; 75 | } 76 | .nav > li > a:focus, 77 | .nav > li > a:hover { 78 | background: none; 79 | } 80 | 81 | /** LIST **/ 82 | 83 | .list-group-item:first-child { 84 | border-top-left-radius: 0.125rem; 85 | border-top-right-radius: 0.125rem; 86 | } 87 | .list-group-item:last-child { 88 | border-bottom-left-radius: 0.125rem; 89 | border-bottom-right-radius: 0.125rem; 90 | } 91 | 92 | /** MISC **/ 93 | 94 | .modifier { 95 | border-radius: 0.125rem; 96 | } 97 | 98 | pre[class*='language-'] { 99 | border-radius: 0.125rem; 100 | } 101 | 102 | /** TABLE **/ 103 | 104 | .table-hover > tbody > tr:hover { 105 | background: rgba(0, 0, 0, 0.075); 106 | } 107 | 108 | table.params thead { 109 | background: none; 110 | } 111 | table.params thead td { 112 | color: rgba(0, 0, 0, 0.54); 113 | font-weight: bold; 114 | } 115 | 116 | .dark .menu .title:hover { 117 | background-color: #2d2d2d; 118 | } 119 | .dark .menu ul.list li a:hover, 120 | .dark .menu ul.list li.chapter .simple:hover { 121 | background-color: #2d2d2d; 122 | } 123 | .dark .nav-tabs > li:not(.active) > a { 124 | color: #fafafa; 125 | } 126 | .dark table.params thead { 127 | background: #484848; 128 | } 129 | .dark table.params thead td { 130 | color: #fafafa; 131 | } 132 | -------------------------------------------------------------------------------- /docs/styles/original.css: -------------------------------------------------------------------------------- 1 | .navbar-default .navbar-brand, 2 | .menu ul.list li.title { 3 | font-weight: bold; 4 | color: #3c3c3c; 5 | padding-bottom: 5px; 6 | } 7 | 8 | .menu ul.list li a[data-type='chapter-link'], 9 | .menu ul.list li.chapter .simple { 10 | font-weight: bold; 11 | font-size: 14px; 12 | } 13 | 14 | .menu ul.list li a[href='./routes.html'] { 15 | border-bottom: none; 16 | } 17 | 18 | .menu ul.list > li:nth-child(2) { 19 | display: none; 20 | } 21 | 22 | .menu ul.list li.chapter ul.links { 23 | background: #fff; 24 | padding-left: 0; 25 | } 26 | 27 | .menu ul.list li.chapter ul.links li { 28 | border-bottom: 1px solid #ddd; 29 | padding-left: 20px; 30 | } 31 | 32 | .menu ul.list li.chapter ul.links li:last-child { 33 | border-bottom: none; 34 | } 35 | 36 | .menu ul.list li a.active { 37 | color: #337ab7; 38 | font-weight: bold; 39 | } 40 | 41 | #book-search-input { 42 | margin-bottom: 0; 43 | border-bottom: none; 44 | } 45 | .menu ul.list li.divider { 46 | margin: 0; 47 | } 48 | 49 | .dark .menu ul.list li.chapter ul.links { 50 | background: none; 51 | } 52 | -------------------------------------------------------------------------------- /docs/styles/postmark.css: -------------------------------------------------------------------------------- 1 | .navbar-default { 2 | background: #ffde00; 3 | border: none; 4 | } 5 | 6 | .navbar-default .navbar-brand { 7 | color: #333; 8 | font-weight: bold; 9 | } 10 | 11 | .menu { 12 | background: #333; 13 | color: #fcfcfc; 14 | } 15 | 16 | .menu ul.list li a { 17 | color: #333; 18 | } 19 | 20 | .menu ul.list li.title { 21 | background: #ffde00; 22 | color: #333; 23 | padding-bottom: 5px; 24 | } 25 | 26 | .menu ul.list li:nth-child(2) { 27 | margin-top: 0; 28 | } 29 | 30 | .menu ul.list li.chapter a, 31 | .menu ul.list li.chapter .simple { 32 | color: white; 33 | text-decoration: none; 34 | } 35 | 36 | .menu ul.list li.chapter ul.links a { 37 | color: #949494; 38 | text-transform: none; 39 | padding-left: 35px; 40 | } 41 | 42 | .menu ul.list li.chapter ul.links a:hover, 43 | .menu ul.list li.chapter ul.links a.active { 44 | color: #ffde00; 45 | } 46 | 47 | .menu ul.list li.chapter ul.links { 48 | padding-left: 0; 49 | } 50 | 51 | .menu ul.list li.divider { 52 | background: rgba(255, 255, 255, 0.07); 53 | } 54 | 55 | #book-search-input input, 56 | #book-search-input input:focus, 57 | #book-search-input input:hover { 58 | color: #949494; 59 | } 60 | 61 | .copyright { 62 | color: #b3b3b3; 63 | background: #272525; 64 | } 65 | 66 | .content { 67 | background: #fcfcfc; 68 | } 69 | 70 | .content a { 71 | color: #007dcc; 72 | } 73 | 74 | .content a:visited { 75 | color: #0165a5; 76 | } 77 | 78 | .menu ul.list li:nth-last-child(2) { 79 | background: none; 80 | } 81 | 82 | .list-group-item:first-child, 83 | .list-group-item:last-child { 84 | border-radius: 0; 85 | } 86 | 87 | .menu ul.list li.title a { 88 | text-decoration: none; 89 | font-weight: bold; 90 | } 91 | 92 | .menu ul.list li.title a:hover { 93 | background: rgba(255, 255, 255, 0.1); 94 | } 95 | 96 | .breadcrumb > li + li:before { 97 | content: '»\00a0'; 98 | } 99 | 100 | .breadcrumb { 101 | padding-bottom: 15px; 102 | border-bottom: 1px solid #e1e4e5; 103 | } 104 | 105 | code { 106 | white-space: nowrap; 107 | max-width: 100%; 108 | background: #f5f5f5; 109 | padding: 2px 5px; 110 | color: #666666; 111 | overflow-x: auto; 112 | border-radius: 0; 113 | } 114 | 115 | pre { 116 | white-space: pre; 117 | margin: 0; 118 | padding: 12px 12px; 119 | font-size: 12px; 120 | line-height: 1.5; 121 | display: block; 122 | overflow: auto; 123 | color: #404040; 124 | background: #f3f3f3; 125 | } 126 | 127 | pre code.hljs { 128 | border: none; 129 | background: inherit; 130 | } 131 | 132 | /* 133 | Atom One Light by Daniel Gamage 134 | Original One Light Syntax theme from https://github.com/atom/one-light-syntax 135 | base: #fafafa 136 | mono-1: #383a42 137 | mono-2: #686b77 138 | mono-3: #a0a1a7 139 | hue-1: #0184bb 140 | hue-2: #4078f2 141 | hue-3: #a626a4 142 | hue-4: #50a14f 143 | hue-5: #e45649 144 | hue-5-2: #c91243 145 | hue-6: #986801 146 | hue-6-2: #c18401 147 | */ 148 | 149 | .hljs { 150 | display: block; 151 | overflow-x: auto; 152 | padding: 0.5em; 153 | color: #383a42; 154 | background: #fafafa; 155 | } 156 | 157 | .hljs-comment, 158 | .hljs-quote { 159 | color: #a0a1a7; 160 | font-style: italic; 161 | } 162 | 163 | .hljs-doctag, 164 | .hljs-keyword, 165 | .hljs-formula { 166 | color: #a626a4; 167 | } 168 | 169 | .hljs-section, 170 | .hljs-name, 171 | .hljs-selector-tag, 172 | .hljs-deletion, 173 | .hljs-subst { 174 | color: #e45649; 175 | } 176 | 177 | .hljs-literal { 178 | color: #0184bb; 179 | } 180 | 181 | .hljs-string, 182 | .hljs-regexp, 183 | .hljs-addition, 184 | .hljs-attribute, 185 | .hljs-meta-string { 186 | color: #50a14f; 187 | } 188 | 189 | .hljs-built_in, 190 | .hljs-class .hljs-title { 191 | color: #c18401; 192 | } 193 | 194 | .hljs-attr, 195 | .hljs-variable, 196 | .hljs-template-variable, 197 | .hljs-type, 198 | .hljs-selector-class, 199 | .hljs-selector-attr, 200 | .hljs-selector-pseudo, 201 | .hljs-number { 202 | color: #986801; 203 | } 204 | 205 | .hljs-symbol, 206 | .hljs-bullet, 207 | .hljs-link, 208 | .hljs-meta, 209 | .hljs-selector-id, 210 | .hljs-title { 211 | color: #4078f2; 212 | } 213 | 214 | .hljs-emphasis { 215 | font-style: italic; 216 | } 217 | 218 | .hljs-strong { 219 | font-weight: bold; 220 | } 221 | 222 | .hljs-link { 223 | text-decoration: underline; 224 | } 225 | 226 | .dark .content { 227 | background: none; 228 | } 229 | .dark code { 230 | background: none; 231 | color: #e09393; 232 | } 233 | .dark .menu ul.list li.chapter a.active { 234 | color: #ffde00; 235 | } 236 | .dark .menu { 237 | background: #272525; 238 | } 239 | -------------------------------------------------------------------------------- /docs/styles/readthedocs.css: -------------------------------------------------------------------------------- 1 | .navbar-default { 2 | background: #2980b9; 3 | border: none; 4 | } 5 | 6 | .navbar-default .navbar-brand { 7 | color: #fcfcfc; 8 | } 9 | 10 | .menu { 11 | background: #343131; 12 | color: #fcfcfc; 13 | } 14 | 15 | .menu ul.list li a { 16 | color: #fcfcfc; 17 | } 18 | 19 | .menu ul.list li.title { 20 | background: #2980b9; 21 | padding-bottom: 5px; 22 | } 23 | 24 | .menu ul.list li:nth-child(2) { 25 | margin-top: 0; 26 | } 27 | 28 | .menu ul.list li.chapter a, 29 | .menu ul.list li.chapter .simple { 30 | color: #555; 31 | text-transform: uppercase; 32 | text-decoration: none; 33 | } 34 | 35 | .menu ul.list li.chapter ul.links a { 36 | color: #b3b3b3; 37 | text-transform: none; 38 | padding-left: 35px; 39 | } 40 | 41 | .menu ul.list li.chapter ul.links a:hover { 42 | background: #4e4a4a; 43 | } 44 | 45 | .menu ul.list li.chapter a.active, 46 | .menu ul.list li.chapter ul.links a.active { 47 | color: #0099e5; 48 | } 49 | 50 | .menu ul.list li.chapter ul.links { 51 | padding-left: 0; 52 | } 53 | 54 | .menu ul.list li.divider { 55 | background: rgba(255, 255, 255, 0.07); 56 | } 57 | 58 | #book-search-input input, 59 | #book-search-input input:focus, 60 | #book-search-input input:hover { 61 | color: #949494; 62 | } 63 | 64 | .copyright { 65 | color: #b3b3b3; 66 | background: #272525; 67 | } 68 | 69 | .content { 70 | background: #fcfcfc; 71 | } 72 | 73 | .content a { 74 | color: #2980b9; 75 | } 76 | 77 | .content a:hover { 78 | color: #3091d1; 79 | } 80 | 81 | .content a:visited { 82 | color: #9b59b6; 83 | } 84 | 85 | .menu ul.list li:nth-last-child(2) { 86 | background: none; 87 | } 88 | 89 | code { 90 | white-space: nowrap; 91 | max-width: 100%; 92 | background: #fff; 93 | padding: 2px 5px; 94 | color: #e74c3c; 95 | overflow-x: auto; 96 | border-radius: 0; 97 | } 98 | 99 | pre { 100 | white-space: pre; 101 | margin: 0; 102 | padding: 12px 12px; 103 | font-size: 12px; 104 | line-height: 1.5; 105 | display: block; 106 | overflow: auto; 107 | color: #404040; 108 | background: rgba(238, 238, 238, 0.35); 109 | } 110 | 111 | .dark .content { 112 | background: none; 113 | } 114 | .dark code { 115 | background: none; 116 | color: #e09393; 117 | } 118 | -------------------------------------------------------------------------------- /docs/styles/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, 7 | body, 8 | div, 9 | span, 10 | applet, 11 | object, 12 | iframe, 13 | h1, 14 | h2, 15 | h3, 16 | h4, 17 | h5, 18 | h6, 19 | p, 20 | blockquote, 21 | pre, 22 | a, 23 | abbr, 24 | acronym, 25 | address, 26 | big, 27 | cite, 28 | code, 29 | del, 30 | dfn, 31 | em, 32 | img, 33 | ins, 34 | kbd, 35 | q, 36 | s, 37 | samp, 38 | small, 39 | strike, 40 | strong, 41 | sub, 42 | sup, 43 | tt, 44 | var, 45 | b, 46 | u, 47 | i, 48 | center, 49 | dl, 50 | dt, 51 | dd, 52 | ol, 53 | ul, 54 | li, 55 | fieldset, 56 | form, 57 | label, 58 | legend, 59 | table, 60 | caption, 61 | tbody, 62 | tfoot, 63 | thead, 64 | tr, 65 | th, 66 | td, 67 | article, 68 | aside, 69 | canvas, 70 | details, 71 | embed, 72 | figure, 73 | figcaption, 74 | footer, 75 | header, 76 | hgroup, 77 | menu, 78 | nav, 79 | output, 80 | ruby, 81 | section, 82 | summary, 83 | time, 84 | mark, 85 | audio, 86 | video { 87 | margin: 0; 88 | padding: 0; 89 | border: 0; 90 | font: inherit; 91 | font-size: 100%; 92 | vertical-align: baseline; 93 | } 94 | /* HTML5 display-role reset for older browsers */ 95 | article, 96 | aside, 97 | details, 98 | figcaption, 99 | figure, 100 | footer, 101 | header, 102 | hgroup, 103 | menu, 104 | nav, 105 | section { 106 | display: block; 107 | } 108 | body { 109 | line-height: 1; 110 | } 111 | ol, 112 | ul { 113 | list-style: none; 114 | } 115 | blockquote, 116 | q { 117 | quotes: none; 118 | } 119 | blockquote:before, 120 | blockquote:after, 121 | q:before, 122 | q:after { 123 | content: ''; 124 | content: none; 125 | } 126 | table { 127 | border-collapse: collapse; 128 | border-spacing: 0; 129 | } 130 | -------------------------------------------------------------------------------- /docs/styles/stripe.css: -------------------------------------------------------------------------------- 1 | .navbar-default .navbar-brand { 2 | color: #0099e5; 3 | } 4 | 5 | .menu ul.list li a[data-type='chapter-link'], 6 | .menu ul.list li.chapter .simple { 7 | color: #939da3; 8 | text-transform: uppercase; 9 | } 10 | 11 | .content h1, 12 | .content h2, 13 | .content h3, 14 | .content h4, 15 | .content h5 { 16 | color: #292e31; 17 | font-weight: normal; 18 | } 19 | 20 | .content { 21 | color: #4c555a; 22 | } 23 | 24 | .menu ul.list li.title { 25 | padding: 5px 0; 26 | } 27 | 28 | a { 29 | color: #0099e5; 30 | text-decoration: none; 31 | } 32 | a:hover { 33 | color: #292e31; 34 | text-decoration: none; 35 | } 36 | 37 | .menu ul.list li:nth-child(2) { 38 | margin-top: 0; 39 | } 40 | 41 | .menu ul.list li.title a, 42 | .navbar a { 43 | color: #0099e5; 44 | text-decoration: none; 45 | font-size: 16px; 46 | } 47 | 48 | .menu ul.list li a.active { 49 | color: #0099e5; 50 | } 51 | 52 | code { 53 | box-sizing: border-box; 54 | display: inline-block; 55 | padding: 0 5px; 56 | background: #fafcfc; 57 | border-radius: 4px; 58 | color: #b93d6a; 59 | font-size: 13px; 60 | line-height: 20px; 61 | } 62 | 63 | pre { 64 | margin: 0; 65 | padding: 12px 12px; 66 | background: #272b2d; 67 | border-radius: 5px; 68 | font-size: 13px; 69 | line-height: 1.5em; 70 | font-weight: 500; 71 | } 72 | 73 | .dark body { 74 | color: #fafafa; 75 | } 76 | .dark .content h1, 77 | .dark .content h2, 78 | .dark .content h3, 79 | .dark .content h4, 80 | .dark .content h5 { 81 | color: #fafafa; 82 | } 83 | 84 | .dark code { 85 | background: none; 86 | } 87 | 88 | .dark .content { 89 | color: #fafafa; 90 | } 91 | 92 | .dark .menu ul.list li a[data-type='chapter-link'], 93 | .dark .menu ul.list li.chapter .simple { 94 | color: #fafafa; 95 | } 96 | 97 | .dark .menu ul.list li.title a { 98 | color: #fafafa; 99 | } 100 | 101 | .dark .menu ul.list li a { 102 | color: #fafafa; 103 | } 104 | .dark .menu ul.list li a.active { 105 | color: #7fc9ff; 106 | } 107 | -------------------------------------------------------------------------------- /docs/styles/style.css: -------------------------------------------------------------------------------- 1 | @import "./reset.css"; 2 | @import "./bootstrap.min.css"; 3 | @import "./bootstrap-card.css"; 4 | @import "./prism.css"; 5 | @import "./ionicons.min.css"; 6 | @import "./compodoc.css"; 7 | @import "./tablesort.css"; 8 | -------------------------------------------------------------------------------- /docs/styles/tablesort.css: -------------------------------------------------------------------------------- 1 | th[role=columnheader]:not(.no-sort) { 2 | cursor: pointer; 3 | } 4 | 5 | th[role=columnheader]:not(.no-sort):after { 6 | content: ''; 7 | float: right; 8 | margin-top: 7px; 9 | border-width: 0 4px 4px; 10 | border-style: solid; 11 | border-color: #404040 transparent; 12 | visibility: visible; 13 | opacity: 1; 14 | -ms-user-select: none; 15 | -webkit-user-select: none; 16 | -moz-user-select: none; 17 | user-select: none; 18 | } 19 | 20 | th[aria-sort=ascending]:not(.no-sort):after { 21 | border-bottom: none; 22 | border-width: 4px 4px 0; 23 | } 24 | 25 | th[aria-sort]:not(.no-sort):after { 26 | visibility: visible; 27 | opacity: 0.4; 28 | } 29 | 30 | th[role=columnheader]:not(.no-sort):hover:after { 31 | visibility: visible; 32 | opacity: 1; 33 | } 34 | -------------------------------------------------------------------------------- /docs/styles/vagrant.css: -------------------------------------------------------------------------------- 1 | .navbar-default .navbar-brand { 2 | background: white; 3 | color: #8d9ba8; 4 | } 5 | 6 | .menu .list { 7 | background: #0c5593; 8 | } 9 | 10 | .menu .chapter { 11 | padding: 0 20px; 12 | } 13 | 14 | .menu ul.list li a[data-type='chapter-link'], 15 | .menu ul.list li.chapter .simple { 16 | color: white; 17 | text-transform: uppercase; 18 | border-bottom: 1px solid rgba(255, 255, 255, 0.4); 19 | } 20 | 21 | .content h1, 22 | .content h2, 23 | .content h3, 24 | .content h4, 25 | .content h5 { 26 | color: #292e31; 27 | font-weight: normal; 28 | } 29 | 30 | .content { 31 | color: #4c555a; 32 | } 33 | 34 | a { 35 | color: #0094bf; 36 | text-decoration: underline; 37 | } 38 | a:hover { 39 | color: #f1362f; 40 | } 41 | 42 | .menu ul.list li.title { 43 | background: white; 44 | padding-bottom: 5px; 45 | } 46 | 47 | .menu ul.list li:nth-child(2) { 48 | margin-top: 0; 49 | } 50 | 51 | .menu ul.list li:nth-last-child(2) { 52 | background: none; 53 | } 54 | 55 | .menu ul.list li.title a { 56 | padding: 10px 15px; 57 | } 58 | 59 | .menu ul.list li.title a, 60 | .navbar a { 61 | color: #8d9ba8; 62 | text-decoration: none; 63 | font-size: 16px; 64 | font-weight: 300; 65 | } 66 | 67 | .menu ul.list li a { 68 | color: white; 69 | padding: 10px; 70 | font-weight: 300; 71 | text-decoration: none; 72 | } 73 | .menu ul.list li a.active { 74 | color: white; 75 | font-weight: bold; 76 | } 77 | 78 | .copyright { 79 | color: white; 80 | background: #000; 81 | } 82 | 83 | code { 84 | box-sizing: border-box; 85 | display: inline-block; 86 | padding: 0 5px; 87 | background: rgba(0, 148, 191, 0.1); 88 | border-radius: 3px; 89 | color: #0094bf; 90 | font-size: 13px; 91 | line-height: 20px; 92 | } 93 | 94 | pre { 95 | margin: 0; 96 | padding: 12px 12px; 97 | background: rgba(238, 238, 238, 0.35); 98 | border-radius: 3px; 99 | font-size: 13px; 100 | line-height: 1.5em; 101 | font-weight: 500; 102 | } 103 | 104 | .dark body { 105 | color: #fafafa; 106 | } 107 | .dark .content h1, 108 | .dark .content h2, 109 | .dark .content h3, 110 | .dark .content h4, 111 | .dark .content h5 { 112 | color: #fafafa; 113 | } 114 | 115 | .dark code { 116 | background: none; 117 | } 118 | 119 | .dark .content { 120 | color: #fafafa; 121 | } 122 | 123 | .dark .menu ul.list li.title a, 124 | .dark .navbar a { 125 | color: #8d9ba8; 126 | } 127 | 128 | .dark .menu ul.list li a { 129 | color: #fafafa; 130 | } 131 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | globalThis.ngJest = { 2 | skipNgcc: true, 3 | tsconfig: '/projects/opentelemetry-interceptor/tsconfig.spec.json', // this is the project root tsconfig 4 | }; 5 | 6 | 7 | module.exports = { 8 | verbose: false, 9 | preset: 'jest-preset-angular', 10 | roots: ['/projects/opentelemetry-interceptor/src'], 11 | coverageReporters: ['lcov', ['text', { skipFull: true }]], 12 | reporters: [ 13 | ['github-actions', { silent: false }], 14 | 'summary', 15 | ["jest-html-reporters", { 16 | publicPath: "./jest-report", 17 | filename: "report.html", 18 | }], 19 | ['jest-junit', { 20 | outputDirectory: '/jest-report', 21 | outputName: "jest-junit.xml" 22 | }] 23 | ], 24 | setupFilesAfterEnv: [ 25 | '/projects/opentelemetry-interceptor/setupJest.ts' 26 | ], 27 | globalSetup: 'jest-preset-angular/global-setup', 28 | testPathIgnorePatterns: [ 29 | '/node_modules/', 30 | '/dist/opentelemetry-interceptor/', 31 | '/projects/instrumentation-example/', 32 | '/projects/interceptor-example/', 33 | '/cypress/' 34 | ], 35 | transform: { 36 | '^.+\\.tsx?$': ['jest-preset-angular', { 37 | tsconfig: '/projects/opentelemetry-interceptor/tsconfig.spec.json', 38 | }] 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "opentelemetry-angular-interceptor", 3 | "version": "1.9.0-1", 4 | "homepage": "https://github.com/jufab/opentelemetry-angular-interceptor", 5 | "author": { 6 | "name": "Julien Fabre" 7 | }, 8 | "scripts": { 9 | "ng": "ng", 10 | "start": "ng serve", 11 | "build": "ng build", 12 | "build:prod": "ng build opentelemetry-interceptor --configuration production && cp README.md dist/opentelemetry-interceptor/README.md", 13 | "test": "jest --coverage", 14 | "lint": "ng lint", 15 | "release": "standard-version", 16 | "e2e": "ng e2e", 17 | "cypress": "concurrently -k -p \"[{name}]\" -n \"backend,interceptor-example,cypress\" -c \"green.bold,cyan.bold,yellow.bold\" \"npm run start:backend-interceptor-example\" \"npm start interceptor-example\" \"cypress open\"", 18 | "cypress-instrumentation": "concurrently -k -p \"[{name}]\" -n \"backend,instrumentation-example,cypress\" -c \"green.bold,cyan.bold,yellow.bold\" \"npm run start:backend-instrumentation-example\" \"npm start instrumentation-example\" \"cypress open\"", 19 | "cypress:run": "concurrently -k -s first -p \"[{name}]\" -n \"backend,interceptor-example,cypress\" -c \"green.bold,cyan.bold,yellow.bold\" \"npm run start:backend-interceptor-example\" \"npm start interceptor-example\" \"cypress run\"", 20 | "cypress-instrumentation:run": "concurrently -k -s first -p \"[{name}]\" -n \"backend,instrumentation-example,cypress\" -c \"green.bold,cyan.bold,yellow.bold\" \"npm run start:backend-instrumentation-example\" \"npm start instrumentation-example\" \"cypress run\"", 21 | "start:backend-interceptor-example": "node ./projects/interceptor-example/src/backend-api.js", 22 | "start:complete-interceptor-example": "concurrently -k -p \"[{name}]\" -n \"backend,interceptor-example\" -c \"green.bold,cyan.bold\" \"npm run start:backend-interceptor-example\" \"npm start interceptor-example\"", 23 | "start:backend-instrumentation-example": "node ./projects/instrumentation-example/src/backend-api.js", 24 | "start:complete-instrumentation-example": "concurrently -k -p \"[{name}]\" -n \"backend,instrumentation-example\" -c \"green.bold,cyan.bold\" \"npm run start:backend-instrumentation-example\" \"npm start instrumentation-example\"", 25 | "compodoc": "npx compodoc -t -p projects/opentelemetry-interceptor/tsconfig.lib.json --theme material -d ./docs -n \"OpenTelemetry Angular Interceptor\"" 26 | }, 27 | "private": true, 28 | "engines": { 29 | "node": ">=12.20.0" 30 | }, 31 | "standard-version": { 32 | "bumpFiles": [ 33 | "./projects/opentelemetry-interceptor/package.json", 34 | "package.json", 35 | { 36 | "filename": "./projects/opentelemetry-interceptor/src/version.json", 37 | "type": "json" 38 | } 39 | ] 40 | }, 41 | "dependencies": { 42 | "@angular-devkit/core": "^14.2.12", 43 | "@angular/animations": "^14.3.0", 44 | "@angular/cdk": "^14.2.7", 45 | "@angular/common": "^14.3.0", 46 | "@angular/compiler": "^14.3.0", 47 | "@angular/core": "^14.3.0", 48 | "@angular/forms": "^14.3.0", 49 | "@angular/material": "^14.2.7", 50 | "@angular/platform-browser": "^14.3.0", 51 | "@angular/platform-browser-dynamic": "^14.3.0", 52 | "@angular/router": "^14.3.0", 53 | "ngx-highlight-js": "^13.0.0", 54 | "ngx-logger": "5.0.12", 55 | "rxjs": "^6.6.3", 56 | "tslib": "^2.6.0", 57 | "zone.js": "~0.11.4" 58 | }, 59 | "devDependencies": { 60 | "@angular-devkit/build-angular": "^14.2.12", 61 | "@angular-eslint/builder": "14.4.0", 62 | "@angular-eslint/eslint-plugin": "14.4.0", 63 | "@angular-eslint/eslint-plugin-template": "14.4.0", 64 | "@angular-eslint/schematics": "14.4.0", 65 | "@angular-eslint/template-parser": "14.4.0", 66 | "@angular/cli": "^14.2.12", 67 | "@angular/compiler-cli": "^14.3.0", 68 | "@angular/language-service": "^14.3.0", 69 | "@compodoc/compodoc": "^1.1.25", 70 | "@opentelemetry/api": "1.9.0", 71 | "@opentelemetry/context-zone-peer-dep": "2.0.0", 72 | "@opentelemetry/exporter-trace-otlp-http": "0.200.0", 73 | "@opentelemetry/exporter-zipkin": "2.0.0", 74 | "@opentelemetry/instrumentation": "0.200.0", 75 | "@opentelemetry/instrumentation-xml-http-request": "0.200.0", 76 | "@opentelemetry/propagator-aws-xray": "2.0.0", 77 | "@opentelemetry/propagator-b3": "2.0.0", 78 | "@opentelemetry/propagator-jaeger": "2.0.0", 79 | "@opentelemetry/sdk-trace-web": "2.0.0", 80 | "@types/express": "^4.17.21", 81 | "@types/jest": "^29.5.13", 82 | "@types/node": "16.18.88", 83 | "@typescript-eslint/eslint-plugin": "^6.19.0", 84 | "@typescript-eslint/parser": "^6.19.0", 85 | "concurrently": "^9.0.1", 86 | "cypress": "^13.14.2", 87 | "eslint": "^8.56.0", 88 | "eslint-plugin-import": "2.30.0", 89 | "eslint-plugin-jsdoc": "^50.2.3", 90 | "eslint-plugin-prefer-arrow": "1.2.3", 91 | "express": "^4.21.0", 92 | "jest": "^29.7.0", 93 | "jest-html-reporters": "^3.1.7", 94 | "jest-junit": "^16.0.0", 95 | "jest-preset-angular": "^13.1.6", 96 | "ng-packagr": "^14.2.2", 97 | "standard-version": "^9.5.0", 98 | "ts-jest": "^29.2.5", 99 | "ts-node": "~10.9.2", 100 | "typescript": "~4.6.4" 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /projects/instrumentation-example/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /projects/instrumentation-example/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc.json", 3 | "ignorePatterns": [ 4 | "!**/*" 5 | ], 6 | "overrides": [ 7 | { 8 | "files": [ 9 | "*.ts" 10 | ], 11 | "parserOptions": { 12 | "project": [ 13 | "projects/instrumentation-example/tsconfig.app.json", 14 | "projects/instrumentation-example/tsconfig.spec.json" 15 | ], 16 | "createDefaultProgram": true 17 | }, 18 | "rules": { 19 | "@angular-eslint/component-selector": [ 20 | "error", 21 | { 22 | "type": "element", 23 | "prefix": "app", 24 | "style": "kebab-case" 25 | } 26 | ], 27 | "@angular-eslint/directive-selector": [ 28 | "error", 29 | { 30 | "type": "attribute", 31 | "prefix": "app", 32 | "style": "camelCase" 33 | } 34 | ] 35 | } 36 | }, 37 | { 38 | "files": [ 39 | "*.html" 40 | ], 41 | "rules": {} 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /projects/instrumentation-example/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/api/*": { 3 | "target": "http://localhost:3000/", 4 | "secure": false, 5 | "logLevel": "debug" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { ViewBackendComponent } from './view-backend/view-backend.component'; 4 | import { PostBackendComponent } from './post-backend/post-backend.component'; 5 | import { JsonpBackendComponent } from './jsonp-backend/jsonp-backend.component'; 6 | 7 | const routes: Routes = [ 8 | { path: 'view', component: ViewBackendComponent }, 9 | { path: 'post', component: PostBackendComponent }, 10 | { path: 'jsonp', component: JsonpBackendComponent }, 11 | { path: '', redirectTo: '/view', pathMatch: 'full' }, 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })], 16 | exports: [RouterModule], 17 | }) 18 | export class AppRoutingModule {} 19 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | .example-icon { 2 | padding: 0 14px; 3 | } 4 | 5 | .example-spacer { 6 | flex: 1 1 auto; 7 | } 8 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | {{title}} 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'Instrumentation-example'; 10 | } 11 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { AppComponent } from './app.component'; 5 | import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http'; 6 | import { MatToolbarModule } from '@angular/material/toolbar'; 7 | import { MatCardModule } from '@angular/material/card'; 8 | import { MatFormFieldModule } from '@angular/material/form-field'; 9 | import { MatMenuModule } from '@angular/material/menu'; 10 | import { MatIconModule } from '@angular/material/icon'; 11 | import { MatButtonModule } from '@angular/material/button'; 12 | import { MatInputModule } from '@angular/material/input'; 13 | import { 14 | OtelColExporterModule, 15 | CompositePropagatorModule, 16 | OtelWebTracerModule, 17 | OTEL_CONFIG } from 'projects/opentelemetry-interceptor/src/public-api'; 18 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 19 | import { ViewBackendComponent } from './view-backend/view-backend.component'; 20 | import { HighlightJsModule } from 'ngx-highlight-js'; 21 | import { AppRoutingModule } from './app-routing.module'; 22 | import { PostBackendComponent } from './post-backend/post-backend.component'; 23 | import { JsonpBackendComponent } from './jsonp-backend/jsonp-backend.component'; 24 | import { environment } from '../environments/environment'; 25 | import { OTEL_INSTRUMENTATION_PLUGINS } from '../../../opentelemetry-interceptor/src/lib/configuration/opentelemetry-config'; 26 | import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'; 27 | 28 | 29 | @NgModule({ 30 | declarations: [AppComponent, ViewBackendComponent, PostBackendComponent, JsonpBackendComponent], 31 | imports: [ 32 | BrowserModule, 33 | OtelWebTracerModule.forRoot( 34 | undefined, 35 | {provide: OTEL_CONFIG, useFactory: () => (environment.openTelemetryConfig)} 36 | ), 37 | OtelColExporterModule, 38 | CompositePropagatorModule, 39 | HttpClientModule, 40 | HttpClientJsonpModule, 41 | FormsModule, 42 | MatToolbarModule, 43 | MatCardModule, 44 | MatFormFieldModule, 45 | MatMenuModule, 46 | MatIconModule, 47 | MatButtonModule, 48 | MatInputModule, 49 | BrowserAnimationsModule, 50 | HighlightJsModule, 51 | AppRoutingModule, 52 | ], 53 | providers: [ 54 | {provide: OTEL_INSTRUMENTATION_PLUGINS, useValue: [new XMLHttpRequestInstrumentation()]} 55 | ], 56 | bootstrap: [AppComponent], 57 | }) 58 | export class AppModule { } 59 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/example.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { environment } from '../environments/environment'; 3 | import { forkJoin, Observable } from 'rxjs'; 4 | import { HttpClient } from '@angular/common/http'; 5 | import { map } from 'rxjs/operators'; 6 | import { Result } from './result'; 7 | 8 | @Injectable({ 9 | providedIn: 'root', 10 | }) 11 | export class ExampleService { 12 | private urlTestBackend: string = environment.urlTest; 13 | 14 | constructor(private readonly http: HttpClient) {} 15 | 16 | getApiBackend(): Observable { 17 | return this.http 18 | .get(`${this.urlTestBackend}/`, {}) 19 | .pipe(map((result: Result) => result)); 20 | } 21 | 22 | getApiParallelBackEnd(): Observable { 23 | return forkJoin({ 24 | result: this.getApiBackend(), 25 | result2: this.getApiBackend() 26 | }); 27 | } 28 | 29 | postApiBackend(result: Result) { 30 | return this.http 31 | .post(`${this.urlTestBackend}/`, result) 32 | .pipe(map((oneResult: Result) => oneResult)); 33 | } 34 | 35 | jsonpApiExample(): Observable { 36 | return this.http.jsonp(`${this.urlTestBackend}/jsonp/`, 'callback'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/jsonp-backend/jsonp-backend.component.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: white; 3 | } 4 | 5 | 6 | .opentelemery-config { 7 | margin: 0 16px; 8 | } 9 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/jsonp-backend/jsonp-backend.component.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | OpenTelemetry Tracing 5 | Example about this interceptor 6 | 7 | 8 |

    This is a call to the JsonP api

    9 |

    There's no Header because JSONP don't use...

    10 |

    result call : {{result?.result}}

    11 |
    12 |
    13 |
    14 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/jsonp-backend/jsonp-backend.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ExampleService } from '../example.service'; 3 | import { Result } from '../result'; 4 | 5 | @Component({ 6 | selector: 'app-jsonp-backend', 7 | templateUrl: './jsonp-backend.component.html', 8 | styleUrls: ['./jsonp-backend.component.css'], 9 | }) 10 | export class JsonpBackendComponent implements OnInit { 11 | result: Result; 12 | 13 | constructor(private exampleService: ExampleService) {} 14 | 15 | ngOnInit(): void { 16 | this.exampleService.jsonpApiExample().subscribe((data: Result) => { 17 | this.result = data; 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/post-backend/post-backend.component.css: -------------------------------------------------------------------------------- 1 | .opentelemery-config { 2 | margin: 0 16px; 3 | } 4 | 5 | .result { 6 | margin-top: 16px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/post-backend/post-backend.component.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | OpenTelemetry Tracing 5 | Example about this interceptor 6 | 7 | 8 |

    This is a form to post a value and retrieve it in trace

    9 |
    10 | 11 | Enter a Value 12 | 13 | 14 |
    15 | 16 | 17 |
    18 |
    19 |
    20 |

    result call : {{result?.result}}

    21 |
    22 |
    23 |
    24 |
    25 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/post-backend/post-backend.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Result } from '../result'; 3 | import { ExampleService } from '../example.service'; 4 | 5 | @Component({ 6 | selector: 'app-post-backend', 7 | templateUrl: './post-backend.component.html', 8 | styleUrls: ['./post-backend.component.css'], 9 | }) 10 | export class PostBackendComponent implements OnInit { 11 | public result: Result; 12 | 13 | constructor(private exampleService: ExampleService) {} 14 | 15 | ngOnInit(): void {} 16 | 17 | onSubmit(resultForm): void { 18 | const oneResult: Result = new Result(resultForm.avalue); 19 | this.exampleService 20 | .postApiBackend(oneResult) 21 | .subscribe((result) => (this.result = result)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/result.ts: -------------------------------------------------------------------------------- 1 | export class Result { 2 | constructor(public result: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/view-backend/view-backend.component.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: white; 3 | } 4 | 5 | 6 | .opentelemery-config { 7 | margin: 0 16px; 8 | } 9 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/view-backend/view-backend.component.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | OpenTelemetry Tracing 5 | Example about this interceptor 6 | 7 | 8 |

    This is a call to the backend api http://localhost:3000/api (with proxy conf)

    10 |

    You can see a trace in navigator console (and collector if you configure one)

    11 |

    with the environment configuration

    12 | 27 |

    with all the module in app.module.ts

    28 | 36 |

    You can see the B3 headers, W3CTraceContext header, Jaeger Propagator header and AWS X-Ray header added

    37 | 54 |

    result call : {{result?.result}}

    55 |
    56 |
    57 |
    58 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/app/view-backend/view-backend.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ExampleService } from '../example.service'; 3 | import { Result } from '../result'; 4 | 5 | @Component({ 6 | selector: 'app-view-backend', 7 | templateUrl: './view-backend.component.html', 8 | styleUrls: ['./view-backend.component.css'] 9 | }) 10 | export class ViewBackendComponent implements OnInit { 11 | 12 | result: Result; 13 | result2: Result; 14 | 15 | constructor(private exampleService: ExampleService) { } 16 | 17 | ngOnInit(): void { 18 | //this.exampleService.getApiBackend().subscribe(result => this.result = result); 19 | this.exampleService.getApiParallelBackEnd().subscribe(({result, result2}) => { 20 | this.result = result; 21 | this.result2 = result2; 22 | }); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/projects/instrumentation-example/src/assets/.gitkeep -------------------------------------------------------------------------------- /projects/instrumentation-example/src/backend-api.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | const PORT = process.env.PORT || 3000; 6 | const backendApp = express(); 7 | backendApp.use(express.json()); 8 | backendApp.use(express.urlencoded({ extended: false })); 9 | 10 | class Result { 11 | constructor(result) { 12 | this.result = result; 13 | } 14 | } 15 | 16 | // 17 | backendApp.get('/api', (req, res) => { 18 | const result = new Result("ok"); 19 | return res.status(200).send(result); 20 | }) 21 | 22 | backendApp.post('/api', (req, res) => { 23 | const result = new Result(req.body.result); 24 | return res.status(201).send(result); 25 | }) 26 | 27 | backendApp.get('/api/jsonp', (req, res) => { 28 | const result = new Result("ok"); 29 | return res.jsonp(result); 30 | }) 31 | 32 | backendApp.get('/api/config', (req,res) => { 33 | return res.status(200).send({ 34 | commonConfig: { 35 | console: true, // Display trace on console 36 | production: true, // Send Trace with BatchSpanProcessor (true) or SimpleSpanProcessor (false) 37 | serviceName: 'instrumentation-example', // Service name send in trace 38 | resourceAttributes: { // extra resource attributes like service.namespace 39 | 'service.namespace': 'namespace' 40 | }, 41 | probabilitySampler: '0.75', // 75% sampling 42 | logLevel: 99 //ALL Log, DiagLogLevel is an Enum from @opentelemetry/api 43 | }, 44 | otelcolConfig: { 45 | url: 'http://localhost:4318/v1/traces', // URL of opentelemetry collector 46 | } 47 | }); 48 | }) 49 | 50 | backendApp.listen(PORT, () => 51 | console.log(`Backend App for example-app listening on port ${PORT}!`), 52 | ); 53 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | import { 2 | OpenTelemetryConfig 3 | } from '../../../opentelemetry-interceptor/src/public-api'; 4 | 5 | interface IEnvironment { 6 | production: boolean; 7 | urlTest: string; 8 | urlOtelConfig: string; 9 | openTelemetryConfig?: OpenTelemetryConfig; 10 | } 11 | 12 | // Example to configure the angular-interceptor library 13 | export const environment: IEnvironment = { 14 | production: false, 15 | urlTest: 'http://localhost:4200/api', 16 | urlOtelConfig: 'http://localhost:4200/api/config', 17 | }; 18 | 19 | /* 20 | * For easier debugging in development mode, you can import the following file 21 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 22 | * 23 | * This import should be commented out in production mode because it will have a negative impact 24 | * on performance if an error is thrown. 25 | */ 26 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 27 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/projects/instrumentation-example/src/favicon.ico -------------------------------------------------------------------------------- /projects/instrumentation-example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | InstrumentationExample 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | (async () => { 11 | const response = await fetch(environment.urlOtelConfig); 12 | const config = await response.json(); 13 | 14 | environment.openTelemetryConfig = config; 15 | 16 | platformBrowserDynamic().bootstrapModule(AppModule) 17 | .catch(err => console.error(err)); 18 | })(); 19 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | 51 | /*************************************************************************************************** 52 | * APPLICATION IMPORTS 53 | */ 54 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, 4 | body { 5 | height: 100%; 6 | } 7 | body { 8 | margin: 0; 9 | font-family: Roboto, "Helvetica Neue", sans-serif; 10 | } 11 | -------------------------------------------------------------------------------- /projects/instrumentation-example/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting(), { 21 | teardown: { destroyAfterEach: false } 22 | } 23 | ); 24 | // Then we find all the tests. 25 | const context = require.context('./', true, /\.spec\.ts$/); 26 | // And load the modules. 27 | context.keys().map(context); 28 | -------------------------------------------------------------------------------- /projects/instrumentation-example/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/app", 5 | "types": [] 6 | }, 7 | "angularCompilerOptions": { 8 | "enableIvy": true, 9 | }, 10 | "files": [ 11 | "src/main.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/instrumentation-example/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /projects/interceptor-example/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /projects/interceptor-example/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc.json", 3 | "ignorePatterns": [ 4 | "!**/*" 5 | ], 6 | "overrides": [ 7 | { 8 | "files": [ 9 | "*.ts" 10 | ], 11 | "parserOptions": { 12 | "project": [ 13 | "projects/interceptor-example/tsconfig.app.json", 14 | "projects/interceptor-example/tsconfig.spec.json" 15 | ], 16 | "createDefaultProgram": true 17 | }, 18 | "rules": { 19 | "@angular-eslint/component-selector": [ 20 | "error", 21 | { 22 | "type": "element", 23 | "prefix": "app", 24 | "style": "kebab-case" 25 | } 26 | ], 27 | "@angular-eslint/directive-selector": [ 28 | "error", 29 | { 30 | "type": "attribute", 31 | "prefix": "app", 32 | "style": "camelCase" 33 | } 34 | ] 35 | } 36 | }, 37 | { 38 | "files": [ 39 | "*.html" 40 | ], 41 | "rules": {} 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /projects/interceptor-example/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/api/*": { 3 | "target": "http://localhost:3000/", 4 | "secure": false, 5 | "logLevel": "debug" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { ViewBackendComponent } from './view-backend/view-backend.component'; 4 | import { PostBackendComponent } from './post-backend/post-backend.component'; 5 | import { JsonpBackendComponent } from './jsonp-backend/jsonp-backend.component'; 6 | 7 | const routes: Routes = [ 8 | { path: 'view', component: ViewBackendComponent }, 9 | { path: 'post', component: PostBackendComponent }, 10 | { path: 'jsonp', component: JsonpBackendComponent }, 11 | { path: '', redirectTo: '/view', pathMatch: 'full' }, 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })], 16 | exports: [RouterModule], 17 | }) 18 | export class AppRoutingModule {} 19 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | .example-icon { 2 | padding: 0 14px; 3 | } 4 | 5 | .example-spacer { 6 | flex: 1 1 auto; 7 | } 8 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | {{title}} 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'Interceptor-example'; 10 | } 11 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { AppComponent } from './app.component'; 5 | import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http'; 6 | import { MatToolbarModule } from '@angular/material/toolbar'; 7 | import { MatCardModule } from '@angular/material/card'; 8 | import { MatFormFieldModule } from '@angular/material/form-field'; 9 | import { MatMenuModule } from '@angular/material/menu'; 10 | import { MatIconModule } from '@angular/material/icon'; 11 | import { MatButtonModule } from '@angular/material/button'; 12 | import { MatInputModule } from '@angular/material/input'; 13 | // eslint-disable-next-line max-len 14 | import { OpenTelemetryInterceptorModule, OTEL_LOGGER, OtelColExporterModule, CompositePropagatorModule } from 'projects/opentelemetry-interceptor/src/public-api'; 15 | import { environment } from '../environments/environment'; 16 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 17 | import { ViewBackendComponent } from './view-backend/view-backend.component'; 18 | import { HighlightJsModule } from 'ngx-highlight-js'; 19 | import { AppRoutingModule } from './app-routing.module'; 20 | import { PostBackendComponent } from './post-backend/post-backend.component'; 21 | import { JsonpBackendComponent } from './jsonp-backend/jsonp-backend.component'; 22 | import { LoggerModule, NGXLogger } from 'ngx-logger'; 23 | import { OTEL_CUSTOM_SPAN } from '../../../opentelemetry-interceptor/src/lib/configuration/opentelemetry-config'; 24 | import { CustomSpanImpl } from './custom-span-impl'; 25 | 26 | @NgModule({ 27 | declarations: [AppComponent, ViewBackendComponent, PostBackendComponent, JsonpBackendComponent], 28 | imports: [ 29 | BrowserModule, 30 | // Insert module OpenTelemetryInterceptorModule with configuration, HttpClientModule is used for interceptor 31 | OpenTelemetryInterceptorModule.forRoot(environment.openTelemetryConfig), 32 | OtelColExporterModule, 33 | CompositePropagatorModule, 34 | HttpClientModule, 35 | HttpClientJsonpModule, 36 | FormsModule, 37 | MatToolbarModule, 38 | MatCardModule, 39 | MatFormFieldModule, 40 | MatMenuModule, 41 | MatIconModule, 42 | MatButtonModule, 43 | MatInputModule, 44 | BrowserAnimationsModule, 45 | HighlightJsModule, 46 | AppRoutingModule, 47 | // Insert a logger (NGXLogger for this example...) 48 | LoggerModule.forRoot(environment.loggerConfig), 49 | ], 50 | providers: [ 51 | // Provide token OTEL_LOGGER with the NGXLogger 52 | { provide: OTEL_LOGGER, useExisting: NGXLogger }, 53 | { provide: OTEL_CUSTOM_SPAN, useClass: CustomSpanImpl} 54 | ], 55 | bootstrap: [AppComponent], 56 | }) 57 | export class AppModule { } 58 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/custom-span-impl.ts: -------------------------------------------------------------------------------- 1 | import { HttpRequest, HttpResponse, HttpErrorResponse } from '@angular/common/http'; 2 | import { Span } from '@opentelemetry/api'; 3 | import { CustomSpan } from 'projects/opentelemetry-interceptor/src/public-api'; 4 | 5 | export class CustomSpanImpl implements CustomSpan { 6 | private myKey = 'mycustom.key'; 7 | add(span: Span, request: HttpRequest, response: HttpResponse | HttpErrorResponse): Span { 8 | span.setAttribute(this.myKey , request.params + ';' + response.status); 9 | return span; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/example.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { environment } from '../environments/environment'; 3 | import { forkJoin, Observable } from 'rxjs'; 4 | import { HttpClient } from '@angular/common/http'; 5 | import { map } from 'rxjs/operators'; 6 | import { Result } from './result'; 7 | 8 | @Injectable({ 9 | providedIn: 'root', 10 | }) 11 | export class ExampleService { 12 | private urlTestBackend: string = environment.urlTest; 13 | 14 | constructor(private readonly http: HttpClient) {} 15 | 16 | getApiBackend(): Observable { 17 | return this.http 18 | .get(`${this.urlTestBackend}/`, {}) 19 | .pipe(map((result: Result) => result)); 20 | } 21 | 22 | getApiParallelBackEnd(): Observable { 23 | return forkJoin({ 24 | result: this.getApiBackend(), 25 | result2: this.getApiBackend() 26 | }); 27 | } 28 | 29 | postApiBackend(result: Result) { 30 | return this.http 31 | .post(`${this.urlTestBackend}/`, result) 32 | .pipe(map((oneResult: Result) => oneResult)); 33 | } 34 | 35 | jsonpApiExample(): Observable { 36 | return this.http.jsonp(`${this.urlTestBackend}/jsonp/`, 'callback'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/jsonp-backend/jsonp-backend.component.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: white; 3 | } 4 | 5 | 6 | .opentelemery-config { 7 | margin: 0 16px; 8 | } 9 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/jsonp-backend/jsonp-backend.component.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | OpenTelemetry Tracing 5 | Example about this interceptor 6 | 7 | 8 |

    This is a call to the JsonP api

    9 |

    There's no Header because JSONP don't use...

    10 |

    result call : {{result?.result}}

    11 |
    12 |
    13 |
    14 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/jsonp-backend/jsonp-backend.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ExampleService } from '../example.service'; 3 | import { Result } from '../result'; 4 | 5 | @Component({ 6 | selector: 'app-jsonp-backend', 7 | templateUrl: './jsonp-backend.component.html', 8 | styleUrls: ['./jsonp-backend.component.css'], 9 | }) 10 | export class JsonpBackendComponent implements OnInit { 11 | result: Result; 12 | 13 | constructor(private exampleService: ExampleService) {} 14 | 15 | ngOnInit(): void { 16 | this.exampleService.jsonpApiExample().subscribe((data: Result) => { 17 | this.result = data; 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/post-backend/post-backend.component.css: -------------------------------------------------------------------------------- 1 | .opentelemery-config { 2 | margin: 0 16px; 3 | } 4 | 5 | .result { 6 | margin-top: 16px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/post-backend/post-backend.component.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | OpenTelemetry Tracing 5 | Example about this interceptor 6 | 7 | 8 |

    This is a form to post a value and retrieve it in trace

    9 |
    10 | 11 | Enter a Value 12 | 13 | 14 |
    15 | 16 | 17 |
    18 |
    19 |
    20 |

    result call : {{result?.result}}

    21 |
    22 |
    23 |
    24 |
    25 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/post-backend/post-backend.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Result } from '../result'; 3 | import { ExampleService } from '../example.service'; 4 | 5 | @Component({ 6 | selector: 'app-post-backend', 7 | templateUrl: './post-backend.component.html', 8 | styleUrls: ['./post-backend.component.css'], 9 | }) 10 | export class PostBackendComponent implements OnInit { 11 | public result: Result; 12 | 13 | constructor(private exampleService: ExampleService) {} 14 | 15 | ngOnInit(): void {} 16 | 17 | onSubmit(resultForm): void { 18 | const oneResult: Result = new Result(resultForm.avalue); 19 | this.exampleService 20 | .postApiBackend(oneResult) 21 | .subscribe((result) => (this.result = result)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/result.ts: -------------------------------------------------------------------------------- 1 | export class Result { 2 | constructor(public result: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/view-backend/view-backend.component.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: white; 3 | } 4 | 5 | 6 | .opentelemery-config { 7 | margin: 0 16px; 8 | } 9 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/view-backend/view-backend.component.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | OpenTelemetry Tracing 5 | Example about this interceptor 6 | 7 | 8 |

    This is a call to the backend api http://localhost:3000/api (with proxy conf)

    10 |

    You can see a trace in navigator console (and collector if you configure one)

    11 |

    with the environment configuration

    12 | 27 |

    with all the module in app.module.ts

    28 | 36 |

    You can see the B3 headers, W3CTraceContext header, Jaeger Propagator header And AWS X-Ray header added

    37 | 54 |

    result call : {{result?.result}}

    55 |

    result2 call : {{result2?.result}}

    56 |
    57 |
    58 |
    59 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/app/view-backend/view-backend.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { NGXLogger } from 'ngx-logger'; 3 | import { ExampleService } from '../example.service'; 4 | import { Result } from '../result'; 5 | 6 | @Component({ 7 | selector: 'app-view-backend', 8 | templateUrl: './view-backend.component.html', 9 | styleUrls: ['./view-backend.component.css'] 10 | }) 11 | export class ViewBackendComponent implements OnInit { 12 | 13 | result: Result; 14 | result2: Result; 15 | 16 | constructor(private exampleService: ExampleService, private logger: NGXLogger) { } 17 | 18 | ngOnInit(): void { 19 | this.logger.debug('View Backend Component'); 20 | //this.exampleService.getApiBackend().subscribe(result => this.result = result); 21 | this.exampleService.getApiParallelBackEnd().subscribe(({result, result2}) => { 22 | this.result = result; 23 | this.result2 = result2; 24 | }); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/projects/interceptor-example/src/assets/.gitkeep -------------------------------------------------------------------------------- /projects/interceptor-example/src/backend-api.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | const PORT = process.env.PORT || 3000; 6 | const backendApp = express(); 7 | backendApp.use(express.json()); 8 | backendApp.use(express.urlencoded({ extended: false })); 9 | 10 | 11 | class Result { 12 | constructor(result) { 13 | this.result = result; 14 | } 15 | } 16 | 17 | // 18 | backendApp.get('/api', (req, res) => { 19 | return res.status(200).send(new Result("ok")); 20 | }) 21 | 22 | backendApp.post('/api', (req, res) => { 23 | return res.status(201).send(new Result(req.body.result)); 24 | }) 25 | 26 | backendApp.get('/api/jsonp', (req, res) => { 27 | return res.jsonp(new Result("ok")); 28 | }) 29 | 30 | backendApp.listen(PORT, () => 31 | console.log(`Backend App for example-app listening on port ${PORT}!`), 32 | ); 33 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | import { INGXLoggerConfig, NgxLoggerLevel } from 'ngx-logger'; 2 | import { DiagLogLevel } from '@opentelemetry/api'; 3 | import { ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'; 4 | import { OpenTelemetryConfig } from '../../../opentelemetry-interceptor/src/public-api'; 5 | 6 | interface IEnvironment { 7 | production: boolean; 8 | urlTest: string; 9 | openTelemetryConfig: OpenTelemetryConfig; 10 | loggerConfig: INGXLoggerConfig; 11 | } 12 | 13 | // Example to configure the angular-interceptor library 14 | export const environment: IEnvironment = { 15 | production: false, 16 | urlTest: 'http://localhost:4200/api', 17 | openTelemetryConfig: { 18 | commonConfig: { 19 | console: true, // Display trace on console 20 | production: true, // Send Trace with BatchSpanProcessor (true) or SimpleSpanProcessor (false) 21 | serviceName: 'interceptor-example', // Service name send in trace 22 | resourceAttributes: { 23 | // extra resource attributes like service.namespace 24 | [ATTR_SERVICE_VERSION]: 'version 1.0.0', // Service version 25 | }, 26 | logBody: true, // true add body in a log, nothing otherwise 27 | probabilitySampler: '1', // 75% sampling 28 | logLevel: DiagLogLevel.ALL, //ALL Log, DiagLogLevel is an Enum from @opentelemetry/api 29 | }, 30 | otelcolConfig: { 31 | url: 'http://127.0.0.1:4318/v1/traces', // URL of opentelemetry collector 32 | timeoutMillis: '10000', 33 | }, 34 | }, 35 | loggerConfig: { 36 | level: NgxLoggerLevel.DEBUG, 37 | disableConsoleLogging: false, 38 | }, 39 | }; 40 | 41 | /* 42 | * For easier debugging in development mode, you can import the following file 43 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 44 | * 45 | * This import should be commented out in production mode because it will have a negative impact 46 | * on performance if an error is thrown. 47 | */ 48 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 49 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jufab/opentelemetry-angular-interceptor/ab46ca4e14255acfa612a611e4fd55be7f830e29/projects/interceptor-example/src/favicon.ico -------------------------------------------------------------------------------- /projects/interceptor-example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | InterceptorExample 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | 51 | /*************************************************************************************************** 52 | * APPLICATION IMPORTS 53 | */ 54 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, 4 | body { 5 | height: 100%; 6 | } 7 | body { 8 | margin: 0; 9 | font-family: Roboto, "Helvetica Neue", sans-serif; 10 | } 11 | -------------------------------------------------------------------------------- /projects/interceptor-example/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | // Then we find all the tests. 23 | const context = require.context('./', true, /\.spec\.ts$/); 24 | // And load the modules. 25 | context.keys().map(context); 26 | -------------------------------------------------------------------------------- /projects/interceptor-example/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/app", 5 | "types": [] 6 | }, 7 | "angularCompilerOptions": { 8 | "enableIvy": true, 9 | }, 10 | "files": [ 11 | "src/main.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/interceptor-example/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc.json", 3 | "ignorePatterns": [ 4 | "!**/*" 5 | ], 6 | "overrides": [ 7 | { 8 | "files": [ 9 | "*.ts" 10 | ], 11 | "parserOptions": { 12 | "project": [ 13 | "projects/opentelemetry-interceptor/tsconfig.lib.json", 14 | "projects/opentelemetry-interceptor/tsconfig.spec.json" 15 | ], 16 | "createDefaultProgram": true 17 | }, 18 | "rules": { 19 | "@angular-eslint/component-selector": [ 20 | "error", 21 | { 22 | "type": "element", 23 | "prefix": "lib", 24 | "style": "kebab-case" 25 | } 26 | ], 27 | "@angular-eslint/directive-selector": [ 28 | "error", 29 | { 30 | "type": "attribute", 31 | "prefix": "lib", 32 | "style": "camelCase" 33 | } 34 | ] 35 | } 36 | }, 37 | { 38 | "files": [ 39 | "*.html" 40 | ], 41 | "rules": {} 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/__mocks__/data/config.mock.ts: -------------------------------------------------------------------------------- 1 | import { 2 | OpenTelemetryConfig, 3 | } from '../../src/lib/configuration/opentelemetry-config'; 4 | 5 | 6 | /** 7 | * @ignore 8 | */ 9 | export const otelcolExporterConfig: OpenTelemetryConfig = { 10 | commonConfig: { 11 | serviceName: 'test', 12 | logBody: true 13 | }, 14 | otelcolConfig: { 15 | url: 'http://localhost', 16 | }, 17 | }; 18 | 19 | /** 20 | * @ignore 21 | */ 22 | export const otelcolExporterProductionConfig: OpenTelemetryConfig = { 23 | commonConfig: { 24 | serviceName: 'test', 25 | production: true, 26 | }, 27 | otelcolConfig: { 28 | url: 'http://localhost', 29 | }, 30 | }; 31 | 32 | /** 33 | * @ignore 34 | */ 35 | export const otelcolExporterProductionAndBatchSpanProcessorConfig: OpenTelemetryConfig = { 36 | commonConfig: { 37 | serviceName: 'test', 38 | production: true, 39 | }, 40 | batchSpanProcessorConfig: { 41 | maxExportBatchSize: '512', 42 | scheduledDelayMillis: '5000', 43 | exportTimeoutMillis: '30000', 44 | maxQueueSize: '2048', 45 | }, 46 | otelcolConfig: { 47 | url: 'http://localhost', 48 | }, 49 | }; 50 | 51 | /** 52 | * @ignore 53 | */ 54 | export const otelcolExporterWithoutUrlAndB3Config: OpenTelemetryConfig = { 55 | commonConfig: { 56 | serviceName: 'test', 57 | }, 58 | otelcolConfig: { 59 | url: 'http://localhost:4318/v1/traces', 60 | } 61 | }; 62 | 63 | /** 64 | * @ignore 65 | */ 66 | export const otelcolExporterWithProbabilitySamplerAndCompositeConfig: OpenTelemetryConfig = { 67 | commonConfig: { 68 | serviceName: 'test', 69 | console: true, 70 | probabilitySampler: '0.7', 71 | resourceAttributes: { 72 | test: 'test' 73 | } 74 | }, 75 | otelcolConfig: { 76 | url: 'http://localhost', 77 | concurrencyLimit: '10', 78 | }, 79 | }; 80 | 81 | /** 82 | * @ignore 83 | */ 84 | export const otelcolExporterWithProbabilitySamplerAtZeroAndCompositeConfig: OpenTelemetryConfig = { 85 | commonConfig: { 86 | serviceName: 'test', 87 | console: true, 88 | probabilitySampler: '0', 89 | }, 90 | otelcolConfig: { 91 | url: 'http://localhost', 92 | }, 93 | }; 94 | 95 | /** 96 | * @ignore 97 | */ 98 | export const otelcolExporterWithProbabilitySamplerAtTwoConfig: OpenTelemetryConfig = { 99 | commonConfig: { 100 | serviceName: 'test', 101 | console: true, 102 | probabilitySampler: '2', 103 | }, 104 | otelcolConfig: { 105 | url: 'http://localhost', 106 | }, 107 | }; 108 | 109 | 110 | /** 111 | * @ignore 112 | */ 113 | export const jaegerPropagatorConfig: OpenTelemetryConfig = { 114 | commonConfig: { 115 | serviceName: 'test', 116 | }, 117 | jaegerPropagatorConfig: { 118 | customHeader: 'custom-header-trace', 119 | }, 120 | }; 121 | 122 | /** 123 | * @ignore 124 | */ 125 | export const zipkinConfig: OpenTelemetryConfig = { 126 | commonConfig: { 127 | production: false, 128 | serviceName: 'test', 129 | }, 130 | zipkinConfig: { 131 | url: 'http://localhost', 132 | headers: { test: 'test' }, 133 | } 134 | }; 135 | 136 | /** 137 | * @ignore 138 | */ 139 | export const zipkinOtherConfig: OpenTelemetryConfig = { 140 | commonConfig: { 141 | production: false, 142 | serviceName: 'test', 143 | } 144 | }; 145 | 146 | /** 147 | * @ignore 148 | */ 149 | export const jaegerPropagatorWithoutCustomHeaderConfig: OpenTelemetryConfig = { 150 | commonConfig: { 151 | serviceName: 'test', 152 | }, 153 | }; 154 | 155 | 156 | /** 157 | * @ignore 158 | */ 159 | export const b3PropagatorMultiConfig: OpenTelemetryConfig = { 160 | commonConfig: { 161 | serviceName: 'test', 162 | }, 163 | otelcolConfig: { 164 | url: 'http://localhost', 165 | } 166 | }; 167 | 168 | /** 169 | * @ignore 170 | */ 171 | export const b3PropagatorSingleConfig: OpenTelemetryConfig = { 172 | commonConfig: { 173 | serviceName: 'test', 174 | }, 175 | otelcolConfig: { 176 | url: 'http://localhost', 177 | }, 178 | b3PropagatorConfig: { 179 | multiHeader: '0', 180 | } 181 | }; 182 | 183 | /** 184 | * @ignore 185 | */ 186 | export const instrumentationConsoleOtelConfig: OpenTelemetryConfig = { 187 | commonConfig: { 188 | serviceName: 'test', 189 | console: true, 190 | production: false, 191 | probabilitySampler: '2', 192 | }, 193 | otelcolConfig: { 194 | url: 'http://localhost', 195 | } 196 | }; 197 | 198 | /** 199 | * @ignore 200 | */ 201 | export const instrumentationConsoleOtelConfigSamplerOff: OpenTelemetryConfig = { 202 | commonConfig: { 203 | serviceName: 'test', 204 | console: true, 205 | production: false, 206 | probabilitySampler: undefined, 207 | }, 208 | otelcolConfig: { 209 | url: 'http://localhost', 210 | } 211 | }; 212 | 213 | /** 214 | * @ignore 215 | */ 216 | export const instrumentationProductionOtelConfig: OpenTelemetryConfig = { 217 | commonConfig: { 218 | serviceName: 'test', 219 | console: false, 220 | production: true, 221 | probabilitySampler: '0.7', 222 | resourceAttributes: { 223 | // eslint-disable-next-line @typescript-eslint/naming-convention 224 | 'service.namespace' : 'test' 225 | } 226 | }, 227 | otelcolConfig: { 228 | url: 'http://localhost', 229 | concurrencyLimit: '10', 230 | } 231 | }; 232 | 233 | /** 234 | * @ignore 235 | */ 236 | export const otelTraceparentIgnoreUrlsConfig: OpenTelemetryConfig = { 237 | commonConfig: { 238 | serviceName: 'test', 239 | logBody: true 240 | }, 241 | ignoreUrls: { 242 | urls: ['http://url.test.com'] 243 | } 244 | }; 245 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/opentelemetry-interceptor", 4 | "assets": [ 5 | "ngcc.config.js" 6 | ], 7 | "lib": { 8 | "entryFile": "src/public-api.ts" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/ngcc.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ignorableDeepImportMatchers: [/build\/.*/i] 3 | }; 4 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jufab/opentelemetry-angular-interceptor", 3 | "version": "1.9.0-1", 4 | "repository": "jufab/opentelemetry-angular-interceptor", 5 | "author": { 6 | "name": "Julien Fabre" 7 | }, 8 | "engines": { 9 | "node": ">=14.15.0" 10 | }, 11 | "keywords": [ 12 | "opentelemetry", 13 | "tracing", 14 | "angular" 15 | ], 16 | "license": "Apache-2.0", 17 | "peerDependencies": { 18 | "@angular/common": ">=14.0.0", 19 | "@angular/core": ">=14.0.0", 20 | "@opentelemetry/api": "1.9.0", 21 | "@opentelemetry/context-zone-peer-dep": "1.29.0", 22 | "@opentelemetry/exporter-trace-otlp-http": "0.56.0", 23 | "@opentelemetry/exporter-zipkin": "1.29.0", 24 | "@opentelemetry/instrumentation": "0.56.0", 25 | "@opentelemetry/propagator-aws-xray": "1.26.0", 26 | "@opentelemetry/propagator-b3": "1.29.0", 27 | "@opentelemetry/propagator-jaeger": "1.29.0", 28 | "@opentelemetry/sdk-trace-web": "1.29.0" 29 | }, 30 | "dependencies": { 31 | "tslib": "^2.6.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/setupJest.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | import { TextEncoder } from 'util'; 3 | /** 4 | * @ignore 5 | */ 6 | const mock = () => { 7 | let storage = {}; 8 | return { 9 | getItem: (key: any) => (key in storage ? storage[key] : null), 10 | setItem: (key: any, value: any) => (storage[key] = value || ''), 11 | removeItem: (key: any) => delete storage[key], 12 | clear: () => (storage = {}) 13 | }; 14 | }; 15 | 16 | Object.defineProperty(window, 'localStorage', {value: mock()}); 17 | Object.defineProperty(window, 'sessionStorage', {value: mock()}); 18 | Object.defineProperty(window, 'getComputedStyle', { 19 | value: () => ['-webkit-appearance'] 20 | }); 21 | Object.defineProperty(window, 'TextEncoder', { 22 | writable: true, 23 | value: TextEncoder 24 | }); 25 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/configuration/opentelemetry-config.ts: -------------------------------------------------------------------------------- 1 | import { ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, InjectionToken, ValueProvider } from '@angular/core'; 2 | import { AttributeValue, DiagLogger, DiagLogLevel } from '@opentelemetry/api'; 3 | import { Instrumentation } from '@opentelemetry/instrumentation'; 4 | import { CustomSpan } from '../interceptor/custom-span.interface'; 5 | 6 | /** 7 | * Common configuration 8 | */ 9 | export interface CommonCollectorConfig { 10 | /** serviceName : Name of service in trace */ 11 | serviceName: string; 12 | /** resourceAttributes: Extra resource attribute like service.namespace ...*/ 13 | resourceAttributes?: Partial>; 14 | /** console : boolean to trace in console */ 15 | console?: boolean; 16 | /** production : boolean to use a BatchSpanExporter(async) or SimpleSpanExporter(sync) */ 17 | production?: boolean; 18 | /** probabilitySampler */ 19 | probabilitySampler?: string; 20 | /** log or not body response in span */ 21 | logBody?: boolean; 22 | /** log level for opentelemetry */ 23 | logLevel?: DiagLogLevel; 24 | } 25 | 26 | /** 27 | * BatchSpanExporter Configuration 28 | */ 29 | export interface BatchSpanProcessorConfig { 30 | /** The maximum queue size. After the size is reached spans are dropped. */ 31 | maxQueueSize?: string; 32 | /** The maximum batch size of every export. It must be smaller or equal to maxQueueSize. */ 33 | maxExportBatchSize?: string; 34 | /** The interval between two consecutive exports */ 35 | scheduledDelayMillis?: string; 36 | /** How long the export can run before it is cancelled */ 37 | exportTimeoutMillis?: string; 38 | } 39 | 40 | /** 41 | * OpenTelemetry Collector configuration 42 | */ 43 | export interface OtelCollectorConfig { 44 | /** 45 | * An url (Default value: http://localhost:4318/v1/trace) 46 | */ 47 | url?: string; 48 | /** 49 | * custom headers 50 | */ 51 | headers?: Record; 52 | /** 53 | * An optional limit on pending requests 54 | */ 55 | concurrencyLimit?: string; 56 | /** 57 | * Maximum time the OTLP exporter will wait for each batch export. 58 | * The default value is 10000ms. 59 | * */ 60 | timeoutMillis?: string; 61 | } 62 | 63 | /** 64 | * Configuration for Zipkin 65 | */ 66 | export interface ZipkinCollectorConfig { 67 | /** 68 | * An url (Default value: http://localhost:9411/api/v2/spans) 69 | */ 70 | url?: string; 71 | /** 72 | * custom headers 73 | */ 74 | headers?: { 75 | [key: string]: string; 76 | }; 77 | } 78 | 79 | /** 80 | * Configuration for JaegerPropagatorConfig 81 | */ 82 | export interface JaegerPropagatorConfig { 83 | /** 84 | * A custom Header for the propagator 85 | */ 86 | customHeader?: string; 87 | } 88 | 89 | /** 90 | * Configuration for B3PropagatorConfig 91 | */ 92 | export interface B3PropagatorConfig { 93 | /** 94 | * Single or Multi Header for b3propagator (default: multi) 95 | * Value : 'O' (single), '1' (multi) 96 | */ 97 | multiHeader?: string; 98 | } 99 | 100 | /** 101 | * Configuration for IgnoreUrlsConfig 102 | */ 103 | export interface IgnoreUrlsConfig { 104 | /** 105 | * URLs that partially match any regex in ignoreUrls will not be traced. 106 | * In addition, URLs that are _exact matches_ of strings in ignoreUrls will 107 | * also not be traced. 108 | */ 109 | urls?: Array; 110 | } 111 | 112 | /** 113 | * OpenTelemetryConfig 114 | */ 115 | export interface OpenTelemetryConfig { 116 | /** commonConfig */ 117 | commonConfig: CommonCollectorConfig; 118 | /** batchSpanProcessorConfig */ 119 | batchSpanProcessorConfig?: BatchSpanProcessorConfig; 120 | /** otelcolConfig */ 121 | otelcolConfig?: OtelCollectorConfig; 122 | /** zipkinConfig */ 123 | zipkinConfig?: ZipkinCollectorConfig; 124 | /** jaegerPropagatorConfig */ 125 | jaegerPropagatorConfig?: JaegerPropagatorConfig; 126 | /** b3PropagatorConfig */ 127 | b3PropagatorConfig?: B3PropagatorConfig; 128 | /** ignoreUrls */ 129 | ignoreUrls?: IgnoreUrlsConfig; 130 | } 131 | 132 | /** OTEL_CONFIG : Config injection */ 133 | export const OTEL_CONFIG = new InjectionToken('opentelemetry.config'); 134 | 135 | /** Logger : injection for a logger compatible */ 136 | export const OTEL_LOGGER = new InjectionToken('otelcol.logger'); 137 | 138 | /** custom span */ 139 | export const OTEL_CUSTOM_SPAN = new InjectionToken('otelcol.custom-span'); 140 | 141 | export const OTEL_INSTRUMENTATION_PLUGINS = new InjectionToken('otelcol.instrumentation.plugins'); 142 | 143 | export const defineConfigProvider = ( 144 | config: OpenTelemetryConfig | null | undefined, 145 | configProvider: ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider 146 | ): ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider => { 147 | if (config) { 148 | configProvider = { provide: OTEL_CONFIG, useValue: config }; 149 | } else { 150 | if (configProvider) { 151 | if (configProvider.provide !== OTEL_CONFIG) { 152 | throw new Error(`Configuration error. token must be : ${OTEL_CONFIG} , your token value is : ${configProvider.provide}`); 153 | } 154 | } else { 155 | throw new Error(`Configuration error. you must specify a configuration in config or configProvider`); 156 | } 157 | } 158 | return configProvider; 159 | }; 160 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/interceptor/custom-span.interface.ts: -------------------------------------------------------------------------------- 1 | import { HttpErrorResponse, HttpRequest, HttpResponse } from '@angular/common/http'; 2 | import { Span } from '@opentelemetry/api'; 3 | 4 | /** 5 | * Interface Injected in HttpInterceptor to add attributes in a Span. 6 | * Implements this interface 7 | */ 8 | export interface CustomSpan { 9 | /** 10 | * To add Attributes in a Span during interception. 11 | * 12 | * @param span Span 13 | * @param request an HttpRequest 14 | * @param response an HttpResponse 15 | */ 16 | add(span: Span, request: HttpRequest, response: HttpResponse | HttpErrorResponse): Span; 17 | } 18 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/opentelemetry-interceptor.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | import { otelcolExporterConfig } from '../../__mocks__/data/config.mock'; 4 | import { OTEL_CONFIG, OpenTelemetryInterceptorModule } from '../public-api'; 5 | 6 | describe('OpenTelemetryInterceptorModule', () => { 7 | let openTelemetryInterceptorModule: OpenTelemetryInterceptorModule; 8 | 9 | it('should be created', () => { 10 | TestBed.configureTestingModule({ 11 | imports: [ 12 | OpenTelemetryInterceptorModule.forRoot(otelcolExporterConfig), 13 | ] 14 | }); 15 | openTelemetryInterceptorModule = TestBed.inject(OpenTelemetryInterceptorModule); 16 | expect(openTelemetryInterceptorModule).toBeTruthy(); 17 | const config = TestBed.inject(OTEL_CONFIG); 18 | expect(config).not.toBeUndefined(); 19 | }); 20 | it('should be created with configProvider', () => { 21 | TestBed.configureTestingModule({ 22 | imports: [ 23 | OpenTelemetryInterceptorModule.forRoot(null,{provide: OTEL_CONFIG, useValue: otelcolExporterConfig}), 24 | ] 25 | }); 26 | openTelemetryInterceptorModule = TestBed.inject(OpenTelemetryInterceptorModule); 27 | expect(openTelemetryInterceptorModule).toBeTruthy(); 28 | const config = TestBed.inject(OTEL_CONFIG); 29 | expect(config).not.toBeUndefined(); 30 | }); 31 | it('should return error without config', () => { 32 | expect(() => { 33 | TestBed.configureTestingModule({ 34 | imports: [OpenTelemetryInterceptorModule.forRoot(null,null)] 35 | }); 36 | }).toThrow('Configuration error. you must specify a configuration in config or configProvider'); 37 | }); 38 | it('should return error with wrong injection', () => { 39 | expect(() => { 40 | TestBed.configureTestingModule({ 41 | imports: [OpenTelemetryInterceptorModule.forRoot(null,{provide: new InjectionToken('date'), useValue: new Date()})] 42 | }); 43 | }).toThrow('Configuration error. token must be : InjectionToken opentelemetry.config , your token value is : InjectionToken date'); 44 | }); 45 | it('should return error without root', () => { 46 | expect(() => { 47 | new OpenTelemetryInterceptorModule({}); 48 | }).toThrow('OpentelemetryInterceptorModule is already loaded. Import it in the AppModule only'); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/opentelemetry-interceptor.module.ts: -------------------------------------------------------------------------------- 1 | import { 2 | NgModule, 3 | ModuleWithProviders, 4 | Optional, 5 | SkipSelf, 6 | ValueProvider, 7 | ClassProvider, 8 | ConstructorProvider, 9 | ExistingProvider, 10 | FactoryProvider, 11 | } from '@angular/core'; 12 | import { 13 | defineConfigProvider, 14 | OpenTelemetryConfig, 15 | } from './configuration/opentelemetry-config'; 16 | import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; 17 | import { OpenTelemetryHttpInterceptor } from './interceptor/opentelemetry-http.interceptor'; 18 | 19 | 20 | @NgModule({ 21 | declarations: [], 22 | imports: [HttpClientModule], 23 | exports: [], 24 | }) 25 | export class OpenTelemetryInterceptorModule { 26 | constructor( 27 | @Optional() @SkipSelf() parentModule?: OpenTelemetryInterceptorModule 28 | ) { 29 | if (parentModule) { 30 | throw new Error( 31 | 'OpentelemetryInterceptorModule is already loaded. Import it in the AppModule only' 32 | ); 33 | } 34 | } 35 | 36 | public static forRoot( 37 | config: OpenTelemetryConfig | null | undefined, 38 | configProvider?: ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider 39 | ): ModuleWithProviders { 40 | 41 | //Interceptor 42 | const interceptorProvider = { 43 | provide: HTTP_INTERCEPTORS, 44 | useClass: OpenTelemetryHttpInterceptor, 45 | multi: true, 46 | }; 47 | 48 | configProvider = defineConfigProvider(config,configProvider); 49 | 50 | return { 51 | ngModule: OpenTelemetryInterceptorModule, 52 | providers: [ 53 | configProvider, 54 | interceptorProvider, 55 | ], 56 | }; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/otel-webtracer.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | import { instrumentationConsoleOtelConfig } from '../../__mocks__/data/config.mock'; 4 | // eslint-disable-next-line max-len 5 | import { NoopSpanExporterModule, NoopTextMapPropagatorModule, OTEL_CONFIG, OTEL_INSTRUMENTATION_PLUGINS, OtelWebTracerModule } from '../public-api'; 6 | import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'; 7 | 8 | describe('OtelWebTracerModule', () => { 9 | let otelWebTracerModule: OtelWebTracerModule; 10 | 11 | it('should be created', () => { 12 | TestBed.configureTestingModule({ 13 | imports: [ 14 | OtelWebTracerModule.forRoot(instrumentationConsoleOtelConfig), 15 | NoopSpanExporterModule, 16 | NoopTextMapPropagatorModule 17 | ], 18 | providers: [ 19 | { provide: OTEL_CONFIG, useValue: instrumentationConsoleOtelConfig }, 20 | { provide: OTEL_INSTRUMENTATION_PLUGINS, useValue: [new XMLHttpRequestInstrumentation()] } 21 | ], 22 | }); 23 | otelWebTracerModule = TestBed.inject(OtelWebTracerModule); 24 | expect(otelWebTracerModule).toBeTruthy(); 25 | const config = TestBed.inject(OTEL_CONFIG); 26 | expect(config).not.toBeUndefined(); 27 | }); 28 | 29 | it('should be created with configProvider', () => { 30 | TestBed.configureTestingModule({ 31 | imports: [ 32 | OtelWebTracerModule.forRoot(null, { provide: OTEL_CONFIG, useValue: instrumentationConsoleOtelConfig }), 33 | NoopSpanExporterModule, 34 | NoopTextMapPropagatorModule 35 | ], 36 | providers: [{ provide: OTEL_INSTRUMENTATION_PLUGINS, useValue: [new XMLHttpRequestInstrumentation()] }] 37 | }); 38 | otelWebTracerModule = TestBed.inject(OtelWebTracerModule); 39 | expect(otelWebTracerModule).toBeTruthy(); 40 | const config = TestBed.inject(OTEL_CONFIG); 41 | expect(config).not.toBeUndefined(); 42 | }); 43 | it('should return error without config', () => { 44 | expect(() => { 45 | TestBed.configureTestingModule({ 46 | imports: [OtelWebTracerModule.forRoot(null, null)] 47 | }); 48 | }).toThrow('Configuration error. you must specify a configuration in config or configProvider'); 49 | }); 50 | it('should return error with wrong injection', () => { 51 | expect(() => { 52 | TestBed.configureTestingModule({ 53 | imports: [OtelWebTracerModule.forRoot(null, { provide: new InjectionToken('date'), useValue: new Date() })] 54 | }); 55 | }).toThrow('Configuration error. token must be : InjectionToken opentelemetry.config , your token value is : InjectionToken date'); 56 | }); 57 | it('should return error without root', () => { 58 | expect(() => { 59 | new OtelWebTracerModule({}); 60 | }).toThrow('OtelWebTracerModule is already loaded. Import it in the AppModule only'); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/otel-webtracer.module.ts: -------------------------------------------------------------------------------- 1 | import { 2 | APP_INITIALIZER, 3 | ClassProvider, 4 | ConstructorProvider, 5 | ExistingProvider, 6 | FactoryProvider, 7 | ModuleWithProviders, 8 | NgModule, 9 | Optional, 10 | SkipSelf, 11 | ValueProvider, 12 | } from '@angular/core'; 13 | import { 14 | defineConfigProvider, 15 | OpenTelemetryConfig, 16 | } from './configuration/opentelemetry-config'; 17 | import { InstrumentationService } from './services/instrumentation/instrumentation.service'; 18 | 19 | export const instruServiceLoader = (instrumentationService: InstrumentationService) => { 20 | const loader = () => instrumentationService.initInstrumentation(); 21 | return loader; 22 | }; 23 | 24 | 25 | @NgModule() 26 | export class OtelWebTracerModule { 27 | 28 | constructor( 29 | @Optional() @SkipSelf() parentModule?: OtelWebTracerModule 30 | ) { 31 | if (parentModule) { 32 | throw new Error( 33 | 'OtelWebTracerModule is already loaded. Import it in the AppModule only' 34 | ); 35 | } 36 | } 37 | 38 | public static forRoot( 39 | config: OpenTelemetryConfig | null | undefined, 40 | configProvider?: ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider 41 | ): ModuleWithProviders { 42 | 43 | configProvider = defineConfigProvider(config, configProvider); 44 | 45 | return { 46 | ngModule: OtelWebTracerModule, 47 | providers: [ 48 | configProvider, 49 | InstrumentationService, 50 | { 51 | provide: APP_INITIALIZER, 52 | useFactory: instruServiceLoader, 53 | deps: [InstrumentationService], 54 | multi: true 55 | } 56 | ], 57 | }; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/console/console-span-exporter.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { ConsoleSpanExporterService } from './console-span-exporter.service'; 3 | import { OTEL_EXPORTER } from '../exporter.interface'; 4 | 5 | 6 | 7 | @NgModule({ 8 | declarations: [], 9 | imports: [], 10 | providers: [ 11 | { provide: OTEL_EXPORTER, useClass: ConsoleSpanExporterService } 12 | ] 13 | }) 14 | export class ConsoleSpanExporterModule { 15 | } 16 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/console/console-span-exporter.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ConsoleSpanExporterService } from './console-span-exporter.service'; 4 | import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base'; 5 | 6 | 7 | describe('ConsoleExporterService', () => { 8 | let service: ConsoleSpanExporterService; 9 | 10 | beforeEach(() => { 11 | TestBed.configureTestingModule({}); 12 | service = TestBed.inject(ConsoleSpanExporterService); 13 | }); 14 | 15 | it('should be created', () => { 16 | expect(service).toBeTruthy(); 17 | expect(service.getExporter()).toBeInstanceOf(ConsoleSpanExporter); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/console/console-span-exporter.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { IExporter } from '../exporter.interface'; 3 | import { SpanExporter, ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base'; 4 | 5 | /** 6 | * ConsoleSpanExporterService 7 | * A default span exporter 8 | */ 9 | @Injectable({ 10 | providedIn: 'root', 11 | }) 12 | export class ConsoleSpanExporterService implements IExporter { 13 | /** 14 | * Return a ConsoleSpanExporter 15 | * 16 | * @return SpanExporter 17 | */ 18 | getExporter(): SpanExporter { 19 | return new ConsoleSpanExporter(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/exporter.interface.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import { SpanExporter } from '@opentelemetry/sdk-trace-base'; 3 | 4 | /** 5 | * Exporter interface to define a default exporter 6 | */ 7 | export interface IExporter { 8 | /** 9 | * give an inmplementation of SpanExporter 10 | * 11 | * @return SpanExporter 12 | */ 13 | getExporter(): SpanExporter; 14 | } 15 | 16 | /** injection for a Exporter */ 17 | export const OTEL_EXPORTER = new InjectionToken('otelcol.exporter'); 18 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/noop-exporter/noop-span-exporter.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { NoopSpanExporterService } from './noop-span-exporter.service'; 4 | import { OTEL_EXPORTER } from '../exporter.interface'; 5 | 6 | 7 | 8 | @NgModule({ 9 | declarations: [], 10 | imports: [ 11 | CommonModule 12 | ], 13 | providers: [ 14 | { provide: OTEL_EXPORTER, useClass: NoopSpanExporterService } 15 | ] 16 | }) 17 | export class NoopSpanExporterModule { 18 | } 19 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/noop-exporter/noop-span-exporter.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { NoopSpanExporterService } from './noop-span-exporter.service'; 4 | 5 | 6 | describe('NoopSpanExporterService', () => { 7 | let service: NoopSpanExporterService; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({}); 11 | service = TestBed.inject(NoopSpanExporterService); 12 | }); 13 | 14 | it('should be created', () => { 15 | expect(service).toBeTruthy(); 16 | expect(service.getExporter()).toBeUndefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/noop-exporter/noop-span-exporter.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { IExporter } from '../exporter.interface'; 3 | import { SpanExporter } from '@opentelemetry/sdk-trace-base'; 4 | 5 | /** 6 | * NoopSpanExporterService 7 | * A No-op span exporter 8 | */ 9 | @Injectable({ 10 | providedIn: 'root', 11 | }) 12 | export class NoopSpanExporterService implements IExporter { 13 | /** 14 | * Return undefined 15 | * 16 | * @return SpanExporter 17 | */ 18 | getExporter(): SpanExporter { 19 | return undefined; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/otelcol/otelcol-exporter.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { OtelcolExporterService } from './otelcol-exporter.service'; 3 | import { OTEL_EXPORTER } from '../exporter.interface'; 4 | 5 | 6 | @NgModule({ 7 | declarations: [], 8 | imports: [], 9 | providers: [ 10 | { provide: OTEL_EXPORTER, useClass: OtelcolExporterService }, 11 | ] 12 | }) 13 | export class OtelColExporterModule { 14 | } 15 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/otelcol/otelcol-exporter.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { OtelcolExporterService } from './otelcol-exporter.service'; 4 | import { OTEL_CONFIG } from '../../../configuration/opentelemetry-config'; 5 | import { 6 | otelcolExporterConfig, 7 | otelcolExporterWithoutUrlAndB3Config, 8 | } from '../../../../../__mocks__/data/config.mock'; 9 | import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; 10 | 11 | 12 | describe('OtelcolExporterService', () => { 13 | let otelcolExporterService: OtelcolExporterService; 14 | 15 | beforeEach(() => { 16 | TestBed.configureTestingModule({ 17 | providers: [ 18 | OtelcolExporterService, 19 | { provide: OTEL_CONFIG, useValue: otelcolExporterConfig }, 20 | ], 21 | }); 22 | otelcolExporterService = TestBed.inject(OtelcolExporterService); 23 | }); 24 | 25 | it('should be created', () => { 26 | expect(otelcolExporterService).toBeTruthy(); 27 | }); 28 | 29 | it('should generate a CollectorTraceExporter', () => { 30 | const exporter = otelcolExporterService.getExporter(); 31 | expect(exporter).not.toBeNull(); 32 | expect(exporter).toBeInstanceOf(OTLPTraceExporter); 33 | }); 34 | 35 | it('should generate a CollectorTraceExporter with no url in configuration and have url default endpoint', () => { 36 | TestBed.resetTestingModule(); 37 | TestBed.configureTestingModule({ 38 | providers: [ 39 | OtelcolExporterService, 40 | { 41 | provide: OTEL_CONFIG, 42 | useValue: otelcolExporterWithoutUrlAndB3Config, 43 | }, 44 | ], 45 | }); 46 | otelcolExporterService = TestBed.inject(OtelcolExporterService); 47 | const exporter = otelcolExporterService.getExporter(); 48 | expect(exporter).not.toBeNull(); 49 | expect(exporter).toBeInstanceOf(OTLPTraceExporter); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/otelcol/otelcol-exporter.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject, Optional } from '@angular/core'; 2 | import { IExporter } from '../exporter.interface'; 3 | import { SpanExporter } from '@opentelemetry/sdk-trace-base'; 4 | import { 5 | OpenTelemetryConfig, 6 | OTEL_CONFIG 7 | } from '../../../configuration/opentelemetry-config'; 8 | import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; 9 | import { OTLPExporterConfigBase } from '@opentelemetry/otlp-exporter-base'; 10 | 11 | /** 12 | * OtelcolExporterService class 13 | */ 14 | @Injectable({ 15 | providedIn: 'root', 16 | }) 17 | export class OtelcolExporterService implements IExporter { 18 | /** 19 | * CollectorExporterConfigBase 20 | */ 21 | private otelcolConfig: OTLPExporterConfigBase; 22 | 23 | /** 24 | * constructor 25 | * 26 | * @param config OpenTelemetryConfig 27 | */ 28 | constructor( 29 | @Inject(OTEL_CONFIG) config: OpenTelemetryConfig 30 | ) { 31 | this.otelcolConfig = { 32 | url: config.otelcolConfig?.url, 33 | headers: config.otelcolConfig?.headers, 34 | // eslint-disable-next-line max-len 35 | concurrencyLimit: Number(config.otelcolConfig?.concurrencyLimit ?? 0) <= 0 ? undefined : Number(config.otelcolConfig?.concurrencyLimit), 36 | timeoutMillis: Number(config.otelcolConfig?.timeoutMillis ?? 0) <= 0 ? undefined : Number(config.otelcolConfig?.timeoutMillis) 37 | }; 38 | } 39 | 40 | /** 41 | * Return a CollectorExporter with the configuration 42 | * 43 | * @return a CollectorExporter 44 | */ 45 | getExporter(): SpanExporter { 46 | return new OTLPTraceExporter(this.otelcolConfig); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/zipkin/zipkin-exporter.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { OTEL_EXPORTER } from '../exporter.interface'; 3 | import { ZipkinExporterService } from './zipkin-exporter.service'; 4 | 5 | 6 | 7 | @NgModule({ 8 | declarations: [], 9 | imports: [], 10 | providers: [ 11 | { provide: OTEL_EXPORTER, useClass: ZipkinExporterService } 12 | ] 13 | }) 14 | export class ZipkinExporterModule { 15 | } 16 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/zipkin/zipkin-exporter.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { ZipkinExporterService } from './zipkin-exporter.service'; 3 | import { OTEL_CONFIG } from '../../../configuration/opentelemetry-config'; 4 | import { zipkinConfig, zipkinOtherConfig } from '../../../../../__mocks__/data/config.mock'; 5 | import { ExporterConfig, ZipkinExporter } from '@opentelemetry/exporter-zipkin'; 6 | import { mocked } from 'jest-mock'; 7 | 8 | jest.mock('@opentelemetry/exporter-zipkin'); 9 | 10 | describe('ZipkinExporterService', () => { 11 | let zipkinExporterService: ZipkinExporterService; 12 | const mockedZipkinExporter = mocked(ZipkinExporter); 13 | 14 | beforeEach(() => { 15 | TestBed.configureTestingModule({ 16 | providers: [ 17 | ZipkinExporterService, 18 | { provide: OTEL_CONFIG, useValue: zipkinConfig }, 19 | ] 20 | }); 21 | zipkinExporterService = TestBed.inject(ZipkinExporterService); 22 | mockedZipkinExporter.mockClear(); 23 | }); 24 | 25 | it('should be created', () => { 26 | expect(zipkinExporterService).toBeTruthy(); 27 | }); 28 | 29 | it('should generate a zipkinExporter', () => { 30 | const exporter = zipkinExporterService.getExporter(); 31 | expect(exporter).not.toBeNull(); 32 | expect(exporter).toBeInstanceOf(ZipkinExporter); 33 | const mockedZipkinConfig: ExporterConfig = mockedZipkinExporter.mock.calls[0][0]; 34 | expect(mockedZipkinConfig.url).toEqual('http://localhost'); 35 | expect(mockedZipkinConfig.headers).toEqual({ test: 'test' }); 36 | }); 37 | 38 | it('should generate an other zipkinExporter', () => { 39 | TestBed.resetTestingModule(); 40 | TestBed.configureTestingModule({ 41 | providers: [ 42 | ZipkinExporterService, 43 | { provide: OTEL_CONFIG, useValue: zipkinOtherConfig }, 44 | ] 45 | }); 46 | zipkinExporterService = TestBed.inject(ZipkinExporterService); 47 | const exporter = zipkinExporterService.getExporter(); 48 | expect(exporter).not.toBeNull(); 49 | expect(exporter).toBeInstanceOf(ZipkinExporter); 50 | const mockedZipkinConfig: ExporterConfig = mockedZipkinExporter.mock.calls[0][0]; 51 | expect(mockedZipkinConfig.headers).toBeUndefined(); 52 | expect(mockedZipkinConfig.url).toBeUndefined(); 53 | }); 54 | 55 | }); 56 | 57 | 58 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/exporter/zipkin/zipkin-exporter.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | import { IExporter } from '../exporter.interface'; 3 | import { SpanExporter } from '@opentelemetry/sdk-trace-base'; 4 | import { OpenTelemetryConfig, OTEL_CONFIG } from '../../../configuration/opentelemetry-config'; 5 | import { ZipkinExporter, ExporterConfig } from '@opentelemetry/exporter-zipkin'; 6 | 7 | /** 8 | * ZipkinExporterService class 9 | */ 10 | @Injectable({ 11 | providedIn: 'root', 12 | }) 13 | export class ZipkinExporterService implements IExporter { 14 | /** 15 | * zipkinConfig 16 | */ 17 | private zipkinConfig: ExporterConfig; 18 | 19 | /** 20 | * constructor 21 | * 22 | * @param config OpenTelemetryConfig 23 | */ 24 | constructor(@Inject(OTEL_CONFIG) config: OpenTelemetryConfig) { 25 | this.zipkinConfig = { 26 | url: config.zipkinConfig?.url, 27 | headers: config.zipkinConfig?.headers 28 | }; 29 | } 30 | 31 | /** 32 | * Return a ZipkinExporter configured with zipkinConfig field 33 | * 34 | * @return SpanExporter 35 | */ 36 | getExporter(): SpanExporter { 37 | return new ZipkinExporter(this.zipkinConfig); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/instrumentation/instrumentation.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { ConsoleSpanExporterModule, W3CTraceContextPropagatorModule, OTEL_CONFIG, OTEL_INSTRUMENTATION_PLUGINS } from '../../../public-api'; 3 | // eslint-disable-next-line max-len 4 | import { instrumentationConsoleOtelConfig, instrumentationConsoleOtelConfigSamplerOff, instrumentationProductionOtelConfig } from '../../../../__mocks__/data/config.mock'; 5 | import { InstrumentationService } from './instrumentation.service'; 6 | import { NoopSpanExporterModule } from '../exporter/noop-exporter/noop-span-exporter.module'; 7 | import { OTEL_EXPORTER } from '../exporter/exporter.interface'; 8 | import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'; 9 | 10 | describe('InstrumentationService', () => { 11 | let instrumentationService: InstrumentationService; 12 | 13 | beforeEach(() => { 14 | TestBed.configureTestingModule({ 15 | imports: [ 16 | ConsoleSpanExporterModule, 17 | W3CTraceContextPropagatorModule, 18 | ], 19 | providers: [ 20 | { provide: OTEL_CONFIG, useValue: instrumentationConsoleOtelConfig }, 21 | { provide: OTEL_INSTRUMENTATION_PLUGINS, useValue: [new XMLHttpRequestInstrumentation()]}, 22 | ], 23 | }); 24 | instrumentationService = TestBed.inject(InstrumentationService); 25 | }); 26 | 27 | it('should be created', () => { 28 | expect(instrumentationService).toBeTruthy(); 29 | }); 30 | 31 | it('must init instrumentation with console config', () => { 32 | instrumentationService.initInstrumentation(); 33 | }); 34 | 35 | it('must init instrumentation with sampler Off config', () => { 36 | TestBed.resetTestingModule(); 37 | TestBed.configureTestingModule({ 38 | imports: [ 39 | ConsoleSpanExporterModule, 40 | W3CTraceContextPropagatorModule, 41 | ], 42 | providers: [ 43 | { provide: OTEL_CONFIG, useValue: instrumentationConsoleOtelConfigSamplerOff }, 44 | { provide: OTEL_INSTRUMENTATION_PLUGINS, useValue: [new XMLHttpRequestInstrumentation()]}, 45 | ], 46 | }); 47 | instrumentationService = TestBed.inject(InstrumentationService); 48 | instrumentationService.initInstrumentation(); 49 | }); 50 | 51 | it('must init instrumentation with production config', () => { 52 | TestBed.resetTestingModule(); 53 | TestBed.configureTestingModule({ 54 | imports: [ 55 | ConsoleSpanExporterModule, 56 | W3CTraceContextPropagatorModule, 57 | ], 58 | providers: [ 59 | { provide: OTEL_CONFIG, useValue: instrumentationProductionOtelConfig }, 60 | { provide: OTEL_INSTRUMENTATION_PLUGINS, useValue: [new XMLHttpRequestInstrumentation()]}, 61 | ], 62 | }); 63 | instrumentationService = TestBed.inject(InstrumentationService); 64 | instrumentationService.initInstrumentation(); 65 | }); 66 | 67 | it('must init instrumentation with noop span exporter', () => { 68 | TestBed.resetTestingModule(); 69 | TestBed.configureTestingModule({ 70 | imports: [ 71 | NoopSpanExporterModule, 72 | W3CTraceContextPropagatorModule, 73 | ], 74 | providers: [ 75 | { provide: OTEL_CONFIG, useValue: instrumentationProductionOtelConfig }, 76 | { provide: OTEL_INSTRUMENTATION_PLUGINS, useValue: [new XMLHttpRequestInstrumentation()]}, 77 | ], 78 | }); 79 | instrumentationService = TestBed.inject(InstrumentationService); 80 | instrumentationService.initInstrumentation(); 81 | }); 82 | 83 | }); 84 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/aws-xray-propagator/aws-xray-propagator.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { OTEL_PROPAGATOR } from '../propagator.interface'; 3 | import { AwsXrayPropagatorService } from './aws-xray-propagator.service'; 4 | 5 | 6 | 7 | @NgModule({ 8 | declarations: [], 9 | imports: [], 10 | providers: [ 11 | { provide: OTEL_PROPAGATOR, useClass: AwsXrayPropagatorService } 12 | ] 13 | }) 14 | export class AwsXrayPropagatorModule { 15 | } 16 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/aws-xray-propagator/aws-xray-propagator.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray'; 3 | import { AwsXrayPropagatorService } from './aws-xray-propagator.service'; 4 | 5 | 6 | describe('AwsXrayPropagatorService', () => { 7 | let service: AwsXrayPropagatorService; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({}); 11 | service = TestBed.inject(AwsXrayPropagatorService); 12 | }); 13 | 14 | it('should be created', () => { 15 | expect(service).toBeTruthy(); 16 | expect(service.getPropagator()).toBeInstanceOf(AWSXRayPropagator); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/aws-xray-propagator/aws-xray-propagator.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { IPropagator } from '../propagator.interface'; 3 | import { TextMapPropagator } from '@opentelemetry/api'; 4 | import { AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray'; 5 | /** 6 | * AwsXrayPropagatorService 7 | */ 8 | @Injectable({ 9 | providedIn: 'root', 10 | }) 11 | export class AwsXrayPropagatorService implements IPropagator { 12 | /** 13 | * Return an AwsXrayPropagator 14 | * 15 | * @return TextMapPropagator as AwsXrayPropagator 16 | */ 17 | getPropagator(): TextMapPropagator { 18 | return new AWSXRayPropagator(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/b3-propagator/b3-propagator.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { B3PropagatorService } from './b3-propagator.service'; 3 | import { OTEL_PROPAGATOR } from '../propagator.interface'; 4 | 5 | 6 | 7 | @NgModule({ 8 | declarations: [], 9 | imports: [], 10 | providers: [ 11 | { provide: OTEL_PROPAGATOR, useClass: B3PropagatorService } 12 | ] 13 | }) 14 | export class B3PropagatorModule { 15 | } 16 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/b3-propagator/b3-propagator.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { B3Propagator } from '@opentelemetry/propagator-b3'; 3 | import { B3PropagatorService } from './b3-propagator.service'; 4 | import { 5 | b3PropagatorSingleConfig, 6 | b3PropagatorMultiConfig 7 | } from '../../../../../__mocks__/data/config.mock'; 8 | import { OTEL_CONFIG } from '../../../configuration/opentelemetry-config'; 9 | 10 | describe('B3PropagatorService', () => { 11 | let b3PropagatorService: B3PropagatorService; 12 | 13 | beforeEach(() => { 14 | TestBed.configureTestingModule({ 15 | providers: [ 16 | B3PropagatorService, 17 | { provide: OTEL_CONFIG, useValue: b3PropagatorMultiConfig }, 18 | ], 19 | }); 20 | b3PropagatorService = TestBed.inject(B3PropagatorService); 21 | }); 22 | 23 | it('should be created', () => { 24 | expect(b3PropagatorService).toBeTruthy(); 25 | }); 26 | 27 | it('should return an B3Propagator with multi header', () => { 28 | expect(b3PropagatorService.getPropagator()).toBeInstanceOf(B3Propagator); 29 | }); 30 | 31 | it('should return an B3Propagator with single header', () => { 32 | TestBed.resetTestingModule(); 33 | TestBed.configureTestingModule({ 34 | providers: [ 35 | B3PropagatorService, 36 | { provide: OTEL_CONFIG, useValue: b3PropagatorSingleConfig }, 37 | ], 38 | }); 39 | b3PropagatorService = TestBed.inject(B3PropagatorService); 40 | expect(b3PropagatorService.getPropagator()).toBeInstanceOf(B3Propagator); 41 | }); 42 | 43 | 44 | 45 | }); 46 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/b3-propagator/b3-propagator.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | import { IPropagator } from '../propagator.interface'; 3 | import { TextMapPropagator } from '@opentelemetry/api'; 4 | import { B3Propagator, B3PropagatorConfig, B3InjectEncoding } from '@opentelemetry/propagator-b3'; 5 | import { 6 | OpenTelemetryConfig, 7 | OTEL_CONFIG, 8 | } from '../../../configuration/opentelemetry-config'; 9 | 10 | /** 11 | * B3PropagatorService 12 | * 13 | * Can be a single or multi header. 14 | * 15 | * See Configuration for more information 16 | */ 17 | @Injectable({ 18 | providedIn: 'root', 19 | }) 20 | export class B3PropagatorService implements IPropagator { 21 | /** 22 | * B3PropagatorConfig 23 | */ 24 | private b3PropagatorConfig: B3PropagatorConfig; 25 | 26 | /** 27 | * Constructor 28 | * 29 | * @param config OpenTelemetryConfig 30 | */ 31 | constructor(@Inject(OTEL_CONFIG) config: OpenTelemetryConfig) { 32 | this.b3PropagatorConfig = { 33 | injectEncoding: B3PropagatorService.defineB3Encoding(config.b3PropagatorConfig?.multiHeader) 34 | }; 35 | } 36 | 37 | /** 38 | * Define if it's a single or multi header 39 | * 40 | * @param value string (0 => single header, 1 => Multi Header) 41 | * @return B3InjectEncoding 42 | */ 43 | private static defineB3Encoding(value: string): B3InjectEncoding { 44 | if (value && '0' === value) { 45 | return B3InjectEncoding.SINGLE_HEADER; 46 | } 47 | return B3InjectEncoding.MULTI_HEADER; 48 | } 49 | 50 | /** 51 | * Return an B3Propagator 52 | * 53 | * @return TextMapPropagator as B3Propagator 54 | */ 55 | getPropagator(): TextMapPropagator { 56 | return new B3Propagator(this.b3PropagatorConfig); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/composite-propagator/composite-propagator.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CompositePropagatorService } from './composite-propagator.service'; 3 | import { OTEL_PROPAGATOR } from '../propagator.interface'; 4 | 5 | 6 | 7 | @NgModule({ 8 | declarations: [], 9 | imports: [], 10 | providers: [ 11 | { provide: OTEL_PROPAGATOR, useClass: CompositePropagatorService } 12 | ] 13 | }) 14 | export class CompositePropagatorModule { 15 | } 16 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/composite-propagator/composite-propagator.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { CompositePropagator } from '@opentelemetry/core'; 3 | import { CompositePropagatorService } from './composite-propagator.service'; 4 | import { OTEL_CONFIG } from '../../../configuration/opentelemetry-config'; 5 | import { jaegerPropagatorConfig } from '../../../../../__mocks__/data/config.mock'; 6 | 7 | describe('CompositePropagatorService', () => { 8 | let service: CompositePropagatorService; 9 | 10 | beforeEach(() => { 11 | TestBed.configureTestingModule({ 12 | providers: [ 13 | CompositePropagatorService, 14 | { 15 | provide: OTEL_CONFIG, 16 | useValue: jaegerPropagatorConfig, 17 | }, 18 | ], 19 | }); 20 | service = TestBed.inject(CompositePropagatorService); 21 | }); 22 | 23 | it('should be created', () => { 24 | expect(service).toBeTruthy(); 25 | }); 26 | 27 | it('should return an CompositePropagator', () => { 28 | expect(service.getPropagator()).toBeInstanceOf(CompositePropagator); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/composite-propagator/composite-propagator.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | import { IPropagator } from '../propagator.interface'; 3 | import { TextMapPropagator } from '@opentelemetry/api'; 4 | import { CompositePropagator } from '@opentelemetry/core'; 5 | import { B3PropagatorService } from '../b3-propagator/b3-propagator.service'; 6 | import { W3CTraceContextPropagatorService } from '../w3c-trace-context-propagator/w3c-trace-context-propagator.service'; 7 | import { JaegerHttpTracePropagatorService } from '../jaeger-http-trace-propagator/jaeger-http-trace-propagator.service'; 8 | import { AwsXrayPropagatorService } from '../aws-xray-propagator/aws-xray-propagator.service'; 9 | /** 10 | * CompositePropagatorService 11 | */ 12 | @Injectable({ 13 | providedIn: 'root', 14 | }) 15 | export class CompositePropagatorService implements IPropagator { 16 | /** 17 | * Constructor 18 | */ 19 | constructor( 20 | @Inject(B3PropagatorService) 21 | private b3PropagatorService: B3PropagatorService, 22 | @Inject(W3CTraceContextPropagatorService) 23 | private w3cTraceContextPropagatorService: W3CTraceContextPropagatorService, 24 | @Inject(JaegerHttpTracePropagatorService) 25 | private jaegerHttpTracePropagatorService: JaegerHttpTracePropagatorService, 26 | @Inject(AwsXrayPropagatorService) 27 | private awsXrayPropagatorService: AwsXrayPropagatorService 28 | ) {} 29 | 30 | /** 31 | * Return an CompositePropagator 32 | * 33 | * @return TextMapPropagator as CompositePropagator 34 | */ 35 | getPropagator(): TextMapPropagator { 36 | return new CompositePropagator({ 37 | propagators: [ 38 | this.b3PropagatorService.getPropagator(), 39 | this.w3cTraceContextPropagatorService.getPropagator(), 40 | this.jaegerHttpTracePropagatorService.getPropagator(), 41 | this.awsXrayPropagatorService.getPropagator() 42 | ], 43 | }); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/jaeger-http-trace-propagator/jaeger-http-trace-propagator.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { JaegerHttpTracePropagatorService } from './jaeger-http-trace-propagator.service'; 3 | import { OTEL_PROPAGATOR } from '../propagator.interface'; 4 | 5 | 6 | 7 | @NgModule({ 8 | declarations: [], 9 | imports: [], 10 | providers: [ 11 | { provide: OTEL_PROPAGATOR, useClass: JaegerHttpTracePropagatorService } 12 | ] 13 | }) 14 | export class JaegerHttpTracePropagatorModule { 15 | } 16 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/jaeger-http-trace-propagator/jaeger-http-trace-propagator.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { JaegerHttpTracePropagatorService } from './jaeger-http-trace-propagator.service'; 4 | import { OTEL_CONFIG } from '../../../configuration/opentelemetry-config'; 5 | import { 6 | jaegerPropagatorConfig, 7 | jaegerPropagatorWithoutCustomHeaderConfig, 8 | } from '../../../../../__mocks__/data/config.mock'; 9 | import { JaegerPropagator } from '@opentelemetry/propagator-jaeger'; 10 | 11 | describe('JaegerHttpTracePropagatorService', () => { 12 | let service: JaegerHttpTracePropagatorService; 13 | 14 | it('should return an JaegerHttpTracePropagator', () => { 15 | TestBed.configureTestingModule({ 16 | providers: [ 17 | JaegerHttpTracePropagatorService, 18 | { 19 | provide: OTEL_CONFIG, 20 | useValue: jaegerPropagatorConfig, 21 | }, 22 | ], 23 | }); 24 | service = TestBed.inject(JaegerHttpTracePropagatorService); 25 | expect(service).toBeTruthy(); 26 | expect(service.getPropagator()).toBeInstanceOf(JaegerPropagator); 27 | }); 28 | 29 | it('should return an JaegerHttpTracePropagator without customHeader', () => { 30 | TestBed.configureTestingModule({ 31 | providers: [ 32 | JaegerHttpTracePropagatorService, 33 | { 34 | provide: OTEL_CONFIG, 35 | useValue: jaegerPropagatorWithoutCustomHeaderConfig, 36 | }, 37 | ], 38 | }); 39 | service = TestBed.inject(JaegerHttpTracePropagatorService); 40 | expect(service).toBeTruthy(); 41 | expect(service.getPropagator()).toBeInstanceOf(JaegerPropagator); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/jaeger-http-trace-propagator/jaeger-http-trace-propagator.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | import { IPropagator } from '../propagator.interface'; 3 | import { TextMapPropagator } from '@opentelemetry/api'; 4 | import { JaegerPropagator } from '@opentelemetry/propagator-jaeger'; 5 | import { OTEL_CONFIG } from '../../../configuration/opentelemetry-config'; 6 | import { OpenTelemetryConfig } from '../../../../public-api'; 7 | 8 | /** 9 | * JaegerHttpTracePropagatorService 10 | */ 11 | @Injectable({ 12 | providedIn: 'root', 13 | }) 14 | export class JaegerHttpTracePropagatorService implements IPropagator { 15 | /** 16 | * custom Header 17 | */ 18 | private customHeader: string; 19 | /** 20 | * Constructor 21 | * 22 | * @param config OpenTelemetryConfig 23 | */ 24 | constructor(@Inject(OTEL_CONFIG) config: OpenTelemetryConfig) { 25 | this.customHeader = config.jaegerPropagatorConfig?.customHeader; 26 | } 27 | 28 | /** 29 | * Return an JaegerPropagator 30 | * 31 | * @return TextMapPropagator as JaegerPropagator 32 | */ 33 | getPropagator(): TextMapPropagator { 34 | return new JaegerPropagator(this.customHeader); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/noop-http-text-propagator/noop-text-map-propagator.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { NoopTextMapPropagatorService } from './noop-text-map-propagator.service'; 3 | import { OTEL_PROPAGATOR } from '../propagator.interface'; 4 | 5 | 6 | 7 | @NgModule({ 8 | declarations: [], 9 | imports: [], 10 | providers: [ 11 | { provide: OTEL_PROPAGATOR, useClass: NoopTextMapPropagatorService } 12 | ] 13 | }) 14 | export class NoopTextMapPropagatorModule { 15 | } 16 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/noop-http-text-propagator/noop-text-map-propagator.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { NoopTextMapPropagatorService } from './noop-text-map-propagator.service'; 3 | 4 | describe('NoopTextMapPropagatorService', () => { 5 | let service: NoopTextMapPropagatorService; 6 | 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({}); 9 | service = TestBed.inject(NoopTextMapPropagatorService); 10 | }); 11 | 12 | it('should be created', () => { 13 | expect(service).toBeTruthy(); 14 | expect(service.getPropagator()).toBeNull(); 15 | }); 16 | }); 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/noop-http-text-propagator/noop-text-map-propagator.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { IPropagator } from '../propagator.interface'; 3 | import { TextMapPropagator } from '@opentelemetry/api'; 4 | /** 5 | * NoopHttpTextPropagatorService 6 | */ 7 | @Injectable({ 8 | providedIn: 'root', 9 | }) 10 | export class NoopTextMapPropagatorService implements IPropagator { 11 | /** 12 | * Return null 13 | * 14 | * @return TextMapPropagator as null 15 | */ 16 | getPropagator(): TextMapPropagator { 17 | return null; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/propagator.interface.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import { TextMapPropagator } from '@opentelemetry/api'; 3 | 4 | /** 5 | * Interface to define propagator 6 | */ 7 | export interface IPropagator { 8 | /** 9 | * give an implementation of a propagator 10 | * 11 | * @return HttpTextPropagator 12 | */ 13 | getPropagator(): TextMapPropagator; 14 | } 15 | 16 | /** injection for a propagator */ 17 | export const OTEL_PROPAGATOR = new InjectionToken('otelcol.propagator'); 18 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/w3c-trace-context-propagator/w3c-trace-context-propagator.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { W3CTraceContextPropagatorService } from './w3c-trace-context-propagator.service'; 3 | import { OTEL_PROPAGATOR } from '../propagator.interface'; 4 | 5 | 6 | 7 | @NgModule({ 8 | declarations: [], 9 | imports: [], 10 | providers: [ 11 | { provide: OTEL_PROPAGATOR, useClass: W3CTraceContextPropagatorService } 12 | ] 13 | }) 14 | export class W3CTraceContextPropagatorModule { 15 | } 16 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/w3c-trace-context-propagator/w3c-trace-context-propagator.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { W3CTraceContextPropagator } from '@opentelemetry/core'; 3 | import { W3CTraceContextPropagatorService } from './w3c-trace-context-propagator.service'; 4 | 5 | describe('W3CTraceContextPropagatorService', () => { 6 | let service: W3CTraceContextPropagatorService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({ 10 | providers: [W3CTraceContextPropagatorService], 11 | }); 12 | service = TestBed.inject(W3CTraceContextPropagatorService); 13 | }); 14 | 15 | it('should be created', () => { 16 | expect(service).toBeTruthy(); 17 | }); 18 | 19 | it('should return an HttpTraceContext', () => { 20 | expect(service.getPropagator()).toBeInstanceOf(W3CTraceContextPropagator); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/lib/services/propagator/w3c-trace-context-propagator/w3c-trace-context-propagator.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { IPropagator } from '../propagator.interface'; 3 | import { TextMapPropagator } from '@opentelemetry/api'; 4 | import { W3CTraceContextPropagator } from '@opentelemetry/core'; 5 | 6 | /** 7 | * W3CTraceContextPropagatorService 8 | */ 9 | @Injectable({ 10 | providedIn: 'root', 11 | }) 12 | export class W3CTraceContextPropagatorService implements IPropagator { 13 | /** 14 | * Return an W3CTraceContextPropagatorService 15 | * 16 | * @return TextMapPropagator as W3CTraceContextPropagatorService 17 | */ 18 | getPropagator(): TextMapPropagator { 19 | return new W3CTraceContextPropagator(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of opentelemetry-interceptor 3 | */ 4 | // Interceptor 5 | export { OpenTelemetryInterceptorModule } from './lib/opentelemetry-interceptor.module'; 6 | export { OpenTelemetryHttpInterceptor } from './lib/interceptor/opentelemetry-http.interceptor'; 7 | // Exporter 8 | export { OtelColExporterModule } from './lib/services/exporter/otelcol/otelcol-exporter.module'; 9 | export { OtelcolExporterService } from './lib/services/exporter/otelcol/otelcol-exporter.service'; 10 | export { ConsoleSpanExporterModule } from './lib/services/exporter/console/console-span-exporter.module'; 11 | export { ConsoleSpanExporterService } from './lib/services/exporter/console/console-span-exporter.service'; 12 | export { ZipkinExporterModule } from './lib/services/exporter/zipkin/zipkin-exporter.module'; 13 | export { ZipkinExporterService } from './lib/services/exporter/zipkin/zipkin-exporter.service'; 14 | export { NoopSpanExporterModule } from './lib/services/exporter/noop-exporter/noop-span-exporter.module'; 15 | export { NoopSpanExporterService } from './lib/services/exporter/noop-exporter/noop-span-exporter.service'; 16 | // Propagator 17 | export { B3PropagatorModule } from './lib/services/propagator/b3-propagator/b3-propagator.module'; 18 | export { CompositePropagatorModule } from './lib/services/propagator/composite-propagator/composite-propagator.module'; 19 | export { AwsXrayPropagatorModule } from './lib/services/propagator/aws-xray-propagator/aws-xray-propagator.module'; 20 | /* eslint-disable max-len */ 21 | export { W3CTraceContextPropagatorModule } from './lib/services/propagator/w3c-trace-context-propagator/w3c-trace-context-propagator.module'; 22 | export { JaegerHttpTracePropagatorModule } from './lib/services/propagator/jaeger-http-trace-propagator/jaeger-http-trace-propagator.module'; 23 | /* eslint-enable max-len */ 24 | export { NoopTextMapPropagatorModule } from './lib/services/propagator/noop-http-text-propagator/noop-text-map-propagator.module'; 25 | //Component 26 | export { OtelWebTracerModule } from './lib/otel-webtracer.module'; 27 | 28 | //Interface 29 | export { CustomSpan } from './lib/interceptor/custom-span.interface'; 30 | export { OTEL_EXPORTER, IExporter } from './lib/services/exporter/exporter.interface'; 31 | export { OTEL_PROPAGATOR, IPropagator } from './lib/services/propagator/propagator.interface'; 32 | 33 | // Configuration 34 | export { 35 | CommonCollectorConfig, 36 | BatchSpanProcessorConfig, 37 | OtelCollectorConfig, 38 | OpenTelemetryConfig, 39 | OTEL_CONFIG, 40 | ZipkinCollectorConfig, 41 | JaegerPropagatorConfig, 42 | B3PropagatorConfig, 43 | IgnoreUrlsConfig, 44 | OTEL_LOGGER, 45 | OTEL_CUSTOM_SPAN, 46 | OTEL_INSTRUMENTATION_PLUGINS 47 | } from './lib/configuration/opentelemetry-config'; 48 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/src/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jufab/opentelemetry-angular-interceptor", 3 | "version": "1.9.0-1" 4 | } 5 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "es2020", 5 | "declarationMap": true, 6 | "declaration": true, 7 | "inlineSources": true, 8 | "types": [], 9 | "lib": [ 10 | "dom", 11 | "ESNext", 12 | "es2018" 13 | ] 14 | }, 15 | "angularCompilerOptions": { 16 | "skipTemplateCodegen": true, 17 | "strictMetadataEmit": true, 18 | "enableResourceInlining": true, 19 | "flatModuleId": "AUTOGENERATED", 20 | "flatModuleOutFile": "AUTOGENERATED", 21 | }, 22 | "exclude": [ 23 | "**/*.spec.ts" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | }, 6 | "angularCompilerOptions": { 7 | "compilationMode": "partial" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /projects/opentelemetry-interceptor/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "module": "CommonJs", 6 | "types": [ 7 | "jest", 8 | "node" 9 | ] 10 | }, 11 | "include": [ 12 | "**/*.spec.ts", 13 | "**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "emitDecoratorMetadata": true, 11 | "esModuleInterop": true, 12 | "module": "es2020", 13 | "moduleResolution": "node", 14 | "importHelpers": true, 15 | "target": "es2020", 16 | "resolveJsonModule": true, 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ], 21 | "paths": { 22 | "opentelemetry-interceptor": [ 23 | "dist/opentelemetry-interceptor/opentelemetry-interceptor", 24 | "dist/opentelemetry-interceptor" 25 | ] 26 | } 27 | }, 28 | "angularCompilerOptions": { 29 | "fullTemplateTypeCheck": true, 30 | "strictInjectionParameters": true, 31 | "enableI18nLegacyMessageIdFormat": false, 32 | "strictInputAccessModifiers": true, 33 | "strictTemplates": true 34 | } 35 | } 36 | --------------------------------------------------------------------------------