├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── example-addition.md ├── config │ └── markdown-link-check-config.json ├── dependabot.yml ├── scripts │ └── markdown-link-check-with-retry.sh └── workflows │ ├── pull_request.yml │ └── repolinter.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── cla.md ├── getting-started-guides ├── .dockerignore ├── .env ├── README.md ├── compose.yaml ├── demo-app-specification.md ├── dotnet │ ├── Controllers │ │ └── FibonacciController.cs │ ├── Dockerfile │ ├── OTEL_DIAGNOSTICS.json │ ├── Program.cs │ ├── README.md │ ├── appsettings.Development.json │ ├── appsettings.json │ └── dotnet.csproj ├── go │ ├── Dockerfile │ ├── README.md │ ├── fibonacci.go │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── otel.go ├── java │ ├── .editorconfig │ ├── Dockerfile │ ├── README.md │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ ├── Application.java │ │ │ └── Controller.java │ │ └── resources │ │ └── log4j2.xml ├── javascript │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── app.js │ ├── instrumentation.js │ ├── package-lock.json │ └── package.json ├── python │ ├── Dockerfile │ ├── README.md │ ├── app.py │ └── requirements.txt ├── ruby │ ├── Dockerfile │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── app.rb │ ├── config.ru │ ├── fibonacci.rb │ └── opentelemetry.rb ├── rust │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Dockerfile │ ├── README.md │ └── src │ │ └── main.rs └── supporting-files │ ├── envoy.yaml │ └── loadgenerator.py ├── java └── micrometer-shim │ └── README.md └── other-examples ├── collector ├── confluentcloud │ ├── README.md │ └── k8s │ │ ├── collector.yaml │ │ └── secrets.yaml ├── docker │ ├── .env │ ├── README.md │ ├── config.yaml │ └── docker-compose.yaml ├── hcp-consul │ ├── README.md │ └── k8s │ │ ├── collector.yaml │ │ └── secrets.yaml ├── hivemq │ ├── .gitignore │ ├── README.md │ ├── download-prometheus-extension.sh │ └── k8s │ │ ├── collector.yaml │ │ ├── hivemq.yaml │ │ └── secrets.yaml ├── host-monitoring │ ├── README.md │ └── k8s │ │ ├── _namespace.yaml │ │ ├── adservice.yaml │ │ ├── collector.yaml │ │ └── secrets.yaml ├── nr-config │ ├── README.md │ ├── docker-compose.yaml │ └── otel-config.yaml ├── nrdot-host-monitoring │ ├── README.md │ └── k8s │ │ ├── _namespace.yaml │ │ ├── adservice.yaml │ │ ├── collector.yaml │ │ └── secrets.yaml ├── prometheus │ ├── README.md │ └── k8s │ │ ├── collector.yaml │ │ ├── prometheus-data-generator.yaml │ │ └── secrets.yaml ├── redis │ ├── README.md │ └── k8s │ │ ├── collector.yaml │ │ ├── redis.yaml │ │ └── secrets.yaml ├── singlestore │ ├── README.md │ └── k8s │ │ ├── collector.yaml │ │ └── secrets.yaml ├── squid │ ├── README.md │ └── k8s │ │ ├── collector.yaml │ │ ├── secrets.yaml │ │ └── squid.yaml └── statsd │ ├── README.md │ └── k8s │ ├── collector.yaml │ ├── gen-statsd.yaml │ └── secrets.yaml ├── dotnet └── agent-nr-config │ ├── .dockerignore │ ├── Controllers │ └── WeatherForecastController.cs │ ├── Dockerfile │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── README.md │ ├── WeatherForecast.cs │ ├── agent-nr-config.csproj │ ├── appsettings.Development.json │ └── appsettings.json ├── java ├── .editorconfig ├── agent-nr-config │ ├── README.md │ ├── application │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── newrelic │ │ │ └── app │ │ │ ├── Application.java │ │ │ └── Controller.java │ └── config-extension │ │ ├── build.gradle │ │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── newrelic │ │ │ └── otel │ │ │ └── extension │ │ │ └── Customizer.java │ │ └── resources │ │ └── META-INF │ │ └── services │ │ └── io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── logs-in-context-log4j2 │ ├── .env │ ├── Dockerfile │ ├── Log4j2EventLayout.json │ ├── README.md │ ├── docker-compose.yaml │ ├── log4j2.xml │ ├── otel-config.yaml │ ├── trace-logs-in-context.png │ └── trace-with-logs.png ├── micrometer-shim │ ├── README.md │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── opentelemetry │ │ └── example │ │ └── micrometer │ │ ├── Application.java │ │ ├── Controller.java │ │ └── Service.java └── settings.gradle └── serverless ├── aws-lambda ├── dotnet │ ├── .gitignore │ ├── README.md │ ├── src │ │ ├── collector.yaml │ │ ├── function.cs │ │ └── function.csproj │ └── template.yml └── java │ ├── .gitignore │ ├── ExampleFunction │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── src │ │ └── main │ │ └── java │ │ └── example │ │ └── App.java │ ├── README.md │ ├── collector.yaml │ └── template.yaml └── azure-functions └── node └── http-trigger-app ├── .funcignore ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── HttpTriggerExample ├── function.json ├── index.js └── sample.dat ├── host.json ├── open-telemetry └── tracing.js ├── package-lock.json ├── package.json └── readme.md /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Global codeowners 2 | 3 | * @newrelic/opentelemetry-community 4 | 5 | getting-started-guides/dotnet/ @alanwest 6 | getting-started-guides/java/ @jack-berg 7 | getting-started-guides/ruby/ @kaylareopelle 8 | 9 | other-examples/collector/ @jcountsNR 10 | other-examples/dotnet/ @alanwest 11 | other-examples/java/ @jack-berg 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Describe a scenario in which this project behaves unexpectedly 4 | title: '' 5 | labels: bug, needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | [NOTE]: # ( ^^ Provide a general summary of the issue in the title above. ^^ ) 11 | 12 | ## Description 13 | 14 | [NOTE]: # ( Describe the problem you're encountering. ) 15 | [TIP]: # ( Do NOT give us access or passwords to your New Relic account or API keys! ) 16 | 17 | ## Steps to Reproduce 18 | 19 | [NOTE]: # ( Please be as specific as possible. ) 20 | 21 | ## Expected Behavior 22 | 23 | [NOTE]: # ( Tell us what you expected to happen. ) 24 | 25 | ## Relevant Logs / Console output 26 | 27 | [NOTE]: # ( Please provide specifics of the local error logs, Browser Dev Tools console, etc. if appropriate and possible. ) 28 | 29 | ## Your Environment 30 | 31 | [TIP]: # ( Include as many relevant details about your environment as possible. ) 32 | 33 | * ex: Browser name and version: 34 | * ex: Operating System and version: 35 | 36 | ## Additional context 37 | 38 | [TIP]: # ( Add any other context about the problem here. ) 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/example-addition.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Example addition request 3 | about: Suggest an idea for a new example 4 | title: '' 5 | labels: example, needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | [NOTE]: # ( ^^ Provide a general summary of the request in the title above. ^^ ) 11 | 12 | ## Summary 13 | 14 | [NOTE]: # ( Provide a brief overview of what the new example proposal. ) 15 | 16 | ## Example category 17 | 18 | [NOTE]: # ( Which category does the example fall under? Options: OpenTelemetry APM monitoring, OpenTelemetry infrastructure monitoring, OpenTelemetry other examples.) 19 | [TIP]: # ( See details on categories and acceptance criteria in README.md. ) 20 | 21 | ## Additional context 22 | 23 | [TIP]: # ( Why does this feature matter to you? What unique circumstances do you have? ) 24 | -------------------------------------------------------------------------------- /.github/config/markdown-link-check-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "retryOn429": true, 3 | "aliveStatusCodes": [ 4 | 200, 5 | 403 6 | ], 7 | "ignorePatterns": [ 8 | { "pattern": "https:\\/\\/.*.nr-data\\.net.*" }, 9 | { "pattern": "http:\\/\\/localhost:[0-9]*" } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | - package-ecosystem: "gradle" 8 | directory: "/other-examples/java" 9 | rebase-strategy: "disabled" 10 | schedule: 11 | interval: "daily" 12 | open-pull-requests-limit: 10 13 | - package-ecosystem: "gradle" 14 | directory: "/getting-started-guides/java" 15 | rebase-strategy: "disabled" 16 | schedule: 17 | interval: "daily" 18 | open-pull-requests-limit: 10 19 | -------------------------------------------------------------------------------- /.github/scripts/markdown-link-check-with-retry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # this script helps to reduce sporadic link check failures by retrying at a file-by-file level 4 | 5 | retry_count=3 6 | 7 | for file in "$@"; do 8 | for i in $(seq 1 $retry_count); do 9 | if markdown-link-check --config "$(dirname "$0")/../config/markdown-link-check-config.json" \ 10 | "$file"; then 11 | break 12 | elif [[ $i -eq $retry_count ]]; then 13 | exit 1 14 | fi 15 | sleep 5 16 | done 17 | done 18 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Java PR build (gradle) 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | 7 | jobs: 8 | build-java: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Set up JDK 17 13 | uses: actions/setup-java@v4.4.0 14 | with: 15 | distribution: temurin 16 | java-version: 17 17 | - name: Build java with Gradle 18 | working-directory: other-examples/java 19 | run: ./gradlew build 20 | - name: Build getting-started-guides/java with Gradle 21 | working-directory: getting-started-guides/java 22 | run: ./gradlew build 23 | 24 | markdown-link-check: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v4 28 | 29 | - name: Install markdown-link-check 30 | # TODO(jack-berg): use latest when config file reading bug is fixed: https://github.com/tcort/markdown-link-check/issues/246 31 | run: npm install -g markdown-link-check@3.10.3 32 | 33 | - name: Run markdown-link-check 34 | run: | 35 | find . -type f \ 36 | -name '*.md' \ 37 | | xargs .github/scripts/markdown-link-check-with-retry.sh 38 | -------------------------------------------------------------------------------- /.github/workflows/repolinter.yml: -------------------------------------------------------------------------------- 1 | # NOTE: This file should always be named `repolinter.yml` to allow 2 | # workflow_dispatch to work properly 3 | name: Repolinter Action 4 | 5 | on: 6 | workflow_dispatch: 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | repolint: 13 | name: Run Repolinter 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Test Default Branch 17 | id: default-branch 18 | uses: actions/github-script@v7 19 | with: 20 | script: | 21 | const data = await github.rest.repos.get(context.repo) 22 | return data.data && data.data.default_branch === context.ref.split('/').slice(-1)[0] 23 | - name: Checkout Self 24 | if: ${{ steps.default-branch.outputs.result == 'true' }} 25 | uses: actions/checkout@v4 26 | - name: Run Repolinter 27 | if: ${{ steps.default-branch.outputs.result == 'true' }} 28 | uses: newrelic/repolinter-action@v1 29 | with: 30 | config_url: https://raw.githubusercontent.com/newrelic/.github/main/repolinter-rulesets/example-code.yml 31 | output_type: issue 32 | 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | .vs/ 4 | 5 | build/ 6 | .gradle/ 7 | .DS_STORE 8 | 9 | getting-started-guides/rust/target 10 | 11 | # Ignore .NET build output 12 | [Bb]in/ 13 | [Oo]bj/ 14 | [Ll]ogs/ 15 | 16 | # Python 17 | venv 18 | __pycache__ 19 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are always welcome. Before contributing please read the 4 | [code of conduct](https://github.com/newrelic/.github/blob/main/CODE_OF_CONDUCT.md) and [search the issue tracker](https://github.com/newrelic/newrelic-opentelemetry-examples/issues); your issue may have already been discussed or fixed in `main`. To contribute, 5 | [fork](https://help.github.com/articles/fork-a-repo/) this repository, commit your changes, and [send a Pull Request](https://help.github.com/articles/using-pull-requests/). 6 | 7 | Note that our [code of conduct](https://github.com/newrelic/.github/blob/main/CODE_OF_CONDUCT.md) applies to all platforms and venues related to this project; please follow it in all your interactions with the project and its participants. 8 | 9 | ## Feature Requests 10 | 11 | Feature requests should be submitted in the [Issue tracker](https://github.com/newrelic/newrelic-opentelemetry-examples/issues), with a description of the expected behavior & use case, where they’ll remain closed until sufficient interest, [e.g. :+1: reactions](https://help.github.com/articles/about-discussions-in-issues-and-pull-requests/), has been [shown by the community](https://github.com/newrelic/newrelic-opentelemetry-examples/issues?q=label%3A%22votes+needed%22+sort%3Areactions-%2B1-desc). 12 | Before submitting an Issue, please search for similar ones in the 13 | [closed issues](https://github.com/newrelic/newrelic-opentelemetry-examples/issues?q=is%3Aissue+is%3Aclosed+label%3Aenhancement). 14 | 15 | ## Pull Requests 16 | 17 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a build. 18 | 2. Increase the version numbers in any examples files and the README.md to the new version that this Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 19 | 3. You may merge the Pull Request in once you have the sign-off of two other developers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. 20 | 21 | ## Contributor License Agreement 22 | 23 | Keep in mind that when you submit your Pull Request, you'll need to sign the CLA via the click-through using CLA-Assistant. If you'd like to execute our corporate CLA, or if you have any questions, please drop us an email at opensource@newrelic.com. 24 | 25 | For more information about CLAs, please check out Alex Russell’s excellent post, 26 | [“Why Do I Need to Sign This?”](https://infrequently.org/2008/06/why-do-i-need-to-sign-this/). 27 | 28 | ## Slack 29 | 30 | We host a public Slack with a dedicated channel for contributors and maintainers of open source projects hosted by New Relic. If you are contributing to this project, you're welcome to request access to the #oss-contributors channel in the newrelicusers.slack.com workspace. To request access, please use this [link](https://join.slack.com/t/newrelicusers/shared_invite/zt-1ayj69rzm-~go~Eo1whIQGYnu3qi15ng). 31 | -------------------------------------------------------------------------------- /getting-started-guides/.dockerignore: -------------------------------------------------------------------------------- 1 | # Include any files or directories that you don't want to be copied to your 2 | # container here (e.g., local build artifacts, temporary files, etc.). 3 | # 4 | # For more help, visit the .dockerignore file reference guide at 5 | # https://docs.docker.com/go/build-context-dockerignore/ 6 | 7 | **/.classpath 8 | **/.dockerignore 9 | **/.env 10 | **/.git 11 | **/.gitignore 12 | **/.project 13 | **/.settings 14 | **/.toolstarget 15 | **/.vs 16 | **/.vscode 17 | **/.next 18 | **/.cache 19 | **/*.*proj.user 20 | **/*.dbmdl 21 | **/*.jfm 22 | **/charts 23 | **/docker-compose* 24 | **/compose.y*ml 25 | **/Dockerfile* 26 | **/node_modules 27 | **/npm-debug.log 28 | **/obj 29 | **/secrets.dev.yaml 30 | **/values.dev.yaml 31 | **/build 32 | **/dist 33 | LICENSE 34 | README.md 35 | -------------------------------------------------------------------------------- /getting-started-guides/.env: -------------------------------------------------------------------------------- 1 | OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net 2 | OTEL_EXPORTER_OTLP_HEADERS="api-key=YOUR_API_KEY_HERE" 3 | 4 | OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095 5 | OTEL_EXPORTER_OTLP_COMPRESSION=gzip 6 | OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 7 | OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=DELTA 8 | -------------------------------------------------------------------------------- /getting-started-guides/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with New Relic using OpenTelemetry 2 | 3 | The examples within this directory demonstrate how to send data to New Relic 4 | using OpenTelemetry. 5 | 6 | Each language directory illustrates how to add OpenTelemetry instrumentation to 7 | a simple web application (see [demo app spec](./demo-app-specification.md) for 8 | details) and configure OpenTelemetry for an optimal New Relic experience. This 9 | includes exporting over OTLP, limiting attributes according to New Relic ingest 10 | limits, and more. 11 | 12 | To get started quickly, you can use Docker Compose to spin up all the example 13 | applications. 14 | 15 | 1. First, open the [.env](./.env) file and configure your New Relic API key. 16 | If necessary, also change the 17 | [New Relic OTLP endpoint](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol) 18 | to match your region and needs. 19 | 20 | 2. Then, run Docker Compose 21 | 22 | ```shell 23 | docker compose up --build 24 | ``` 25 | 26 | 3. Lastly, go view your data in New Relic. Running using Docker Compose also 27 | starts a simple load generator, so data should be flowing. -------------------------------------------------------------------------------- /getting-started-guides/compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | dotnet: 3 | build: dotnet 4 | environment: 5 | - OTEL_SERVICE_NAME=getting-started-dotnet 6 | # No need to set service.instance.id because otel dot net generates random UUID 7 | #- OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 8 | - OTEL_EXPORTER_OTLP_ENDPOINT 9 | - OTEL_EXPORTER_OTLP_HEADERS 10 | - OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT 11 | - OTEL_EXPORTER_OTLP_COMPRESSION 12 | - OTEL_EXPORTER_OTLP_PROTOCOL 13 | - OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE 14 | ports: 15 | - 8080 16 | go: 17 | build: go 18 | environment: 19 | - OTEL_SERVICE_NAME=getting-started-go 20 | - OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 21 | - OTEL_EXPORTER_OTLP_ENDPOINT 22 | - OTEL_EXPORTER_OTLP_HEADERS 23 | - OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT 24 | - OTEL_EXPORTER_OTLP_COMPRESSION 25 | - OTEL_EXPORTER_OTLP_PROTOCOL 26 | - OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE 27 | ports: 28 | - 8080 29 | java: 30 | build: java 31 | environment: 32 | - OTEL_SERVICE_NAME=getting-started-java 33 | # No need to set service.instance.id because otel java agent generates random UUID 34 | # - OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 35 | - OTEL_EXPERIMENTAL_EXPORTER_OTLP_RETRY_ENABLED=true 36 | - OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION=BASE2_EXPONENTIAL_BUCKET_HISTOGRAM 37 | - OTEL_EXPERIMENTAL_RESOURCE_DISABLED_KEYS=process.command_args 38 | - OTEL_EXPORTER_OTLP_ENDPOINT 39 | - OTEL_EXPORTER_OTLP_HEADERS 40 | - OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT 41 | - OTEL_EXPORTER_OTLP_COMPRESSION 42 | - OTEL_EXPORTER_OTLP_PROTOCOL 43 | - OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE 44 | ports: 45 | - 8080 46 | javascript: 47 | build: javascript 48 | environment: 49 | - OTEL_SERVICE_NAME=getting-started-javascript 50 | - OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 51 | - OTEL_EXPORTER_OTLP_ENDPOINT 52 | - OTEL_EXPORTER_OTLP_HEADERS 53 | - OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT 54 | - OTEL_EXPORTER_OTLP_COMPRESSION 55 | - OTEL_EXPORTER_OTLP_PROTOCOL 56 | - OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE 57 | ports: 58 | - 8080 59 | python: 60 | build: python 61 | environment: 62 | - OTEL_SERVICE_NAME=getting-started-python 63 | - OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 64 | - OTEL_EXPORTER_OTLP_ENDPOINT 65 | - OTEL_EXPORTER_OTLP_HEADERS 66 | - OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT 67 | - OTEL_EXPORTER_OTLP_COMPRESSION 68 | - OTEL_EXPORTER_OTLP_PROTOCOL 69 | - OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE 70 | ports: 71 | - 8080 72 | ruby: 73 | build: ruby 74 | environment: 75 | - OTEL_SERVICE_NAME=getting-started-ruby 76 | - OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 77 | - OTEL_EXPORTER_OTLP_ENDPOINT 78 | - OTEL_EXPORTER_OTLP_HEADERS 79 | - OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT 80 | - OTEL_EXPORTER_OTLP_COMPRESSION 81 | - OTEL_EXPORTER_OTLP_PROTOCOL 82 | # Ruby doesn't support metrics yet 83 | # - OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE 84 | ports: 85 | - 8080 86 | rust: 87 | build: rust 88 | environment: 89 | - OTEL_SERVICE_NAME=getting-started-rust 90 | - OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 91 | - OTEL_EXPORTER_OTLP_ENDPOINT 92 | - OTEL_EXPORTER_OTLP_HEADERS 93 | - OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT 94 | - OTEL_EXPORTER_OTLP_COMPRESSION 95 | - OTEL_EXPORTER_OTLP_PROTOCOL 96 | - OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE 97 | ports: 98 | - 8080 99 | envoy: 100 | image: envoyproxy/envoy:v1.29.4 101 | ports: 102 | - "8080:8080" 103 | volumes: 104 | - ./supporting-files/envoy.yaml:/etc/envoy/envoy.yaml 105 | loadgenerator: 106 | image: python:3.12.3 107 | command: ["python", "/loadgenerator.py"] 108 | volumes: 109 | - ./supporting-files/loadgenerator.py:/loadgenerator.py 110 | depends_on: 111 | - dotnet 112 | - go 113 | - java 114 | - javascript 115 | - python 116 | - ruby 117 | - rust 118 | -------------------------------------------------------------------------------- /getting-started-guides/demo-app-specification.md: -------------------------------------------------------------------------------- 1 | # Specification for the Getting Started Guide demo applications 2 | 3 | ## Application 4 | 5 | 1. Must use port 8080 6 | 7 | 2. User must be able to access the endpoint http://localhost:8080/fibonacci?n=[input], and endpoint should return the following JSON response: 8 | * For valid input, `{"n":5,"result":5}` 9 | * For invalid input, `{"message":"n must be 1 <= n <= 90."}` 10 | 11 | 3. Must configure the OpenTelemetry SDK according to New Relic best practices. 12 | * Should use be kept up to date with latest version of OpenTelemetry API / SDK for language. 13 | * Should export data to New Relic using OTLP, preferring `http/protobuf` where there is no clear preference. 14 | * Should enable gzip compression. 15 | * Should configure metrics w/ delta temporality. 16 | * Should configure attribute limits. 17 | * Should use the standard environment variables for configuration rather than programmatic or other means: 18 | * `OTEL_SERVICE_NAME=getting-started->` 19 | * `OTEL_EXPORTER_OTLP_HEADERS=api-key=` 20 | * `OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net` 21 | * `OTEL_EXPORTER_OTLP_COMPRESSION=gzip` 22 | * `OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf` 23 | * `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=DELTA` 24 | * `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095` 25 | 26 | 4. Must accept input as `n`, with the valid input range as 1 <= n <= 90 27 | 5. The application must emit the following telemetry: 28 | * Traces 29 | * Root span 30 | * The root span may be emitted manually when the endpoint is invoked or preferrably by instrumentation if available in the language. 31 | * Child span 32 | * This span should represent the fibonacci calculation. 33 | * Span name = `fibonacci` 34 | * Span kind = internal 35 | * Attributes 36 | * `fibonacci.n`, with the value of `n` representing the user's input 37 | * `fibonacci.result`, with the value of `result` representing the result of the user’s input 38 | * Span event 39 | * When an error occurs, an exception event should be added as follows: 40 | * Span status = `ERROR` 41 | * Status description: `n must be 1 <= n <= 90.` 42 | * Metrics 43 | * Counter named`fibonacci.invocations` 44 | * Attributes 45 | * Counter description: `Measures the number of times the fibonacci method is invoked.` 46 | * `fibonacci.valid.n`, with a boolean value indicating whether `n` was valid or not 47 | * Logs 48 | * Output the following when `n` is valid: `Compute fibonacci(n) = result` 49 | * Output the following when `n` is invalid: `Failed to compute fibonacci(n)` 50 | 51 | ## Validation 52 | 53 | Use the following NRQL query to verify that data is flowing from all apps: 54 | 55 | ``` 56 | FROM Span, Metric, Log 57 | SELECT 58 | filter(count(*), WHERE eventType() = 'Log') as 'log_recprd_count', 59 | filter(count(*), WHERE eventType() = 'Metric') as 'metric_point_count', 60 | filter(count(*), WHERE eventType() = 'Span') as 'span_count' 61 | WHERE service.name LIKE 'getting%' AND metricName NOT LIKE 'apm%' FACET service.name SINCE 5 minute ago 62 | ``` 63 | 64 | This outputs a table of each service name, and columns containing the number of log records, metric data points, and spans. Each language should have a row, and the point counts should all be non-zero except: 65 | 66 | - `getting-started-ruby` doesn't have support for metrics or logs 67 | - `getting-started-javascript` doesn't have support for logs 68 | -------------------------------------------------------------------------------- /getting-started-guides/dotnet/Controllers/FibonacciController.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Diagnostics.Metrics; 3 | using Microsoft.AspNetCore.Mvc; 4 | using OpenTelemetry.Trace; 5 | 6 | namespace dotnet.Controllers; 7 | 8 | [ApiController] 9 | [Route("[controller]")] 10 | public class FibonacciController : ControllerBase 11 | { 12 | private const string AttributeNameN = "fibonacci.n"; 13 | private const string AttributeNameResult = "fibonacci.result"; 14 | private const string AttributeNameValid = "fibonacci.valid.n"; 15 | 16 | private static ActivitySource activitySource = new ActivitySource(nameof(dotnet)); 17 | private static Meter meter = new Meter(nameof(dotnet)); 18 | private static Counter fibonacciInvocations = meter.CreateCounter( 19 | name: "fibonacci.invocations", 20 | unit: null, 21 | description: "Measures the number of times the fibonacci method is invoked."); 22 | 23 | private readonly ILogger logger; 24 | 25 | public FibonacciController(ILogger logger) 26 | { 27 | this.logger = logger; 28 | } 29 | 30 | [HttpGet] 31 | public IActionResult Get(long n) 32 | { 33 | try 34 | { 35 | return Ok(new { n = n, result = Fibonacci(n) }); 36 | } 37 | catch (ArgumentOutOfRangeException ex) 38 | { 39 | Activity.Current?.SetStatus(Status.Error.WithDescription(ex.Message)); 40 | return BadRequest(new { message = ex.Message }); 41 | } 42 | } 43 | 44 | private long Fibonacci(long n) 45 | { 46 | using var activity = activitySource.StartActivity(nameof(Fibonacci)); 47 | activity?.SetTag(AttributeNameN, n); 48 | 49 | try 50 | { 51 | if (n < 1 || n > 90) 52 | { 53 | throw new ArgumentOutOfRangeException(nameof(n), n, "n must be between 1 and 90"); 54 | } 55 | 56 | var result = 1L; 57 | if (n > 2) 58 | { 59 | var a = 0L; 60 | var b = 1L; 61 | 62 | for (var i = 1; i < n; i++) 63 | { 64 | result = a + b; 65 | a = b; 66 | b = result; 67 | } 68 | } 69 | 70 | activity?.SetTag(AttributeNameResult, result); 71 | fibonacciInvocations.Add(1, new KeyValuePair(AttributeNameValid, true)); 72 | logger.LogInformation("Computed fib({n}) = {result}.", n, result); 73 | return result; 74 | } 75 | catch (ArgumentOutOfRangeException ex) 76 | { 77 | activity?.SetStatus(Status.Error.WithDescription(ex.Message)); 78 | activity?.RecordException(ex); 79 | fibonacciInvocations.Add(1, new KeyValuePair(AttributeNameValid, false)); 80 | logger.LogInformation("Failed to compute fib({n}).", n); 81 | throw; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /getting-started-guides/dotnet/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build 4 | 5 | COPY . /source 6 | 7 | WORKDIR /source 8 | 9 | ARG TARGETARCH 10 | 11 | # Build the application. 12 | # Leverage a cache mount to /root/.nuget/packages so that subsequent builds don't have to re-download packages. 13 | # If TARGETARCH is "amd64", replace it with "x64" - "x64" is .NET's canonical name for this and "amd64" doesn't 14 | # work in .NET 6.0. 15 | RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \ 16 | dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app 17 | 18 | FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS final 19 | 20 | WORKDIR /app 21 | 22 | COPY --from=build /app . 23 | 24 | USER $APP_UID 25 | 26 | EXPOSE 8080 27 | 28 | ENTRYPOINT ["dotnet", "dotnet.dll"] 29 | -------------------------------------------------------------------------------- /getting-started-guides/dotnet/OTEL_DIAGNOSTICS.json: -------------------------------------------------------------------------------- 1 | { 2 | "LogDirectory": "./logs", 3 | "FileSize": 32768, 4 | "LogLevel": "Warning" 5 | } 6 | -------------------------------------------------------------------------------- /getting-started-guides/dotnet/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.Metrics; 2 | using OpenTelemetry; 3 | using OpenTelemetry.Logs; 4 | using OpenTelemetry.Metrics; 5 | using OpenTelemetry.Resources; 6 | using OpenTelemetry.Trace; 7 | 8 | var builder = WebApplication.CreateBuilder(args); 9 | 10 | builder.Services.AddControllers(); 11 | 12 | // Configure the OpenTelemetry SDK for traces and metrics 13 | builder.Services.AddOpenTelemetry() 14 | .UseOtlpExporter() 15 | .ConfigureResource(resourceBuilder => 16 | { 17 | resourceBuilder 18 | .AddService(serviceName: "getting-started-dotnet", 19 | serviceVersion: typeof(Program).Assembly.GetName().Version?.ToString() ?? "unknown"); 20 | }) 21 | .WithTracing(tracerProviderBuilder => 22 | { 23 | tracerProviderBuilder 24 | .AddSource(nameof(dotnet)) 25 | .AddAspNetCoreInstrumentation(); 26 | }) 27 | .WithMetrics(meterProviderBuilder => 28 | { 29 | meterProviderBuilder 30 | .AddMeter(nameof(dotnet)) 31 | .AddAspNetCoreInstrumentation() 32 | .AddRuntimeInstrumentation() 33 | .AddView(instrument => 34 | { 35 | return instrument.GetType().GetGenericTypeDefinition() == typeof(Histogram<>) 36 | ? new Base2ExponentialBucketHistogramConfiguration() 37 | : null; 38 | }); 39 | }); 40 | 41 | // Configure the OpenTelemetry SDK for logs 42 | builder.Logging.ClearProviders(); 43 | builder.Logging.AddOpenTelemetry(options => 44 | { 45 | options.IncludeFormattedMessage = true; 46 | options.ParseStateValues = true; 47 | options.IncludeScopes = true; 48 | }); 49 | 50 | var app = builder.Build(); 51 | 52 | app.MapControllers(); 53 | 54 | app.Run(); 55 | -------------------------------------------------------------------------------- /getting-started-guides/dotnet/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started Guide - .NET 2 | 3 | This is a simple application instrumented with [OpenTelemetry .NET](https://github.com/open-telemetry/opentelemetry-dotnet). 4 | It demonstrates how to configure OpenTelemetry .NET to send data to New Relic. 5 | 6 | ## Requirements 7 | 8 | * [.NET SDK](https://dotnet.microsoft.com/en-us/download) 9 | * [A New Relic account](https://one.newrelic.com/) 10 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 11 | 12 | ## Running the application 13 | 14 | 1. Set the following environment variables to configure OpenTelemetry to send 15 | data to New Relic: 16 | 17 | ```shell 18 | export OTEL_SERVICE_NAME=getting-started-dotnet 19 | export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net 20 | export OTEL_EXPORTER_OTLP_HEADERS=api-key= 21 | export OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095 22 | export OTEL_EXPORTER_OTLP_COMPRESSION=gzip 23 | export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 24 | export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta 25 | ``` 26 | 27 | * If your account is based in the EU, set the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 28 | 29 | 2. Run the application with the following command and open 30 | [http://localhost:8080/fibonacci?n=1](http://localhost:8080/fibonacci?n=1) 31 | in your web browser to ensure it is working. 32 | 33 | ```shell 34 | dotnet run 35 | ``` 36 | 37 | 3. Experiment with providing different values for `n` in the query string. 38 | Valid values are between 1 and 90. Values outside this range cause an error 39 | which will show up in New Relic. 40 | -------------------------------------------------------------------------------- /getting-started-guides/dotnet/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Kestrel": { 3 | "Endpoints": { 4 | "Localhost": { 5 | "Url": "http://*:8080" 6 | } 7 | } 8 | }, 9 | "Logging": { 10 | "LogLevel": { 11 | "Default": "Information", 12 | "Microsoft.AspNetCore": "Warning" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /getting-started-guides/dotnet/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Kestrel": { 3 | "Endpoints": { 4 | "Localhost": { 5 | "Url": "http://*:8080" 6 | } 7 | } 8 | }, 9 | "Logging": { 10 | "LogLevel": { 11 | "Default": "Information", 12 | "Microsoft.AspNetCore": "Warning" 13 | } 14 | }, 15 | "AllowedHosts": "*" 16 | } 17 | -------------------------------------------------------------------------------- /getting-started-guides/dotnet/dotnet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /getting-started-guides/go/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | ARG GO_VERSION=1.22 4 | FROM --platform=$BUILDPLATFORM golang:${GO_VERSION} AS build 5 | WORKDIR /src 6 | 7 | RUN --mount=type=cache,target=/go/pkg/mod/ \ 8 | --mount=type=bind,source=go.sum,target=go.sum \ 9 | --mount=type=bind,source=go.mod,target=go.mod \ 10 | go mod download -x 11 | 12 | ARG TARGETARCH 13 | 14 | RUN --mount=type=cache,target=/go/pkg/mod/ \ 15 | --mount=type=bind,target=. \ 16 | CGO_ENABLED=0 GOARCH=$TARGETARCH go build -o /bin/server . 17 | 18 | FROM alpine:latest AS final 19 | 20 | RUN --mount=type=cache,target=/var/cache/apk \ 21 | apk --update add \ 22 | ca-certificates \ 23 | tzdata \ 24 | && \ 25 | update-ca-certificates 26 | 27 | ARG UID=10001 28 | RUN adduser \ 29 | --disabled-password \ 30 | --gecos "" \ 31 | --home "/nonexistent" \ 32 | --shell "/sbin/nologin" \ 33 | --no-create-home \ 34 | --uid "${UID}" \ 35 | appuser 36 | USER appuser 37 | 38 | COPY --from=build /bin/server /bin/ 39 | 40 | EXPOSE 8080 41 | 42 | ENTRYPOINT [ "/bin/server" ] 43 | -------------------------------------------------------------------------------- /getting-started-guides/go/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started Guide - Go 2 | 3 | This is a simple application instrumented with [OpenTelemetry Go](https://github.com/open-telemetry/opentelemetry-go). 4 | It demonstrates how to configure OpenTelemetry Go to send data to New Relic. 5 | 6 | ## Requirements 7 | 8 | * [Go](https://go.dev/dl) 9 | * [A New Relic account](https://one.newrelic.com/) 10 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 11 | 12 | ## Running the application 13 | 14 | 1. Set the following environment variables to configure OpenTelemetry to send 15 | data to New Relic: 16 | 17 | ```shell 18 | export OTEL_SERVICE_NAME=getting-started-go 19 | export OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 20 | export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net 21 | export OTEL_EXPORTER_OTLP_HEADERS=api-key= 22 | export OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095 23 | export OTEL_EXPORTER_OTLP_COMPRESSION=gzip 24 | export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 25 | export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta 26 | 27 | ``` 28 | 29 | * If your account is based in the EU, set the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 30 | 31 | 2. Run the application with the following command and open 32 | [http://localhost:8080/fibonacci?n=1](http://localhost:8080/fibonacci?n=1) 33 | in your web browser to ensure it is working. 34 | 35 | ```shell 36 | go run . 37 | ``` 38 | 39 | 3. Experiment with providing different values for `n` in the query string. 40 | Valid values are between 1 and 90. Values outside this range cause an error 41 | which will show up in New Relic. 42 | -------------------------------------------------------------------------------- /getting-started-guides/go/fibonacci.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "fmt" 8 | "net/http" 9 | "strconv" 10 | 11 | "go.opentelemetry.io/contrib/bridges/otelslog" 12 | "go.opentelemetry.io/otel" 13 | "go.opentelemetry.io/otel/attribute" 14 | "go.opentelemetry.io/otel/codes" 15 | "go.opentelemetry.io/otel/metric" 16 | "go.opentelemetry.io/otel/trace" 17 | ) 18 | 19 | const ( 20 | name = "fibonacci-calculator" 21 | ) 22 | 23 | var ( 24 | tracer = otel.Tracer(name) 25 | meter = otel.Meter(name) 26 | logger = otelslog.NewLogger(name) 27 | fibonacciInvocations metric.Int64Counter 28 | ) 29 | 30 | type fibonacciResponse struct { 31 | N int `json:"n,omitempty"` 32 | Result int `json:"result,omitempty"` 33 | Message string `json:"message,omitempty"` 34 | } 35 | 36 | func init() { 37 | var err error 38 | fibonacciInvocations, err = meter.Int64Counter( 39 | "fibonacci.invocations", 40 | metric.WithDescription("Measures the number of times the fibonacci method is invoked."), 41 | ) 42 | if err != nil { 43 | panic(err) 44 | } 45 | } 46 | 47 | func fibonacci(w http.ResponseWriter, r *http.Request) { 48 | n, err := parseNum(r) 49 | if err != nil { 50 | createHttpResponse(w, http.StatusBadRequest, fibonacciResponse{Message: err.Error()}) 51 | return 52 | } 53 | 54 | result, err := calculateFibonacci(r.Context(), n) 55 | if err != nil { 56 | createHttpResponse(w, http.StatusBadRequest, fibonacciResponse{Message: err.Error()}) 57 | return 58 | } 59 | 60 | createHttpResponse(w, http.StatusOK, fibonacciResponse{N: n, Result: result}) 61 | } 62 | 63 | func parseNum(r *http.Request) (int, error) { 64 | n, err := strconv.ParseInt(r.URL.Query().Get("n"), 10, 32) 65 | if err != nil { 66 | logger.Error(err.Error()) 67 | } 68 | return int(n), err 69 | } 70 | 71 | func calculateFibonacci(ctx context.Context, n int) (int, error) { 72 | ctx, span := tracer.Start(ctx, "fibonacci") 73 | defer span.End() 74 | 75 | span.SetAttributes(attribute.Int("fibonacci.n", n)) 76 | 77 | if n < 1 || n > 90 { 78 | err := errors.New("n must be between 1 and 90") 79 | span.SetStatus(codes.Error, err.Error()) 80 | span.RecordError(err, trace.WithStackTrace(true)) 81 | fibonacciInvocations.Add(ctx, 1, metric.WithAttributes(attribute.Bool("fibonacci.valid.n", false))) 82 | msg := fmt.Sprintf("Failed to compute fib(%d).", n) 83 | logger.InfoContext(ctx, msg, "fibonacci.n", n) 84 | return 0, err 85 | } 86 | 87 | var result = 1 88 | if n > 2 { 89 | var a = 0 90 | var b = 1 91 | 92 | for i := 1; i < n; i++ { 93 | result = a + b 94 | a = b 95 | b = result 96 | } 97 | } 98 | 99 | span.SetAttributes(attribute.Int("fibonacci.result", result)) 100 | fibonacciInvocations.Add(ctx, 1, metric.WithAttributes(attribute.Bool("fibonacci.valid.n", true))) 101 | msg := fmt.Sprintf("Computed fib(%d) = %d.", n, result) 102 | logger.InfoContext(ctx, msg, "fibonacci.n", n, "fibonacci.result", result) 103 | return result, nil 104 | } 105 | 106 | func createHttpResponse(w http.ResponseWriter, statusCode int, res fibonacciResponse) { 107 | w.Header().Set("Content-Type", "application/json") 108 | w.WriteHeader(statusCode) 109 | json.NewEncoder(w).Encode(res) 110 | } 111 | -------------------------------------------------------------------------------- /getting-started-guides/go/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/newrelic/newrelic-opentelemetry-examples/getting-started-guides/go 2 | 3 | go 1.22 4 | 5 | require ( 6 | go.opentelemetry.io/contrib/bridges/otelslog v0.2.0 7 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 8 | go.opentelemetry.io/contrib/instrumentation/runtime v0.52.0 9 | go.opentelemetry.io/otel v1.27.0 10 | go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0 11 | go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0 12 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 13 | go.opentelemetry.io/otel/log v0.3.0 14 | go.opentelemetry.io/otel/metric v1.27.0 15 | go.opentelemetry.io/otel/sdk v1.27.0 16 | go.opentelemetry.io/otel/sdk/log v0.3.0 17 | go.opentelemetry.io/otel/sdk/metric v1.27.0 18 | go.opentelemetry.io/otel/trace v1.27.0 19 | ) 20 | 21 | require ( 22 | github.com/cenkalti/backoff/v4 v4.3.0 // indirect 23 | github.com/felixge/httpsnoop v1.0.4 // indirect 24 | github.com/go-logr/logr v1.4.1 // indirect 25 | github.com/go-logr/stdr v1.2.2 // indirect 26 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect 27 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect 28 | go.opentelemetry.io/proto/otlp v1.2.0 // indirect 29 | golang.org/x/net v0.26.0 // indirect 30 | golang.org/x/sys v0.21.0 // indirect 31 | golang.org/x/text v0.16.0 // indirect 32 | google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect 33 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect 34 | google.golang.org/grpc v1.64.1 // indirect 35 | google.golang.org/protobuf v1.34.1 // indirect 36 | ) 37 | -------------------------------------------------------------------------------- /getting-started-guides/go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "log" 7 | "net" 8 | "net/http" 9 | "os" 10 | "os/signal" 11 | "time" 12 | 13 | "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" 14 | ) 15 | 16 | func main() { 17 | if err := run(); err != nil { 18 | log.Fatalln(err) 19 | } 20 | } 21 | 22 | func run() (err error) { 23 | // Handle SIGINT (CTRL+C) gracefully. 24 | ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) 25 | defer stop() 26 | 27 | // Set up OpenTelemetry. 28 | otelShutdown, err := setupOTelSDK(ctx) 29 | if err != nil { 30 | return 31 | } 32 | // Handle shutdown properly so nothing leaks. 33 | defer func() { 34 | err = errors.Join(err, otelShutdown(context.Background())) 35 | }() 36 | 37 | // Start HTTP server. 38 | srv := &http.Server{ 39 | Addr: ":8080", 40 | BaseContext: func(_ net.Listener) context.Context { return ctx }, 41 | ReadTimeout: time.Second, 42 | WriteTimeout: 10 * time.Second, 43 | Handler: newHTTPHandler(), 44 | } 45 | srvErr := make(chan error, 1) 46 | go func() { 47 | srvErr <- srv.ListenAndServe() 48 | }() 49 | 50 | // Wait for interruption. 51 | select { 52 | case err = <-srvErr: 53 | // Error when starting HTTP server. 54 | return 55 | case <-ctx.Done(): 56 | // Wait for first CTRL+C. 57 | // Stop receiving signal notifications as soon as possible. 58 | stop() 59 | } 60 | 61 | // When Shutdown is called, ListenAndServe immediately returns ErrServerClosed. 62 | err = srv.Shutdown(context.Background()) 63 | return 64 | } 65 | 66 | func newHTTPHandler() http.Handler { 67 | mux := http.NewServeMux() 68 | 69 | // handleFunc is a replacement for mux.HandleFunc 70 | // which enriches the handler's HTTP instrumentation with the pattern as the http.route. 71 | handleFunc := func(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) { 72 | // Configure the "http.route" for the HTTP instrumentation. 73 | handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc)) 74 | mux.Handle(pattern, handler) 75 | } 76 | 77 | // Register handlers. 78 | handleFunc("/fibonacci", fibonacci) 79 | 80 | // Add HTTP instrumentation for the whole server. 81 | handler := otelhttp.NewHandler(mux, "/") 82 | return handler 83 | } 84 | -------------------------------------------------------------------------------- /getting-started-guides/go/otel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "time" 7 | 8 | "go.opentelemetry.io/contrib/instrumentation/runtime" 9 | "go.opentelemetry.io/otel" 10 | "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" 11 | "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" 12 | "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" 13 | "go.opentelemetry.io/otel/log/global" 14 | "go.opentelemetry.io/otel/propagation" 15 | "go.opentelemetry.io/otel/sdk/log" 16 | "go.opentelemetry.io/otel/sdk/metric" 17 | "go.opentelemetry.io/otel/sdk/trace" 18 | ) 19 | 20 | // setupOTelSDK bootstraps the OpenTelemetry pipeline. 21 | // If it does not return an error, make sure to call shutdown for proper cleanup. 22 | func setupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, err error) { 23 | var shutdownFuncs []func(context.Context) error 24 | 25 | // shutdown calls cleanup functions registered via shutdownFuncs. 26 | // The errors from the calls are joined. 27 | // Each registered cleanup will be invoked once. 28 | shutdown = func(ctx context.Context) error { 29 | var err error 30 | for _, fn := range shutdownFuncs { 31 | err = errors.Join(err, fn(ctx)) 32 | } 33 | shutdownFuncs = nil 34 | return err 35 | } 36 | 37 | // handleErr calls shutdown for cleanup and makes sure that all errors are returned. 38 | handleErr := func(inErr error) { 39 | err = errors.Join(inErr, shutdown(ctx)) 40 | } 41 | 42 | // Set up propagator. 43 | prop := newPropagator() 44 | otel.SetTextMapPropagator(prop) 45 | 46 | // Set up trace provider. 47 | tracerProvider, err := newTraceProvider(ctx) 48 | if err != nil { 49 | handleErr(err) 50 | return 51 | } 52 | shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown) 53 | otel.SetTracerProvider(tracerProvider) 54 | 55 | // Set up meter provider. 56 | meterProvider, err := newMeterProvider(ctx) 57 | if err != nil { 58 | handleErr(err) 59 | return 60 | } 61 | shutdownFuncs = append(shutdownFuncs, meterProvider.Shutdown) 62 | otel.SetMeterProvider(meterProvider) 63 | 64 | runtime.Start(runtime.WithMeterProvider(meterProvider)) 65 | 66 | // Set up logger provider. 67 | loggerProvider, err := newLoggerProvider(ctx) 68 | if err != nil { 69 | handleErr(err) 70 | return 71 | } 72 | shutdownFuncs = append(shutdownFuncs, loggerProvider.Shutdown) 73 | global.SetLoggerProvider(loggerProvider) 74 | 75 | return 76 | } 77 | 78 | func newPropagator() propagation.TextMapPropagator { 79 | return propagation.NewCompositeTextMapPropagator( 80 | propagation.TraceContext{}, 81 | propagation.Baggage{}, 82 | ) 83 | } 84 | 85 | func newTraceProvider(ctx context.Context) (*trace.TracerProvider, error) { 86 | traceExporter, err := otlptracehttp.New(ctx) 87 | if err != nil { 88 | return nil, err 89 | } 90 | 91 | traceProvider := trace.NewTracerProvider( 92 | trace.WithBatcher(traceExporter), 93 | ) 94 | return traceProvider, nil 95 | } 96 | 97 | func newMeterProvider(ctx context.Context) (*metric.MeterProvider, error) { 98 | metricExporter, err := otlpmetrichttp.New(ctx) 99 | if err != nil { 100 | return nil, err 101 | } 102 | 103 | meterProvider := metric.NewMeterProvider( 104 | metric.WithReader( 105 | metric.NewPeriodicReader( 106 | metricExporter, 107 | metric.WithInterval(3*time.Second), 108 | ), 109 | ), 110 | ) 111 | return meterProvider, nil 112 | } 113 | 114 | func newLoggerProvider(ctx context.Context) (*log.LoggerProvider, error) { 115 | logExporter, err := otlploghttp.New(ctx) 116 | if err != nil { 117 | return nil, err 118 | } 119 | 120 | loggerProvider := log.NewLoggerProvider( 121 | log.WithProcessor(log.NewBatchProcessor(logExporter)), 122 | ) 123 | return loggerProvider, nil 124 | } 125 | -------------------------------------------------------------------------------- /getting-started-guides/java/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | FROM eclipse-temurin:17 as build 4 | 5 | COPY . /source 6 | 7 | WORKDIR /source 8 | 9 | RUN ./gradlew bootJar 10 | 11 | FROM eclipse-temurin:17 as final 12 | 13 | WORKDIR /app 14 | 15 | COPY --from=build /source/build/libs/getting-started-java.jar . 16 | COPY --from=build /source/build/agent/opentelemetry-javaagent.jar . 17 | 18 | ENTRYPOINT ["java", "-javaagent:opentelemetry-javaagent.jar", "-jar", "getting-started-java.jar"] 19 | 20 | EXPOSE 8080 21 | -------------------------------------------------------------------------------- /getting-started-guides/java/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started Guide - Java 2 | 3 | This is a simple application instrumented 4 | with [OpenTelemetry Java's](https://github.com/open-telemetry/opentelemetry-java) [automatic instrumentation javaagent](https://opentelemetry.io/docs/languages/java/automatic/). 5 | It demonstrates how to configure OpenTelemetry Java to send data to New Relic. 6 | 7 | ## Requirements 8 | 9 | * Java JDK 17+, due to the use of Spring Boot 3; [Java 8+ otherwise](https://github.com/open-telemetry/opentelemetry-java/blob/main/VERSIONING.md#language-version-compatibility) 10 | * [A New Relic account](https://one.newrelic.com/) 11 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 12 | 13 | ## Running the application 14 | 15 | 1. Set the following environment variables to configure OpenTelemetry to send 16 | data to New Relic: 17 | 18 | ```shell 19 | export OTEL_SERVICE_NAME=getting-started-java 20 | export OTEL_EXPERIMENTAL_EXPORTER_OTLP_RETRY_ENABLED=true 21 | export OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION=BASE2_EXPONENTIAL_BUCKET_HISTOGRAM 22 | export OTEL_EXPERIMENTAL_RESOURCE_DISABLED_KEYS=process.command_args 23 | export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net 24 | export OTEL_EXPORTER_OTLP_HEADERS=api-key= 25 | export OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095 26 | export OTEL_EXPORTER_OTLP_COMPRESSION=gzip 27 | export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 28 | export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta 29 | ``` 30 | 31 | * If your account is based in the EU, set the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 32 | 33 | 2. Run the application with the following command and open 34 | [http://localhost:8080/fibonacci?n=1](http://localhost:8080/fibonacci?n=1) 35 | in your web browser to ensure it is working. 36 | 37 | ```shell 38 | ./gradlew bootRun 39 | ``` 40 | 41 | 3. Experiment with providing different values for `n` in the query string. 42 | Valid values are between 1 and 90. Values outside this range cause an error 43 | which will show up in New Relic. 44 | -------------------------------------------------------------------------------- /getting-started-guides/java/build.gradle: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | 3 | plugins { 4 | id 'java' 5 | id 'com.diffplug.spotless' version '6.25.0' 6 | id 'org.springframework.boot' version '3.3.4' 7 | } 8 | 9 | java { 10 | toolchain { 11 | languageVersion = JavaLanguageVersion.of(17) 12 | } 13 | } 14 | 15 | spotless { 16 | java { 17 | googleJavaFormat() 18 | } 19 | } 20 | 21 | repositories { 22 | mavenCentral() 23 | } 24 | 25 | configurations { 26 | // Create a new configuration to hold the otel java agent 27 | agent 28 | } 29 | 30 | def otelInstrumentationVersion = "2.9.0-alpha"; 31 | 32 | dependencies { 33 | implementation platform(SpringBootPlugin.BOM_COORDINATES) 34 | implementation 'org.springframework.boot:spring-boot-starter-web' 35 | 36 | implementation platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:${otelInstrumentationVersion}") 37 | implementation("io.opentelemetry:opentelemetry-api") 38 | 39 | // Add OpenTelemetry java agent to the "agent" configuration we previously defined 40 | agent(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:${otelInstrumentationVersion}")) 41 | agent("io.opentelemetry.javaagent:opentelemetry-javaagent") 42 | } 43 | 44 | tasks.register("copyAgent", Copy) { 45 | from(configurations.agent.singleFile) 46 | into(layout.buildDirectory.dir('agent')) 47 | rename("opentelemetry-javaagent-.*\\.jar", "opentelemetry-javaagent.jar") 48 | } 49 | 50 | bootJar { 51 | archiveBaseName.set('getting-started-java') 52 | // Before running, copy the agent to a reliable place in the build dir 53 | dependsOn("copyAgent") 54 | } 55 | 56 | bootRun { 57 | // Before running, copy the agent to a reliable place in the build dir 58 | dependsOn("copyAgent") 59 | 60 | mainClass.set 'com.example.demo.Application' 61 | 62 | def agentPath = project.buildDir.toString() + "/agent/opentelemetry-javaagent.jar" 63 | jvmArgs = [ 64 | // Set the opentelemetry-java-instrumentation agent as the javaagent 65 | "-javaagent:${agentPath}" 66 | ] 67 | 68 | } 69 | -------------------------------------------------------------------------------- /getting-started-guides/java/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newrelic/newrelic-opentelemetry-examples/30519f2658f077a35c2cd85afea610b7e2b59f7b/getting-started-guides/java/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /getting-started-guides/java/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=1b6b558be93f29438d3df94b7dfee02e794b94d9aca4611a92cdb79b6b88e909 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip 5 | networkTimeout=10000 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /getting-started-guides/java/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /getting-started-guides/java/src/main/java/com/example/demo/Application.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.opentelemetry.api.GlobalOpenTelemetry; 4 | import io.opentelemetry.api.OpenTelemetry; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | 9 | @SpringBootApplication 10 | public class Application { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(Application.class, args); 14 | } 15 | 16 | @Bean 17 | public OpenTelemetry openTelemetry() { 18 | // OpenTelemetry javaagent will install the OpenTelemetrySdk and make the instance available via 19 | // GlobalOpenTelemetry.get(). Set this instance as a spring bean so we can add additional manual 20 | // instrumentation. 21 | return GlobalOpenTelemetry.get(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /getting-started-guides/java/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /getting-started-guides/javascript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /getting-started-guides/javascript/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | ARG NODE_VERSION=20.10.0 4 | 5 | FROM node:${NODE_VERSION}-alpine 6 | 7 | ENV NODE_ENV production 8 | 9 | WORKDIR /usr/src/app 10 | 11 | RUN --mount=type=bind,source=package.json,target=package.json \ 12 | --mount=type=bind,source=package-lock.json,target=package-lock.json \ 13 | --mount=type=cache,target=/root/.npm \ 14 | npm ci --omit=dev 15 | 16 | USER node 17 | 18 | COPY . . 19 | 20 | EXPOSE 8080 21 | 22 | CMD npm start 23 | -------------------------------------------------------------------------------- /getting-started-guides/javascript/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started Guide - JavaScript (Node.js) 2 | 3 | This is a simple application instrumented with [OpenTelemetry JavaScript](https://github.com/open-telemetry/opentelemetry-js). 4 | It demonstrates how to configure OpenTelemetry JavaScript to send data to New Relic. 5 | 6 | ## Requirements 7 | 8 | * [Node.js](https://nodejs.org/en/download/) 9 | * [A New Relic account](https://one.newrelic.com/) 10 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 11 | 12 | ## Running the application 13 | 14 | 1. Set the following environment variables to configure OpenTelemetry to send 15 | data to New Relic: 16 | 17 | ```shell 18 | export OTEL_SERVICE_NAME=getting-started-nodejs 19 | export OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 20 | export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net 21 | export OTEL_EXPORTER_OTLP_HEADERS=api-key= 22 | export OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095 23 | export OTEL_EXPORTER_OTLP_COMPRESSION=gzip 24 | export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 25 | export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta 26 | ``` 27 | 28 | * If your account is based in the EU, set the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 29 | 30 | 2. Run the following command to install dependencies: 31 | 32 | ```shell 33 | npm install 34 | ``` 35 | 36 | 3. Run the application with the following command and open 37 | [http://localhost:8080/fibonacci?n=1](http://localhost:8080/fibonacci?n=1) 38 | in your web browser to ensure it is working. 39 | 40 | ```shell 41 | npm start 42 | ``` 43 | 44 | 4. Experiment with providing different values for `n` in the query string. 45 | Valid values are between 1 and 90. Values outside this range cause an error 46 | which will show up in New Relic. 47 | -------------------------------------------------------------------------------- /getting-started-guides/javascript/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const opentelemetry = require("@opentelemetry/api"); 3 | 4 | const PORT = parseInt(process.env.PORT || '8080'); 5 | const app = express(); 6 | 7 | const tracer = opentelemetry.trace.getTracer("fibonacci"); 8 | const meter = opentelemetry.metrics.getMeter("fibonacci"); 9 | 10 | const fibonacciInvocations = meter.createCounter("fibonacci.invocations", { 11 | description: "Measures the number of times the fibonacci method is invoked.", 12 | }); 13 | 14 | app.get("/fibonacci", (req, res) => { 15 | try { 16 | const n = req.query.n 17 | res.json({ n: n, result: fibonacci(n) }); 18 | } catch (ex) { 19 | if (ex instanceof RangeError) { 20 | const span = opentelemetry.trace.getActiveSpan(); 21 | span.recordException(ex); 22 | 23 | // TODO: The opentelemetry-js express instrumentation undoes explicitly setting the span status. 24 | // For now, we will return a 500 status instead of 400. This forces an error to show up in the error inbox. 25 | // span.setStatus({ code: opentelemetry.SpanStatusCode.ERROR, message: ex.message }); 26 | // res.status(400).json({ error: ex.message }); 27 | res.status(500).json({ error: ex.message }); 28 | } else { 29 | throw ex; 30 | } 31 | } 32 | }); 33 | 34 | function fibonacci(n) { 35 | return tracer.startActiveSpan("fibonacci", (span) => { 36 | span.setAttribute("fibonacci.n", n); 37 | 38 | try { 39 | n = parseInt(n); 40 | 41 | if (n < 1 || n > 90 || isNaN(n)) { 42 | throw new RangeError("n must be between 1 and 90"); 43 | } 44 | 45 | var result = 1; 46 | if (n > 2) { 47 | var a = 0; 48 | var b = 1; 49 | 50 | for (var i = 1; i < n; i++) { 51 | result = a + b; 52 | a = b; 53 | b = result; 54 | } 55 | } 56 | 57 | span.setAttribute("fibonacci.result", result); 58 | fibonacciInvocations.add(1, { "fibonacci.valid.n": true }); 59 | return result; 60 | } catch (ex) { 61 | span.setStatus({ code: opentelemetry.SpanStatusCode.ERROR, message: ex.message }); 62 | span.recordException(ex); 63 | fibonacciInvocations.add(1, { "fibonacci.valid.n": false }); 64 | throw ex; 65 | } finally { 66 | span.end(); 67 | } 68 | }); 69 | }; 70 | 71 | app.listen(PORT, () => { 72 | console.log(`Listening for requests on http://localhost:${PORT}`); 73 | }); 74 | -------------------------------------------------------------------------------- /getting-started-guides/javascript/instrumentation.js: -------------------------------------------------------------------------------- 1 | const opentelemetry = require('@opentelemetry/sdk-node'); 2 | const { 3 | getNodeAutoInstrumentations, 4 | } = require('@opentelemetry/auto-instrumentations-node'); 5 | const { 6 | OTLPTraceExporter, 7 | } = require('@opentelemetry/exporter-trace-otlp-proto'); 8 | const { 9 | OTLPMetricExporter, 10 | } = require('@opentelemetry/exporter-metrics-otlp-proto'); 11 | const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics'); 12 | const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api'); 13 | 14 | diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO); 15 | 16 | const sdk = new opentelemetry.NodeSDK({ 17 | traceExporter: new OTLPTraceExporter(), 18 | metricReader: new PeriodicExportingMetricReader({ 19 | exporter: new OTLPMetricExporter(), 20 | }), 21 | instrumentations: [getNodeAutoInstrumentations()], 22 | }); 23 | 24 | sdk.start(); 25 | -------------------------------------------------------------------------------- /getting-started-guides/javascript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "newrelic-opentelemetry-examples-nodejs", 3 | "scripts": { 4 | "start": "node --require ./instrumentation.js app.js" 5 | }, 6 | "dependencies": { 7 | "@opentelemetry/api": "^1.8.0", 8 | "@opentelemetry/auto-instrumentations-node": "^0.45.0", 9 | "@opentelemetry/exporter-metrics-otlp-proto": "^0.51.0", 10 | "@opentelemetry/exporter-trace-otlp-proto": "^0.51.0", 11 | "@opentelemetry/sdk-metrics": "^1.24.0", 12 | "@opentelemetry/sdk-node": "^0.51.0", 13 | "@opentelemetry/sdk-trace-node": "^1.24.0", 14 | "express": "^4.19.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /getting-started-guides/python/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | ARG PYTHON_VERSION=3.12.2 4 | FROM python:${PYTHON_VERSION}-slim as base 5 | 6 | # Prevents Python from writing pyc files. 7 | # ENV PYTHONDONTWRITEBYTECODE=1 8 | 9 | # Keeps Python from buffering stdout and stderr to avoid situations where 10 | # the application crashes without emitting any logs due to buffering. 11 | # ENV PYTHONUNBUFFERED=1 12 | 13 | WORKDIR /app 14 | 15 | # Create a non-privileged user that the app will run under. 16 | # See https://docs.docker.com/go/dockerfile-user-best-practices/ 17 | ARG UID=10001 18 | RUN adduser \ 19 | --disabled-password \ 20 | --gecos "" \ 21 | --home "/nonexistent" \ 22 | --shell "/sbin/nologin" \ 23 | --no-create-home \ 24 | --uid "${UID}" \ 25 | appuser 26 | 27 | # Download dependencies as a separate step to take advantage of Docker's caching. 28 | # Leverage a cache mount to /root/.cache/pip to speed up subsequent builds. 29 | # Leverage a bind mount to requirements.txt to avoid having to copy them into 30 | # into this layer. 31 | RUN --mount=type=cache,target=/root/.cache/pip \ 32 | --mount=type=bind,source=requirements.txt,target=requirements.txt \ 33 | python -m pip install -r requirements.txt 34 | 35 | ENV OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true 36 | 37 | RUN opentelemetry-bootstrap -a install 38 | 39 | COPY . . 40 | 41 | # Switch to the non-privileged user to run the application. 42 | USER appuser 43 | 44 | EXPOSE 8080 45 | 46 | CMD opentelemetry-instrument --logs_exporter otlp python3 app.py 47 | -------------------------------------------------------------------------------- /getting-started-guides/python/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started Guide - Python 2 | 3 | This is a simple application instrumented with [OpenTelemetry Python](https://github.com/open-telemetry/opentelemetry-python). 4 | It demonstrates how to configure OpenTelemetry Python to send data to New Relic. 5 | 6 | ## Requirements 7 | 8 | * [Python](https://www.python.org/downloads/) 9 | * [A New Relic account](https://one.newrelic.com/) 10 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 11 | 12 | ## Running the application 13 | 14 | 1. Set the following environment variables to configure OpenTelemetry to send 15 | data to New Relic: 16 | 17 | ```shell 18 | export OTEL_SERVICE_NAME=getting-started-python 19 | export OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 20 | export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true 21 | export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net 22 | export OTEL_EXPORTER_OTLP_HEADERS=api-key= 23 | export OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095 24 | export OTEL_EXPORTER_OTLP_COMPRESSION=gzip 25 | export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 26 | export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta 27 | ``` 28 | 29 | * If your account is based in the EU, set the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 30 | 31 | 2. Run the following command to install dependencies: 32 | 33 | ```shell 34 | python -m pip install -r requirements.txt 35 | opentelemetry-bootstrap -a install 36 | ``` 37 | 38 | 3. Run the application with the following command and open 39 | [http://localhost:8080/fibonacci?n=1](http://localhost:8080/fibonacci?n=1) 40 | in your web browser to ensure it is working. 41 | 42 | ```shell 43 | opentelemetry-instrument --logs_exporter otlp python3 app.py 44 | ``` 45 | 46 | 4. Experiment with providing different values for `n` in the query string. 47 | Valid values are between 1 and 90. Values outside this range cause an error 48 | which will show up in New Relic. 49 | -------------------------------------------------------------------------------- /getting-started-guides/python/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, request 2 | import logging 3 | from opentelemetry import metrics 4 | from opentelemetry import trace 5 | from opentelemetry.trace.status import Status, StatusCode 6 | 7 | fib_counter = metrics.get_meter("opentelemetry.instrumentation.custom").create_counter("fibonacci.invocations", unit="1", description="Measures the number of times the fibonacci method is invoked.") 8 | 9 | logging.basicConfig(level=logging.DEBUG) 10 | 11 | app = Flask(__name__) 12 | 13 | @app.route("/fibonacci") 14 | @trace.get_tracer("opentelemetry.instrumentation.custom").start_as_current_span("/fibonacci") 15 | def fibonacci(): 16 | args = request.args 17 | x = int(args.get("n")) 18 | error_message = "n must be 1 <= n <= 90." 19 | trace.get_current_span().set_attribute("fibonacci.n", x) 20 | 21 | try: 22 | assert 1 <= x <= 90 23 | array = [0, 1] 24 | for n in range(2, x + 1): 25 | array.append(array[n - 1] + array[n - 2]) 26 | 27 | trace.get_current_span().set_attribute("fibonacci.result", array[x]) 28 | fib_counter.add(1, {"fibonacci.valid.n": "true"}) 29 | logging.info("Compute fibonacci(" + str(x) + ") = " + str(array[x])) 30 | return jsonify(n=x, result=array[x]) 31 | 32 | except AssertionError: 33 | trace.get_current_span().record_exception(exception=Exception, attributes={"exception.type": "AssertionError", "exception.message": error_message}) 34 | trace.get_current_span().set_status(Status(StatusCode.ERROR, error_message)) 35 | fib_counter.add(1, {"fibonacci.valid.n": "false"}) 36 | logging.error("Failed to compute fibonacci(" + str(x) + ")") 37 | return jsonify({"message": error_message}) 38 | 39 | app.run(host='0.0.0.0', port=8080) 40 | -------------------------------------------------------------------------------- /getting-started-guides/python/requirements.txt: -------------------------------------------------------------------------------- 1 | blinker==1.8.2 2 | certifi==2024.7.4 3 | charset-normalizer==3.3.2 4 | click==8.1.7 5 | Deprecated==1.2.14 6 | Flask==3.0.3 7 | googleapis-common-protos==1.63.0 8 | idna==3.7 9 | importlib-metadata==7.0.0 10 | itsdangerous==2.2.0 11 | Jinja2==3.1.4 12 | MarkupSafe==2.1.5 13 | opentelemetry-api==1.24.0 14 | opentelemetry-distro==0.45b0 15 | opentelemetry-exporter-otlp-proto-common==1.24.0 16 | opentelemetry-exporter-otlp-proto-http==1.24.0 17 | opentelemetry-instrumentation==0.45b0 18 | opentelemetry-proto==1.24.0 19 | opentelemetry-sdk==1.24.0 20 | opentelemetry-semantic-conventions==0.45b0 21 | protobuf==4.25.3 22 | requests==2.32.3 23 | setuptools==70.0.0 24 | typing_extensions==4.12.0 25 | urllib3==2.2.2 26 | Werkzeug==3.0.3 27 | wrapt==1.16.0 28 | zipp==3.19.1 29 | -------------------------------------------------------------------------------- /getting-started-guides/ruby/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | FROM ruby:3.2.2 as base 4 | 5 | WORKDIR /usr/src/app 6 | 7 | COPY . . 8 | 9 | RUN bundle install 10 | 11 | EXPOSE 8080 12 | 13 | CMD bundle exec rackup 14 | -------------------------------------------------------------------------------- /getting-started-guides/ruby/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | ruby '3.2.2' 6 | 7 | gem 'sinatra', '~> 3.0.6' 8 | gem 'thin', '~> 1.8.2' 9 | 10 | gem 'opentelemetry-sdk', '~> 1.2.1' 11 | gem 'opentelemetry-exporter-otlp', '~> 0.25.0' 12 | gem 'opentelemetry-instrumentation-all', '~> 0.39.1' 13 | -------------------------------------------------------------------------------- /getting-started-guides/ruby/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started Guide - Ruby 2 | 3 | This is a simple application instrumented with [OpenTelemetry Ruby](https://github.com/open-telemetry/opentelemetry-ruby). 4 | It demonstrates how to configure OpenTelemetry Ruby to send data to New Relic. 5 | 6 | ## Requirements 7 | 8 | * [Ruby 3.2.2](https://www.ruby-lang.org/en) 9 | * [A New Relic account](https://one.newrelic.com/) 10 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 11 | 12 | ## Running the application 13 | 14 | 1. Set the following environment variables to configure OpenTelemetry to send 15 | data to New Relic: 16 | 17 | ```shell 18 | export OTEL_SERVICE_NAME=getting-started-ruby 19 | export OTEL_RESOURCE_ATTRIBUTES=service.instance.id=123 20 | export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net 21 | export OTEL_EXPORTER_OTLP_HEADERS=api-key= 22 | export OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095 23 | export OTEL_EXPORTER_OTLP_COMPRESSION=gzip 24 | export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 25 | ``` 26 | 27 | * If your account is based in the EU, set the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 28 | 29 | 2. Run the following command to install dependencies: 30 | 31 | ```shell 32 | bundle install 33 | ``` 34 | 35 | 3. Run the application with the following command and open 36 | [http://localhost:8080/fibonacci?n=1](http://localhost:8080/fibonacci?n=1) 37 | in your web browser to ensure it is working. 38 | 39 | ```shell 40 | bundle exec rackup 41 | ``` 42 | 43 | 4. Experiment with providing different values for `n` in the query string. 44 | Valid values are between 1 and 90. Values outside this range cause an error 45 | which will show up in New Relic. 46 | -------------------------------------------------------------------------------- /getting-started-guides/ruby/app.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | require 'sinatra/base' 5 | require_relative 'fibonacci' 6 | 7 | class App < Sinatra::Base 8 | set :show_exceptions, :after_handler 9 | 10 | get '/' do 11 | redirect '/fibonacci' 12 | end 13 | 14 | get '/fibonacci' do 15 | content_type :json 16 | 17 | n = params['n'].to_i 18 | 19 | result = Fibonacci.calculate(n) 20 | 21 | JSON.generate({ n: n, result: result }) 22 | end 23 | 24 | error Fibonacci::RangeError do 25 | status 400 26 | OpenTelemetry::Trace.current_span.record_exception(env['sinatra.error']) 27 | env['sinatra.error'].message 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /getting-started-guides/ruby/config.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler' 4 | 5 | Bundler.require 6 | 7 | require './opentelemetry' 8 | require './fibonacci' 9 | require './app' 10 | 11 | Rack::Handler.default.run(App, :Host => "0.0.0.0", :Port => 8080) 12 | -------------------------------------------------------------------------------- /getting-started-guides/ruby/fibonacci.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Fibonacci 4 | MIN = 1 5 | MAX = 90 6 | 7 | class RangeError < StandardError 8 | MESSAGE = JSON.generate(message: 'n must be 1 <= n <= 90.') 9 | 10 | def initialize(msg = MESSAGE) 11 | super(msg) 12 | end 13 | end 14 | 15 | def self.calculate(n) 16 | APP_TRACER.in_span('fibonacci', kind: :internal) do 17 | raise RangeError, RangeError::MESSAGE unless n.between?(MIN, MAX) 18 | 19 | first_num, second_num = [0, 1] 20 | 21 | (n - 1).times do 22 | first_num, second_num = second_num, first_num + second_num 23 | end 24 | 25 | current_span = OpenTelemetry::Trace.current_span 26 | current_span.add_attributes({ 27 | 'fibonacci.n' => n, 28 | 'fibonacci.result' => first_num, 29 | }) 30 | 31 | first_num 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /getting-started-guides/ruby/opentelemetry.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'opentelemetry/sdk' 4 | require 'opentelemetry/exporter/otlp' 5 | require 'opentelemetry/instrumentation/all' 6 | 7 | OpenTelemetry::SDK.configure do |c| 8 | # c.use_all() # enables all instrumentation! 9 | c.use 'OpenTelemetry::Instrumentation::Sinatra' 10 | c.use 'OpenTelemetry::Instrumentation::Rack' 11 | c.use 'OpenTelemetry::Instrumentation::Net::HTTP' 12 | end 13 | 14 | APP_TRACER = OpenTelemetry.tracer_provider.tracer('AppTracer') 15 | -------------------------------------------------------------------------------- /getting-started-guides/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fibonacci" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | actix-web = "4.8.0" 8 | actix-web-opentelemetry = { version = "0.19.0", features = ["metrics"] } 9 | opentelemetry = "0.24.0" 10 | opentelemetry-otlp = { version = "0.17.0", features = ["tls-roots", "gzip-tonic"] } 11 | opentelemetry_sdk = { version = "0.24.1", features = ["rt-tokio-current-thread"] } 12 | serde = { version = "1.0.205", features = ["derive"] } 13 | tonic = "0.12.1" 14 | -------------------------------------------------------------------------------- /getting-started-guides/rust/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | ARG RUST_VERSION=1.79.0 4 | ARG APP_NAME=fibonacci 5 | 6 | FROM rust:${RUST_VERSION}-alpine AS build 7 | ARG APP_NAME 8 | WORKDIR /app 9 | 10 | RUN apk add --no-cache clang lld musl-dev git 11 | 12 | # Build the application. 13 | # Leverage a cache mount to /usr/local/cargo/registry/ 14 | # for downloaded dependencies, a cache mount to /usr/local/cargo/git/db 15 | # for git repository dependencies, and a cache mount to /app/target/ for 16 | # compiled dependencies which will speed up subsequent builds. 17 | # Leverage a bind mount to the src directory to avoid having to copy the 18 | # source code into the container. Once built, copy the executable to an 19 | # output directory before the cache mounted /app/target is unmounted. 20 | RUN --mount=type=bind,source=src,target=src \ 21 | --mount=type=bind,source=Cargo.toml,target=Cargo.toml \ 22 | --mount=type=bind,source=Cargo.lock,target=Cargo.lock \ 23 | --mount=type=cache,target=/app/target/ \ 24 | --mount=type=cache,target=/usr/local/cargo/git/db \ 25 | --mount=type=cache,target=/usr/local/cargo/registry/ \ 26 | cargo build --locked --release && \ 27 | cp ./target/release/$APP_NAME /bin/server 28 | 29 | FROM alpine:3.18 AS final 30 | 31 | # Create a non-privileged user that the app will run under. 32 | # See https://docs.docker.com/go/dockerfile-user-best-practices/ 33 | ARG UID=10001 34 | RUN adduser \ 35 | --disabled-password \ 36 | --gecos "" \ 37 | --home "/nonexistent" \ 38 | --shell "/sbin/nologin" \ 39 | --no-create-home \ 40 | --uid "${UID}" \ 41 | appuser 42 | USER appuser 43 | 44 | COPY --from=build /bin/server /bin/ 45 | 46 | EXPOSE 8080 47 | 48 | CMD ["/bin/server"] 49 | -------------------------------------------------------------------------------- /getting-started-guides/rust/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started Guide - Rust 2 | 3 | This is a simple application instrumented with [OpenTelemetry Rust](https://github.com/open-telemetry/opentelemetry-rust). 4 | It demonstrates how to configure OpenTelemetry Rust to send data to New Relic. 5 | 6 | ## Requirements 7 | 8 | * [Rust](https://www.rust-lang.org/tools/install) 9 | * [A New Relic account](https://one.newrelic.com/) 10 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 11 | 12 | ## Running the application 13 | 14 | 1. Set the following environment variables to configure OpenTelemetry to send 15 | data to New Relic: 16 | 17 | ```shell 18 | export OTEL_SERVICE_NAME=getting-started-rust 19 | export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net 20 | export OTEL_EXPORTER_OTLP_HEADERS=api-key= 21 | export OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095 22 | export OTEL_EXPORTER_OTLP_COMPRESSION=gzip 23 | export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf 24 | export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta 25 | ``` 26 | 27 | * If your account is based in the EU, set the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 28 | 29 | 2. Run the application with the following command and open 30 | [http://localhost:8080/fibonacci?n=1](http://localhost:8080/fibonacci?n=1) 31 | in your web browser to ensure it is working. 32 | 33 | ```shell 34 | cargo run fibonacci 35 | ``` 36 | 37 | 3. Experiment with providing different values for `n` in the query string. 38 | Valid values are between 1 and 90. Values outside this range cause an error 39 | which will show up in New Relic. 40 | -------------------------------------------------------------------------------- /getting-started-guides/supporting-files/loadgenerator.py: -------------------------------------------------------------------------------- 1 | import os, random, sys, signal, time 2 | 3 | def signal_handler(signal, frame): 4 | print("\nCtrl-C received. Stopping load generator.") 5 | sys.exit(0) 6 | 7 | signal.signal(signal.SIGINT, signal_handler) 8 | 9 | languages = ["dotnet", "go", "java", "javascript", "python", "ruby", "rust"] 10 | 11 | while True: 12 | n = random.randint(1, 100) 13 | for language in languages: 14 | os.system(f"curl http://{language}:8080/fibonacci?n={n} > /dev/null 2>&1") 15 | time.sleep(1) 16 | -------------------------------------------------------------------------------- /java/micrometer-shim/README.md: -------------------------------------------------------------------------------- 1 | This page has been relocated to [./other-examples/java/micrometer-shim](../../other-examples/java/micrometer-shim). 2 | -------------------------------------------------------------------------------- /other-examples/collector/confluentcloud/k8s/collector.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: nr-confluent 6 | --- 7 | apiVersion: v1 8 | kind: ConfigMap 9 | metadata: 10 | name: collector-config 11 | namespace: nr-confluent 12 | labels: 13 | app.kubernetes.io/name: collector-config 14 | data: 15 | collector-config: | 16 | receivers: 17 | prometheus: 18 | config: 19 | scrape_configs: 20 | - job_name: "confluent" 21 | scrape_interval: 60s # Do not go any lower than this or you'll hit rate limits 22 | static_configs: 23 | - targets: ["api.telemetry.confluent.cloud"] 24 | scheme: https 25 | basic_auth: 26 | username: $CONFLUENT_API_KEY 27 | password: $CONFLUENT_API_SECRET 28 | metrics_path: /v2/metrics/cloud/export 29 | params: 30 | "resource.kafka.id": 31 | - $CONFLUENT_CLUSTER_ID 32 | # OPTIONAL - You can include monitoring for Confluent connectors or schema registry's by including the ID here. 33 | #"resource.connector.id": 34 | # - $CONFLUENT_CONNECTOR_ID 35 | #"resource.schema_registry.id": 36 | # - $CONFLUENT_SCHEMA_REGISTRY_ID 37 | 38 | processors: 39 | batch: 40 | 41 | exporters: 42 | otlphttp: 43 | endpoint: ${NEW_RELIC_OTLP_ENDPOINT} 44 | headers: 45 | api-key: ${NEW_RELIC_API_KEY} 46 | 47 | service: 48 | pipelines: 49 | metrics: 50 | receivers: [prometheus] 51 | processors: [batch] 52 | exporters: [otlphttp] 53 | --- 54 | apiVersion: v1 55 | kind: Pod 56 | metadata: 57 | name: collector 58 | namespace: nr-confluent 59 | labels: 60 | app.kubernetes.io/name: collector 61 | spec: 62 | containers: 63 | - name: collector 64 | image: otel/opentelemetry-collector-contrib:0.98.0 65 | env: 66 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 67 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 68 | - name: NEW_RELIC_OTLP_ENDPOINT 69 | value: https://otlp.nr-data.net/ 70 | # The New Relic API key used to authenticate export requests. 71 | # Defined in secrets.yaml 72 | - name: NEW_RELIC_API_KEY 73 | valueFrom: 74 | secretKeyRef: 75 | name: nr-confluent-secret 76 | key: NEW_RELIC_API_KEY 77 | # The Confluent API key. 78 | # Defined in secrets.yaml 79 | - name: CONFLUENT_API_KEY 80 | valueFrom: 81 | secretKeyRef: 82 | name: nr-confluent-secret 83 | key: CONFLUENT_API_KEY 84 | # The Confluent API secret. 85 | # Defined in secrets.yaml 86 | - name: CONFLUENT_API_SECRET 87 | valueFrom: 88 | secretKeyRef: 89 | name: nr-confluent-secret 90 | key: CONFLUENT_API_SECRET 91 | # Set your Confluent Cluster ID here. 92 | # docs: https://docs.confluent.io/confluent-cli/current/command-reference/kafka/cluster/confluent_kafka_cluster_list.html 93 | - name: CONFLUENT_CLUSTER_ID 94 | value: 95 | # OPTIONAL: Set your Confluent Schema Registry ID here, and uncomment reference in .receivers.prometheus.config.scrape_configs[0].params 96 | # docs: https://docs.confluent.io/confluent-cli/current/command-reference/kafka/cluster/confluent_kafka_cluster_list.html 97 | #- name: CONFLUENT_SCHEMA_REGISTRY_ID 98 | # value: 99 | # OPTIONAL: Set your Confluent Connector ID here, and uncomment reference in .receivers.prometheus.config.scrape_configs[0].params 100 | # docs: https://docs.confluent.io/confluent-cli/current/command-reference/kafka/cluster/confluent_kafka_cluster_list.html 101 | #- name: CONFLUENT_CONNECTOR_ID 102 | # value: 103 | volumeMounts: 104 | - name: collector-config-vol 105 | mountPath: /etc/otelcol-contrib 106 | volumes: 107 | - name: collector-config-vol 108 | configMap: 109 | name: collector-config 110 | items: 111 | - key: collector-config 112 | path: config.yaml 113 | -------------------------------------------------------------------------------- /other-examples/collector/confluentcloud/k8s/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nr-confluent-secret 5 | namespace: nr-confluent 6 | stringData: 7 | # New Relic API key to authenticate the export requests. 8 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 9 | NEW_RELIC_API_KEY: 10 | # Set your authentication keys for the Confluent Cloud metrics API. 11 | # docs: https://docs.confluent.io/cloud/current/monitoring/metrics-api.html 12 | CONFLUENT_API_KEY: 13 | CONFLUENT_API_SECRET: 14 | -------------------------------------------------------------------------------- /other-examples/collector/docker/.env: -------------------------------------------------------------------------------- 1 | # New Relic API key to authenticate the call. 2 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 3 | NEW_RELIC_API_KEY= 4 | 5 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 6 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/get-started/opentelemetry-set-up-your-app/#review-settings 7 | NEW_RELIC_OTLP_ENDPOINT=https://otlp.nr-data.net/ 8 | 9 | # User ID used to run the collector. Must have permission to access the docker socket. 10 | # Obtain for a given user via "id -g " 11 | HOST_USER_ID=0 12 | -------------------------------------------------------------------------------- /other-examples/collector/docker/config.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | docker_stats: 3 | metrics: 4 | container.cpu.usage.total: 5 | enabled: true 6 | container.cpu.throttling_data.periods: 7 | enabled: true 8 | container.cpu.throttling_data.throttled_periods: 9 | enabled: true 10 | container.cpu.utilization: 11 | enabled: true 12 | container.memory.usage.limit: 13 | enabled: true 14 | container.memory.usage.total: 15 | enabled: true 16 | container.memory.percent: 17 | enabled: true 18 | container.blockio.io_service_bytes_recursive: 19 | enabled: true 20 | container.network.io.usage.rx_bytes: 21 | enabled: true 22 | container.network.io.usage.tx_bytes: 23 | enabled: true 24 | container.network.io.usage.rx_dropped: 25 | enabled: true 26 | container.network.io.usage.tx_dropped: 27 | enabled: true 28 | container.network.io.usage.rx_errors: 29 | enabled: true 30 | container.network.io.usage.tx_errors: 31 | enabled: true 32 | container.network.io.usage.rx_packets: 33 | enabled: true 34 | container.network.io.usage.tx_packets: 35 | enabled: true 36 | container.pids.count: 37 | enabled: true 38 | 39 | processors: 40 | batch: 41 | 42 | resourcedetection: 43 | detectors: [env, system, gcp, ec2, azure] 44 | 45 | exporters: 46 | otlphttp: 47 | endpoint: ${NEW_RELIC_OTLP_ENDPOINT} 48 | headers: 49 | api-key: ${NEW_RELIC_API_KEY} 50 | 51 | service: 52 | pipelines: 53 | metrics: 54 | receivers: [docker_stats] 55 | processors: [resourcedetection, batch] 56 | exporters: [otlphttp] 57 | 58 | -------------------------------------------------------------------------------- /other-examples/collector/docker/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | collector: 4 | image: otel/opentelemetry-collector-contrib:0.98.0 5 | volumes: 6 | - ./config.yaml:/etc/otelcol-contrib/config.yaml 7 | - /var/run/docker.sock:/var/run/docker.sock 8 | # Set the user id used to run the collector. HOST_USER_ID is defined in .env, and MUST have permission to access the docker socket. 9 | user: ${HOST_USER_ID} 10 | # Expose the env vars defined in .env 11 | environment: 12 | - NEW_RELIC_API_KEY 13 | - NEW_RELIC_OTLP_ENDPOINT 14 | # host.id is required for New Relic. 15 | # Optionally manually set it if one of the resource detectors in config.yaml is unable to identify it. 16 | # - OTEL_RESOURCE_ATTRIBUTES=host.id= 17 | 18 | # Run a dummy nginx image to generate more interesting data. 19 | nginx: 20 | image: nginx 21 | -------------------------------------------------------------------------------- /other-examples/collector/hcp-consul/k8s/collector.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: nr-hcp-consul 6 | --- 7 | apiVersion: v1 8 | kind: ConfigMap 9 | metadata: 10 | name: collector-config 11 | namespace: nr-hcp-consul 12 | labels: 13 | app.kubernetes.io/name: collector-config 14 | data: 15 | collector-config: | 16 | receivers: 17 | prometheus: 18 | config: 19 | scrape_configs: 20 | - job_name: "hcp-consul" 21 | scrape_interval: 60s # Do not go any lower than this or you'll hit rate limits 22 | scheme: https 23 | dns_sd_configs: 24 | - names: 25 | - "${HCP_ACCESS_URL}" 26 | type: "A" 27 | port: 443 28 | authorization: 29 | credentials: "${HCP_ACCESS_TOKEN}" 30 | metrics_path: "/v1/agent/metrics" 31 | # Skipping TLS verification based on Consul docs(https://developer.hashicorp.com/hcp/docs/consul/monitor/metrics#prometheus). 32 | tls_config: 33 | insecure_skip_verify: true 34 | 35 | processors: 36 | batch: 37 | 38 | exporters: 39 | otlphttp: 40 | endpoint: ${NEW_RELIC_OTLP_ENDPOINT} 41 | headers: 42 | api-key: ${NEW_RELIC_API_KEY} 43 | 44 | service: 45 | pipelines: 46 | metrics: 47 | receivers: [prometheus] 48 | processors: [batch] 49 | exporters: [otlphttp] 50 | --- 51 | apiVersion: v1 52 | kind: Pod 53 | metadata: 54 | name: collector 55 | namespace: nr-hcp-consul 56 | labels: 57 | app.kubernetes.io/name: collector 58 | spec: 59 | containers: 60 | - name: collector 61 | image: otel/opentelemetry-collector-contrib:0.98.0 62 | env: 63 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 64 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 65 | - name: NEW_RELIC_OTLP_ENDPOINT 66 | value: https://otlp.nr-data.net/ 67 | # The New Relic API key used to authenticate export requests. 68 | # Defined in secrets.yaml 69 | - name: NEW_RELIC_API_KEY 70 | valueFrom: 71 | secretKeyRef: 72 | name: nr-hcp-consul-secret 73 | key: NEW_RELIC_API_KEY 74 | # The HCP Consul access token. 75 | # Defined in secrets.yaml 76 | - name: HCP_ACCESS_TOKEN 77 | valueFrom: 78 | secretKeyRef: 79 | name: nr-hcp-consul-secret 80 | key: HCP_ACCESS_TOKEN 81 | # The HCP Consul access url. 82 | # docs: https://developer.hashicorp.com/hcp/docs/consul/hcp-managed/access#get-access-url 83 | - name: HCP_ACCESS_URL 84 | value: 85 | volumeMounts: 86 | - name: collector-config-vol 87 | mountPath: /etc/otelcol-contrib 88 | volumes: 89 | - name: collector-config-vol 90 | configMap: 91 | name: collector-config 92 | items: 93 | - key: collector-config 94 | path: config.yaml 95 | -------------------------------------------------------------------------------- /other-examples/collector/hcp-consul/k8s/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nr-hcp-consul-secret 5 | namespace: nr-hcp-consul 6 | stringData: 7 | # New Relic API key to authenticate the export requests. 8 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 9 | NEW_RELIC_API_KEY: 10 | # Set your HCP Access Token API Key. 11 | # docs: https://developer.hashicorp.com/hcp/docs/consul/hcp-managed/access#generate-admin-token 12 | HCP_ACCESS_TOKEN: 13 | -------------------------------------------------------------------------------- /other-examples/collector/hivemq/.gitignore: -------------------------------------------------------------------------------- 1 | hivemq-prometheus-extension -------------------------------------------------------------------------------- /other-examples/collector/hivemq/download-prometheus-extension.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | curl --silent --location https://github.com/hivemq/hivemq-prometheus-extension/releases/download/4.0.10/hivemq-prometheus-extension-4.0.10.zip \ 4 | --output ./hivemq-prometheus-extension.zip 5 | unzip ./hivemq-prometheus-extension.zip -d . 6 | rm ./hivemq-prometheus-extension.zip 7 | -------------------------------------------------------------------------------- /other-examples/collector/hivemq/k8s/collector.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: nr-hivemq 6 | --- 7 | apiVersion: v1 8 | kind: ConfigMap 9 | metadata: 10 | name: collector-config 11 | namespace: nr-hivemq 12 | labels: 13 | app.kubernetes.io/name: collector-config 14 | data: 15 | collector-config: | 16 | receivers: 17 | prometheus: 18 | config: 19 | scrape_configs: 20 | - job_name: "hivemq" 21 | static_configs: 22 | - targets: [ "${HIVEMQ_SERVICE_HOST}:${HIVEMQ_SERVICE_PORT_METRICS}" ] 23 | metrics_path: /metrics 24 | 25 | processors: 26 | batch: 27 | 28 | exporters: 29 | otlphttp: 30 | endpoint: ${NEW_RELIC_OTLP_ENDPOINT} 31 | headers: 32 | api-key: ${NEW_RELIC_API_KEY} 33 | 34 | service: 35 | pipelines: 36 | metrics: 37 | receivers: [prometheus] 38 | processors: [batch] 39 | exporters: [otlphttp] 40 | --- 41 | apiVersion: v1 42 | kind: Pod 43 | metadata: 44 | name: collector 45 | namespace: nr-hivemq 46 | labels: 47 | app.kubernetes.io/name: collector 48 | spec: 49 | containers: 50 | - name: collector 51 | image: otel/opentelemetry-collector-contrib:0.98.0 52 | env: 53 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 54 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 55 | - name: NEW_RELIC_OTLP_ENDPOINT 56 | value: https://otlp.nr-data.net/ 57 | # The New Relic API key used to authenticate export requests. 58 | # Defined in secrets.yaml 59 | - name: NEW_RELIC_API_KEY 60 | valueFrom: 61 | secretKeyRef: 62 | name: nr-hivemq-secret 63 | key: NEW_RELIC_API_KEY 64 | volumeMounts: 65 | - name: collector-config-vol 66 | mountPath: /etc/otelcol-contrib 67 | volumes: 68 | - name: collector-config-vol 69 | configMap: 70 | name: collector-config 71 | items: 72 | - key: collector-config 73 | path: config.yaml 74 | -------------------------------------------------------------------------------- /other-examples/collector/hivemq/k8s/hivemq.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: hivemq 6 | namespace: nr-hivemq 7 | labels: 8 | app.kubernetes.io/name: hivemq 9 | spec: 10 | containers: 11 | - name: hivemq 12 | image: hivemq/hivemq-ce:2024.5 13 | volumeMounts: 14 | - name: hivemq-prometheus-extension 15 | mountPath: /opt/hivemq/extensions/hivemq-prometheus-extension 16 | ports: 17 | - containerPort: 9399 18 | volumes: 19 | # This volume contains the hivemq-prometheus-extension, which is downloaded via ../download-prometheus-extension.sh 20 | # Replace with the fully qualified path to the root of the hivemq example. 21 | - name: hivemq-prometheus-extension 22 | hostPath: 23 | path: /hivemq-prometheus-extension 24 | type: Directory 25 | --- 26 | apiVersion: v1 27 | kind: Service 28 | metadata: 29 | name: hivemq 30 | namespace: nr-hivemq 31 | labels: 32 | app.kubernetes.io/name: hivemq 33 | spec: 34 | ports: 35 | - name: metrics 36 | port: 9399 37 | protocol: TCP 38 | selector: 39 | app.kubernetes.io/name: hivemq 40 | -------------------------------------------------------------------------------- /other-examples/collector/hivemq/k8s/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nr-hivemq-secret 5 | namespace: nr-hivemq 6 | stringData: 7 | # New Relic API key to authenticate the export requests. 8 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 9 | NEW_RELIC_API_KEY: 10 | -------------------------------------------------------------------------------- /other-examples/collector/host-monitoring/k8s/_namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: nr-host-monitoring 6 | -------------------------------------------------------------------------------- /other-examples/collector/host-monitoring/k8s/adservice.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: adservice 6 | namespace: nr-host-monitoring 7 | labels: 8 | app.kubernetes.io/name: adservice 9 | spec: 10 | containers: 11 | - name: adservice 12 | image: otel/demo:1.10.0-adservice 13 | env: 14 | - name: AD_SERVICE_PORT 15 | value: "8080" 16 | - name: HOST_IP 17 | valueFrom: 18 | fieldRef: 19 | fieldPath: status.hostIP 20 | - name: OTEL_EXPORTER_OTLP_ENDPOINT 21 | value: http://$(HOST_IP):4318 22 | - name: OTEL_SERVICE_NAME 23 | value: adservice 24 | ports: 25 | - containerPort: 8080 26 | -------------------------------------------------------------------------------- /other-examples/collector/host-monitoring/k8s/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nr-host-monitoring-secret 5 | namespace: nr-host-monitoring 6 | stringData: 7 | # New Relic API key to authenticate the export requests. 8 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 9 | NEW_RELIC_API_KEY: 10 | -------------------------------------------------------------------------------- /other-examples/collector/nr-config/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Collector with OTLP Export to New Relic 2 | 3 | This example demonstrates how to run the OpenTelemetry Collector and configure it to export telemetry to New Relic. The `docker-compose.yaml` file configures the collector via `otel-config.yaml`. 4 | 5 | ## Run 6 | 7 | Set the following environment variables: 8 | * `NEW_RELIC_API_KEY=` 9 | * Replace `` with your [Account License Key](https://one.newrelic.com/launcher/api-keys-ui.launcher). 10 | 11 | Then run: 12 | ```shell 13 | docker-compose -f docker-compose.yaml up 14 | ``` 15 | 16 | ## Collector configuration 17 | 18 | The collector is configured with the following components. 19 | 20 | ### Receivers 21 | * The [OTLP receiver](https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver/otlpreceiver). This receiver is configured to accept OTLP data over gRPC on port `4317`. Configure applications to export over OTLP to `http://localhost:4317`. 22 | * The [Fluent Forward receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/fluentforwardreceiver). This receiver listens on port `8006`. You can forward application logs to it using the [Fluentd logging driver](https://docs.docker.com/config/containers/logging/fluentd/). 23 | 24 | ### Processors 25 | * The [Batch processor](https://github.com/open-telemetry/opentelemetry-collector/tree/main/processor/batchprocessor). This processor helps limit the number of outgoing requests. See our [best practices](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-best-practices-batching/) regarding batching data. 26 | * The [Cumulative to Delta processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/cumulativetodeltaprocessor). This processor converts histograms and monotonic sums received in cumulative temporality to delta temporality. New Relic currently rejects cumulative histograms and monotonic sums, so this processor is necessary. However, New Relic [cumulative metric support](https://docs.newrelic.com/docs/data-apis/understand-data/metric-data/cumulative-metrics/) is currently in preview. Contact your account representative to participate in the preview. For more information on how New Relic ingests metrics, take a look at our [best practices](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-best-practices-metrics). 27 | * The [Transform processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/transformprocessor). This processor is configured to truncate attributes on spans and logs to adhere to New Relic's attribute length limits. Attributes over the limit will cause data to be dropped. Note that the transform processor has not been configured to truncate attributes on metrics. Long metric attributes should be unusual. Truncating metric attributes can be complex and may require metrics to be reaggregated. The transform processor does not perform any reaggregation. 28 | 29 | ### Exporters 30 | * The [OTLP HTTP exporter](https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter/otlphttpexporter). This exporter is configured to send data to New Relic. See [documentation](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/get-started/opentelemetry-set-up-your-app/) for more information about New Relic OTLP support. 31 | * The [Debug exporter](https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter/debugexporter). This exporter logs data the collector processes to standard out. It can be useful for troubleshooting. 32 | -------------------------------------------------------------------------------- /other-examples/collector/nr-config/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | otel-collector: 4 | image: otel/opentelemetry-collector-contrib:0.121.0 5 | volumes: 6 | - ./otel-config.yaml:/otel-config.yaml 7 | command: ["--config=/otel-config.yaml", "${OTELCOL_ARGS}"] 8 | environment: 9 | LOG_EXPORTER_LOG_VERBOSITY: "detailed" 10 | NEW_RELIC_API_KEY: "${NEW_RELIC_API_KEY}" 11 | ports: 12 | - "4317:4317" # grpc 13 | - "4318:4318" # http 14 | - "13133:13133" # health 15 | - "8006:8006" # fluentdforward 16 | - "8006:8006/udp" # fluentforward 17 | -------------------------------------------------------------------------------- /other-examples/collector/nr-config/otel-config.yaml: -------------------------------------------------------------------------------- 1 | extensions: 2 | health_check: {} 3 | receivers: 4 | otlp: 5 | protocols: 6 | grpc: 7 | endpoint: otel-collector:4317 8 | http: 9 | endpoint: otel-collector:4318 10 | fluentforward: 11 | endpoint: 0.0.0.0:8006 12 | processors: 13 | batch: 14 | # Will convert all monotonic, cumulative sums to monotonic, delta sums 15 | cumulativetodelta: 16 | transform: 17 | trace_statements: 18 | - truncate_all(span.attributes, 4095) 19 | - truncate_all(resource.attributes, 4095) 20 | log_statements: 21 | - truncate_all(log.attributes, 4095) 22 | - truncate_all(resource.attributes, 4095) 23 | metric_statements: 24 | - truncate_all(datapoint.attributes, 4095) 25 | - truncate_all(resource.attributes, 4095) 26 | exporters: 27 | debug: 28 | verbosity: ${LOG_EXPORTER_LOG_VERBOSITY} 29 | otlphttp: 30 | endpoint: https://otlp.nr-data.net 31 | headers: 32 | api-key: ${NEW_RELIC_API_KEY} 33 | service: 34 | extensions: [health_check] 35 | pipelines: 36 | metrics: 37 | receivers: [otlp] 38 | processors: [cumulativetodelta, transform, batch] 39 | exporters: [debug, otlphttp] 40 | traces: 41 | receivers: [otlp] 42 | processors: [transform, batch] 43 | exporters: [debug, otlphttp] 44 | logs: 45 | receivers: [otlp, fluentforward] 46 | processors: [transform, batch] 47 | exporters: [debug, otlphttp] 48 | -------------------------------------------------------------------------------- /other-examples/collector/nrdot-host-monitoring/README.md: -------------------------------------------------------------------------------- 1 | # Monitoring Hosts with OpenTelemetry Collector 2 | 3 | This example demonstrates monitoring hosts with the [NRDOT collector](https://docs.newrelic.com/docs/opentelemetry/nrdot/nrdot-intro/), using the [host metrics receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/hostmetricsreceiver) and sending the data to New Relic via OTLP. 4 | 5 | Functionally this example is similar to the [host monitoring example](../host-monitoring/README.md) but using the pre-packaged configuration of the NRDOT collector. 6 | 7 | 8 | ## Requirements 9 | 10 | * You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. Docker desktop [includes a standalone Kubernetes server and client](https://docs.docker.com/desktop/kubernetes/) which is useful for local testing. 11 | * [A New Relic account](https://one.newrelic.com/) 12 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 13 | 14 | ## Running the example 15 | 16 | 1. Update the `NEW_RELIC_API_KEY` value in [secrets.yaml](./k8s/secrets.yaml) to your New Relic license key. 17 | ```yaml 18 | # ...omitted for brevity 19 | stringData: 20 | # New Relic API key to authenticate the export requests. 21 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 22 | NEW_RELIC_API_KEY: 23 | ``` 24 | 25 | * Note, be careful to avoid inadvertent secret sharing when modifying `secrets.yaml`. To ignore changes to this file from git, run `git update-index --skip-worktree k8s/secrets.yaml`. 26 | 27 | * If your account is based in the EU, update the `NEW_RELIC_OTLP_ENDPOINT` value in [collector.yaml](./k8s/collector.yaml) the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 28 | 29 | ```yaml 30 | # ...omitted for brevity 31 | env: 32 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 33 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 34 | - name: NEW_RELIC_OTLP_ENDPOINT 35 | value: https://otlp.eu01.nr-data.net 36 | ``` 37 | 38 | 3. Run the application with the following command. 39 | 40 | ```shell 41 | kubectl apply -f k8s/ 42 | ``` 43 | 44 | * When finished, cleanup resources with the following command. This is also useful to reset if modifying configuration. 45 | 46 | ```shell 47 | kubectl delete -f k8s/ 48 | ``` 49 | 50 | ## Viewing your data 51 | 52 | To review your host data in New Relic, navigate to "New Relic -> All Entities -> Hosts" and click on the instance with name corresponding to the collector pod name to view the instance summary. Use [NRQL](https://docs.newrelic.com/docs/query-your-data/explore-query-data/get-started/introduction-querying-new-relic-data/) to perform ad-hoc analysis. 53 | 54 | ``` 55 | FROM Metric SELECT uniques(metricName) WHERE otel.library.name like '%/receiver/hostmetricsreceiver/%' 56 | ``` 57 | 58 | See [get started with querying](https://docs.newrelic.com/docs/query-your-data/explore-query-data/get-started/introduction-querying-new-relic-data/) for additional details on querying data in New Relic. 59 | -------------------------------------------------------------------------------- /other-examples/collector/nrdot-host-monitoring/k8s/_namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: nr-nrdot-host-monitoring 6 | -------------------------------------------------------------------------------- /other-examples/collector/nrdot-host-monitoring/k8s/adservice.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: adservice 6 | namespace: nr-nrdot-host-monitoring 7 | labels: 8 | app.kubernetes.io/name: adservice 9 | spec: 10 | containers: 11 | - name: adservice 12 | image: otel/demo:1.10.0-adservice 13 | env: 14 | - name: AD_SERVICE_PORT 15 | value: "8080" 16 | - name: HOST_IP 17 | valueFrom: 18 | fieldRef: 19 | fieldPath: status.hostIP 20 | - name: OTEL_EXPORTER_OTLP_ENDPOINT 21 | value: http://$(HOST_IP):4318 22 | - name: OTEL_SERVICE_NAME 23 | value: adservice 24 | ports: 25 | - containerPort: 8080 26 | -------------------------------------------------------------------------------- /other-examples/collector/nrdot-host-monitoring/k8s/collector.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: apps/v1 4 | kind: DaemonSet 5 | metadata: 6 | name: collector 7 | namespace: nr-nrdot-host-monitoring 8 | labels: 9 | app.kubernetes.io/name: collector 10 | spec: 11 | selector: 12 | matchLabels: 13 | name: collector 14 | template: 15 | metadata: 16 | labels: 17 | name: collector 18 | spec: 19 | containers: 20 | - name: collector 21 | image: newrelic/nrdot-collector-host:1.0.2 22 | args: 23 | - --config=/etc/nrdot-collector-host/config.yaml 24 | # The root path of the host filesystem. This is required by the hostmetrics receiver and not set by default in the nrdot-collector-host config. 25 | - "--config=yaml:receivers::hostmetrics::root_path: /hostfs" 26 | # By default, the otlp receiver is configured to listen on localhost at port 4318, we need to change this to listen on the pod IP. 27 | - "--config=yaml:receivers::otlp::protocols::http::endpoint: ${env:MY_POD_IP}:4318" 28 | env: 29 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 30 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 31 | - name: OTEL_EXPORTER_OTLP_ENDPOINT 32 | value: https://otlp.nr-data.net/ 33 | # The New Relic API key used to authenticate export requests. 34 | # Defined in secrets.yaml 35 | - name: NEW_RELIC_LICENSE_KEY 36 | valueFrom: 37 | secretKeyRef: 38 | name: nr-nrdot-host-monitoring-secret 39 | key: NEW_RELIC_API_KEY 40 | - name: NODE_NAME 41 | valueFrom: 42 | fieldRef: 43 | fieldPath: spec.nodeName 44 | # host.id is required for NewRelic host entity synthesis and relationships, but is not included by any resourcedetection detector when running with docker on macOS. 45 | # We enabled the "env" resource detector and set host.id to the name of the node via env var. 46 | - name: OTEL_RESOURCE_ATTRIBUTES 47 | value: host.id=$(NODE_NAME) 48 | - name: MY_POD_IP 49 | valueFrom: 50 | fieldRef: 51 | fieldPath: status.podIP 52 | volumeMounts: 53 | - name: hostfs 54 | mountPath: /hostfs 55 | readOnly: true 56 | mountPropagation: HostToContainer 57 | ports: 58 | - containerPort: 4318 59 | hostPort: 4318 60 | volumes: 61 | - name: hostfs 62 | hostPath: 63 | path: / 64 | -------------------------------------------------------------------------------- /other-examples/collector/nrdot-host-monitoring/k8s/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nr-nrdot-host-monitoring-secret 5 | namespace: nr-nrdot-host-monitoring 6 | stringData: 7 | # New Relic API key to authenticate the export requests. 8 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 9 | NEW_RELIC_API_KEY: 10 | -------------------------------------------------------------------------------- /other-examples/collector/prometheus/README.md: -------------------------------------------------------------------------------- 1 | # Monitoring Prometheus with OpenTelemetry Collector 2 | 3 | This simple example demonstrates monitoring prometheus sources with the [OpenTelemetry collector](https://opentelemetry.io/docs/collector/), using the [prometheus receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/prometheusreceiver) and sending the data to New Relic via OTLP. A simple prometheus data generator is configured to generate dummy metrics scraped by prometheus receiver. 4 | 5 | ## Requirements 6 | 7 | * You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. Docker desktop [includes a standalone Kubernetes server and client](https://docs.docker.com/desktop/kubernetes/) which is useful for local testing. 8 | * [A New Relic account](https://one.newrelic.com/) 9 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 10 | 11 | ## Running the example 12 | 13 | 1. Update the `NEW_RELIC_API_KEY` value in [secrets.yaml](./k8s/secrets.yaml) to your New Relic license key. 14 | 15 | ```yaml 16 | # ...omitted for brevity 17 | stringData: 18 | # New Relic API key to authenticate the export requests. 19 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 20 | NEW_RELIC_API_KEY: 21 | ``` 22 | 23 | * Note, be careful to avoid inadvertent secret sharing when modifying `secrets.yaml`. To ignore changes to this file from git, run `git update-index --skip-worktree k8s/secrets.yaml`. 24 | 25 | * If your account is based in the EU, update the `NEW_RELIC_OTLP_ENDPOINT` value in [collector.yaml](./k8s/collector.yaml) the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 26 | 27 | ```yaml 28 | # ...omitted for brevity 29 | env: 30 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 31 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 32 | - name: NEW_RELIC_OTLP_ENDPOINT 33 | value: https://otlp.eu01.nr-data.net 34 | ``` 35 | 36 | 2. Run the application with the following command. 37 | 38 | ```shell 39 | kubectl apply -f k8s/ 40 | ``` 41 | 42 | * When finished, cleanup resources with the following command. This is also useful to reset if modifying configuration. 43 | 44 | ```shell 45 | kubectl delete -f k8s/ 46 | ``` 47 | 48 | ## Viewing your data 49 | 50 | To review your statsd data in New Relic, navigate to "New Relic -> Query Your Data". To list the metrics reported, query for: 51 | 52 | ``` 53 | FROM Metric SELECT uniques(metricName) WHERE otel.library.name = 'otelcol/prometheusreceiver' LIMIT MAX 54 | ``` 55 | 56 | See [get started with querying](https://docs.newrelic.com/docs/query-your-data/explore-query-data/get-started/introduction-querying-new-relic-data/) for additional details on querying data in New Relic. 57 | 58 | ## Additional notes 59 | 60 | This example monitors a simple prometheus data generator instance defined in [prometheus-data-generator.yaml](./k8s/prometheus-data-generator.yaml). To use in production, you'll need to modify the `.receivers.prometheus.config.scrape_configs` value in [collector.yaml](k8s/collector.yaml) ConfigMap to point at your prometheus sources. 61 | 62 | The prometheus receiver includes `service.name` and `service.instance.id` resource attributes derived from job name and target configured in `.receivers.prometheus.config.scraep_configs`. As documented [here](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-best-practices-resources/#services), New Relic considers any data with `service.name` as a service despite the fact that not all prometheus data sources are services. As a result, you can find a `prometheus_data_generator` entity under "New Relic -> All Entities -> Services - OpenTelemetry", although the panels will not contain data because the scraped metrics do not represent APM data. 63 | -------------------------------------------------------------------------------- /other-examples/collector/prometheus/k8s/collector.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: nr-prometheus 6 | --- 7 | apiVersion: v1 8 | kind: ConfigMap 9 | metadata: 10 | name: collector-config 11 | namespace: nr-prometheus 12 | labels: 13 | app.kubernetes.io/name: collector-config 14 | data: 15 | collector-config: | 16 | receivers: 17 | prometheus: 18 | config: 19 | scrape_configs: 20 | - job_name: prometheus_data_generator 21 | static_configs: 22 | # Connect to prometheus data generator pod defined in prometheus-data-generator.yaml using service env vars set by k8s 23 | - targets: [ "${PROMETHEUS_DATA_GENERATOR_SERVICE_HOST}:${PROMETHEUS_DATA_GENERATOR_SERVICE_PORT}" ] 24 | metrics_path: /metrics 25 | 26 | processors: 27 | batch: 28 | 29 | exporters: 30 | otlphttp: 31 | endpoint: ${NEW_RELIC_OTLP_ENDPOINT} 32 | headers: 33 | api-key: ${NEW_RELIC_API_KEY} 34 | 35 | service: 36 | pipelines: 37 | metrics: 38 | receivers: [prometheus] 39 | processors: [batch] 40 | exporters: [otlphttp] 41 | --- 42 | apiVersion: v1 43 | kind: Pod 44 | metadata: 45 | name: collector 46 | namespace: nr-prometheus 47 | labels: 48 | app.kubernetes.io/name: collector 49 | spec: 50 | containers: 51 | - name: collector 52 | image: otel/opentelemetry-collector-contrib:0.98.0 53 | env: 54 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 55 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 56 | - name: NEW_RELIC_OTLP_ENDPOINT 57 | value: https://otlp.nr-data.net/ 58 | # The New Relic API key used to authenticate export requests. 59 | # Defined in secrets.yaml 60 | - name: NEW_RELIC_API_KEY 61 | valueFrom: 62 | secretKeyRef: 63 | name: nr-prometheus-secret 64 | key: NEW_RELIC_API_KEY 65 | volumeMounts: 66 | - name: collector-config-vol 67 | mountPath: /etc/otelcol-contrib 68 | volumes: 69 | - name: collector-config-vol 70 | configMap: 71 | name: collector-config 72 | items: 73 | - key: collector-config 74 | path: config.yaml 75 | -------------------------------------------------------------------------------- /other-examples/collector/prometheus/k8s/prometheus-data-generator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: prometheus-data-generator-config 6 | namespace: nr-prometheus 7 | data: 8 | config: | 9 | --- 10 | config: 11 | - name: number_of_fruits 12 | description: The number of fruits we have. 13 | type: gauge 14 | labels: [name, color] 15 | sequence: 16 | - time: 5 17 | values: 0-20 18 | operation: inc 19 | labels: 20 | name: apple 21 | color: red 22 | - eval_time: 5 23 | operation: set 24 | labels: 25 | name: apple 26 | color: red 27 | - time: 5 28 | eval_time: 1 29 | values: 0-20 30 | operation: inc 31 | labels: 32 | name: apple 33 | color: green 34 | - time: 5 35 | eval_time: 1 36 | values: 0-5 37 | operation: dec 38 | labels: 39 | name: apple 40 | color: green 41 | - time: 5 42 | eval_time: 1 43 | value: 3 44 | operation: inc 45 | labels: 46 | name: apple 47 | color: yellow 48 | --- 49 | apiVersion: v1 50 | kind: Pod 51 | metadata: 52 | name: prometheus-data-generator 53 | namespace: nr-prometheus 54 | labels: 55 | app.kubernetes.io/name: prometheus-data-generator 56 | spec: 57 | containers: 58 | - name: prometheus-data-generator 59 | image: littleangryclouds/prometheus-data-generator:0.2 60 | env: 61 | - name: PDG_CONFIG 62 | value: /pdg/config.yaml 63 | volumeMounts: 64 | - name: prometheus-data-generator-config-vol 65 | mountPath: /pdg/ 66 | ports: 67 | - containerPort: 9000 68 | volumes: 69 | - name: prometheus-data-generator-config-vol 70 | configMap: 71 | name: prometheus-data-generator-config 72 | items: 73 | - key: config 74 | path: config.yaml 75 | --- 76 | apiVersion: v1 77 | kind: Service 78 | metadata: 79 | name: prometheus-data-generator 80 | namespace: nr-prometheus 81 | labels: 82 | app.kubernetes.io/name: prometheus-data-generator 83 | spec: 84 | ports: 85 | - port: 9000 86 | protocol: TCP 87 | selector: 88 | app.kubernetes.io/name: prometheus-data-generator 89 | -------------------------------------------------------------------------------- /other-examples/collector/prometheus/k8s/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nr-prometheus-secret 5 | namespace: nr-prometheus 6 | stringData: 7 | # New Relic API key to authenticate the export requests. 8 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 9 | NEW_RELIC_API_KEY: 10 | 11 | -------------------------------------------------------------------------------- /other-examples/collector/redis/README.md: -------------------------------------------------------------------------------- 1 | # Monitoring Redis with OpenTelemetry Collector 2 | 3 | This simple example demonstrates monitoring redis with the [OpenTelemetry collector](https://opentelemetry.io/docs/collector/), using the [redis receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/redisreceiver) and sending the data to New Relic via OTLP. 4 | 5 | ## Requirements 6 | 7 | * You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. Docker desktop [includes a standalone Kubernetes server and client](https://docs.docker.com/desktop/kubernetes/) which is useful for local testing. 8 | * [A New Relic account](https://one.newrelic.com/) 9 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 10 | 11 | ## Running the example 12 | 13 | 1. Update the `NEW_RELIC_API_KEY` value in [secrets.yaml](./k8s/secrets.yaml) to your New Relic license key. 14 | 15 | ```yaml 16 | # ...omitted for brevity 17 | stringData: 18 | # New Relic API key to authenticate the export requests. 19 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 20 | NEW_RELIC_API_KEY: 21 | ``` 22 | 23 | * Note, be careful to avoid inadvertent secret sharing when modifying `secrets.yaml`. To ignore changes to this file from git, run `git update-index --skip-worktree k8s/secrets.yaml`. 24 | 25 | * If your account is based in the EU, update the `NEW_RELIC_OTLP_ENDPOINT` value in [collector.yaml](./k8s/collector.yaml) the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 26 | 27 | ```yaml 28 | # ...omitted for brevity 29 | env: 30 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 31 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 32 | - name: NEW_RELIC_OTLP_ENDPOINT 33 | value: https://otlp.eu01.nr-data.net 34 | ``` 35 | 36 | 2. Run the application with the following command. 37 | 38 | ```shell 39 | kubectl apply -f k8s/ 40 | ``` 41 | 42 | * When finished, cleanup resources with the following command. This is also useful to reset if modifying configuration. 43 | 44 | ```shell 45 | kubectl delete -f k8s/ 46 | ``` 47 | 48 | ## Viewing your data 49 | 50 | To review your redis data in New Relic, navigate to "New Relic -> All Entities -> Redis instances" and click on the instance with name "redis" to view the instance summary. Click on "Metric explorer" to view all metrics associated with the redis instance, or use [NRQL](https://docs.newrelic.com/docs/query-your-data/explore-query-data/get-started/introduction-querying-new-relic-data/) to perform ad-hoc analysis. 51 | 52 | ## Additional notes 53 | 54 | This example monitors a redis instance defined in [redis.yaml](./k8s/redis.yaml), which is not receiving any load. To use in production, you'll need to modify the `.receivers.redis.endpoint` value in [collector.yaml](k8s/collector.yaml) ConfigMap to point to the endpoint of your redis instance. Additionally, update the `server.address` and `server.port` resource attributes defined in `attributes/redis_metrics` to values which reflect the redis instance being monitored. 55 | -------------------------------------------------------------------------------- /other-examples/collector/redis/k8s/collector.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: nr-redis 6 | --- 7 | apiVersion: v1 8 | kind: ConfigMap 9 | metadata: 10 | name: collector-config 11 | namespace: nr-redis 12 | labels: 13 | app.kubernetes.io/name: collector-config 14 | data: 15 | collector-config: | 16 | receivers: 17 | redis: 18 | # Connect to redis pod defined in redis.yaml using service env vars set by k8s 19 | endpoint: ${REDIS_SERVICE_HOST}:${REDIS_SERVICE_PORT} 20 | metrics: 21 | # Enable redis.maxmemory optional metric 22 | redis.maxmemory: 23 | enabled: true 24 | 25 | processors: 26 | batch: 27 | # Add identifying resource attributes, which is required for New Relic entity synthesis. 28 | # The redis receiver does not currently include any identifying attributes on the metrics it produces. 29 | # We manually assign values to server.address and server.port, since values for ${REDIS_SERVICE_HOST} and ${REDIS_SERVICE_PORT} are unstable. 30 | attributes/redis_metrics: 31 | include: 32 | match_type: regexp 33 | metric_names: 34 | # Notice that if with single or without quotes just one backslash is needed 'redis\..*' 35 | - "redis\\..*" 36 | actions: 37 | - action: upsert 38 | key: server.address 39 | value: "redis" 40 | - action: upsert 41 | key: server.port 42 | value: "6379" 43 | 44 | exporters: 45 | otlphttp: 46 | endpoint: ${NEW_RELIC_OTLP_ENDPOINT} 47 | headers: 48 | api-key: ${NEW_RELIC_API_KEY} 49 | 50 | service: 51 | pipelines: 52 | metrics: 53 | receivers: [redis] 54 | processors: [attributes/redis_metrics, batch] 55 | exporters: [otlphttp] 56 | --- 57 | apiVersion: v1 58 | kind: Pod 59 | metadata: 60 | name: collector 61 | namespace: nr-redis 62 | labels: 63 | app.kubernetes.io/name: collector 64 | spec: 65 | containers: 66 | - name: collector 67 | image: otel/opentelemetry-collector-contrib:0.98.0 68 | env: 69 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 70 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 71 | - name: NEW_RELIC_OTLP_ENDPOINT 72 | value: https://otlp.nr-data.net/ 73 | # The New Relic API key used to authenticate export requests. 74 | # Defined in secrets.yaml 75 | - name: NEW_RELIC_API_KEY 76 | valueFrom: 77 | secretKeyRef: 78 | name: nr-redis-secret 79 | key: NEW_RELIC_API_KEY 80 | volumeMounts: 81 | - name: collector-config-vol 82 | mountPath: /etc/otelcol-contrib 83 | volumes: 84 | - name: collector-config-vol 85 | configMap: 86 | name: collector-config 87 | items: 88 | - key: collector-config 89 | path: config.yaml 90 | -------------------------------------------------------------------------------- /other-examples/collector/redis/k8s/redis.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: redis 6 | namespace: nr-redis 7 | labels: 8 | app.kubernetes.io/name: redis 9 | spec: 10 | containers: 11 | - name: redis 12 | image: redis:7.2-alpine 13 | ports: 14 | - containerPort: 6379 15 | --- 16 | apiVersion: v1 17 | kind: Service 18 | metadata: 19 | name: redis 20 | namespace: nr-redis 21 | labels: 22 | app.kubernetes.io/name: redis 23 | spec: 24 | ports: 25 | - port: 6379 26 | protocol: TCP 27 | selector: 28 | app.kubernetes.io/name: redis 29 | -------------------------------------------------------------------------------- /other-examples/collector/redis/k8s/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nr-redis-secret 5 | namespace: nr-redis 6 | stringData: 7 | # New Relic API key to authenticate the export requests. 8 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 9 | NEW_RELIC_API_KEY: 10 | -------------------------------------------------------------------------------- /other-examples/collector/singlestore/k8s/collector.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: nr-singlestore 6 | --- 7 | apiVersion: v1 8 | kind: ConfigMap 9 | metadata: 10 | name: collector-config 11 | namespace: nr-singlestore 12 | labels: 13 | app.kubernetes.io/name: collector-config 14 | data: 15 | collector-config: | 16 | receivers: 17 | prometheus: 18 | config: 19 | scrape_configs: 20 | - job_name: "singlestore" 21 | scrape_interval: 60s # Do not go any lower than this or you'll hit rate limits 22 | static_configs: 23 | - targets: ["api.singlestore.com"] 24 | scheme: https 25 | bearer_token: "${SINGLESTORE_API_KEY}" 26 | metrics_path: /v2/organizations/${SINGLESTORE_ORG_ID}/workspaceGroups/${SINGLESTORE_WORKSPACE_GROUP_ID}/metrics 27 | 28 | processors: 29 | batch: 30 | 31 | exporters: 32 | otlphttp: 33 | endpoint: ${NEW_RELIC_OTLP_ENDPOINT} 34 | headers: 35 | api-key: ${NEW_RELIC_API_KEY} 36 | 37 | service: 38 | pipelines: 39 | metrics: 40 | receivers: [prometheus] 41 | processors: [batch] 42 | exporters: [otlphttp] 43 | --- 44 | apiVersion: v1 45 | kind: Pod 46 | metadata: 47 | name: collector 48 | namespace: nr-singlestore 49 | labels: 50 | app.kubernetes.io/name: collector 51 | spec: 52 | containers: 53 | - name: collector 54 | image: otel/opentelemetry-collector-contrib:0.98.0 55 | env: 56 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 57 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 58 | - name: NEW_RELIC_OTLP_ENDPOINT 59 | value: https://otlp.nr-data.net/ 60 | # The New Relic API key used to authenticate export requests. 61 | # Defined in secrets.yaml 62 | - name: NEW_RELIC_API_KEY 63 | valueFrom: 64 | secretKeyRef: 65 | name: nr-singlestore-secret 66 | key: NEW_RELIC_API_KEY 67 | # The Singlestore API key. 68 | # Defined in secrets.yaml 69 | - name: SINGLESTORE_API_KEY 70 | valueFrom: 71 | secretKeyRef: 72 | name: nr-singlestore-secret 73 | key: SINGLESTORE_API_KEY 74 | # The Singlestore Org ID. 75 | # docs: https://support.singlestore.com/hc/en-us/articles/12396547132564-Workspace-Group-ID-or-Cluster-ID 76 | - name: SINGLESTORE_ORG_ID 77 | value: 78 | # The Singlestore Workspace Group ID. 79 | # docs: https://support.singlestore.com/hc/en-us/articles/12396547132564-Workspace-Group-ID-or-Cluster-ID 80 | - name: SINGLESTORE_WORKSPACE_GROUP_ID 81 | value: 82 | volumeMounts: 83 | - name: collector-config-vol 84 | mountPath: /etc/otelcol-contrib 85 | volumes: 86 | - name: collector-config-vol 87 | configMap: 88 | name: collector-config 89 | items: 90 | - key: collector-config 91 | path: config.yaml 92 | -------------------------------------------------------------------------------- /other-examples/collector/singlestore/k8s/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nr-singlestore-secret 5 | namespace: nr-singlestore 6 | stringData: 7 | # New Relic API key to authenticate the export requests. 8 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 9 | NEW_RELIC_API_KEY: 10 | # Set your Singlestore API Key. 11 | # docs: https://support.singlestore.com/hc/en-us/articles/12396018910228-Creating-Management-API-Key 12 | SINGLESTORE_API_KEY: > 13 | -------------------------------------------------------------------------------- /other-examples/collector/squid/README.md: -------------------------------------------------------------------------------- 1 | # Monitoring Squid with OpenTelemetry Collector 2 | 3 | This simple example demonstrates monitoring [Squid Web Proxy Cache](https://github.com/squid-cache/squid) prometheus metrics with the [OpenTelemetry collector](https://opentelemetry.io/docs/collector/), using the [prometheus receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/prometheusreceiver) and sending the data to New Relic via OTLP. 4 | 5 | ## Requirements 6 | 7 | * You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. Docker desktop [includes a standalone Kubernetes server and client](https://docs.docker.com/desktop/kubernetes/) which is useful for local testing. 8 | * [A New Relic account](https://one.newrelic.com/) 9 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 10 | 11 | ## Running the example 12 | 13 | 1. Update the `NEW_RELIC_API_KEY` value in [secrets.yaml](./k8s/secrets.yaml) to your New Relic license key. 14 | ```yaml 15 | # ...omitted for brevity 16 | stringData: 17 | # New Relic API key to authenticate the export requests. 18 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 19 | NEW_RELIC_API_KEY: 20 | ``` 21 | 22 | * Note, be careful to avoid inadvertent secret sharing when modifying `secrets.yaml`. To ignore changes to this file from git, run `git update-index --skip-worktree k8s/secrets.yaml`. 23 | 24 | * If your account is based in the EU, update the `NEW_RELIC_OTLP_ENDPOINT` value in [collector.yaml](./k8s/collector.yaml) the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 25 | 26 | ```yaml 27 | # ...omitted for brevity 28 | env: 29 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 30 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 31 | - name: NEW_RELIC_OTLP_ENDPOINT 32 | value: https://otlp.eu01.nr-data.net 33 | ``` 34 | 35 | 2. Set the `SQUID_CACHEMGR` env var value in [collector.yaml](./k8s/collector.yaml). The value is used to identify the squid entity in New Relic. 36 | 37 | ```yaml 38 | # ...omitted for brevity 39 | # A unique identifier for the instance of the squid cache manager being monitored, used as the entity name in New Relic. 40 | - name: SQUID_CACHEMGR 41 | value: 42 | ``` 43 | 44 | 3. Run the application with the following command. 45 | 46 | ```shell 47 | kubectl apply -f k8s/ 48 | ``` 49 | 50 | * When finished, cleanup resources with the following command. This is also useful to reset if modifying configuration. 51 | 52 | ```shell 53 | kubectl delete -f k8s/ 54 | ``` 55 | 56 | ## Viewing your data 57 | 58 | To review your squid data in New Relic, navigate to "New Relic -> All Entities -> Squid Cache managers" and click on the instance with name corresponding to the `SQUID_CACHEMGR` env var value to view the instance summary. Use [NRQL](https://docs.newrelic.com/docs/query-your-data/explore-query-data/get-started/introduction-querying-new-relic-data/) to perform ad-hoc analysis. 59 | 60 | ``` 61 | FROM Metric SELECT uniques(metricName) WHERE otel.library.name = 'otelcol/prometheusreceiver' AND metricName like 'squid%' LIMIT MAX 62 | ``` 63 | 64 | See [get started with querying](https://docs.newrelic.com/docs/query-your-data/explore-query-data/get-started/introduction-querying-new-relic-data/) for additional details on querying data in New Relic. 65 | 66 | ## Additional notes 67 | 68 | This example monitors a squid instance defined in [squid.yaml](./k8s/squid.yaml), with [squid-exporter](https://github.com/boynux/squid-exporter) running in a sidecar container. To use in production, you'll need to modify the `.receivers.prometheus.config.scrape_configs[0].static_configs[0].targets` value in [collector.yaml](k8s/collector.yaml) ConfigMap to point to the `squid-exporter` target corresponding to your squid instance. 69 | -------------------------------------------------------------------------------- /other-examples/collector/squid/k8s/collector.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: nr-squid 6 | --- 7 | apiVersion: v1 8 | kind: ConfigMap 9 | metadata: 10 | name: collector-config 11 | namespace: nr-squid 12 | labels: 13 | app.kubernetes.io/name: collector-config 14 | data: 15 | collector-config: | 16 | receivers: 17 | prometheus: 18 | config: 19 | scrape_configs: 20 | - job_name: "squid" 21 | static_configs: 22 | - targets: [ "${SQUID_SERVICE_HOST}:${SQUID_SERVICE_PORT_METRICS}" ] 23 | labels: 24 | squid_cachemgr: ${SQUID_CACHEMGR} 25 | metrics_path: /metrics 26 | metric_relabel_configs: 27 | - source_labels: [__name__] 28 | regex: "^squid_.*" 29 | action: keep 30 | 31 | processors: 32 | batch: 33 | 34 | exporters: 35 | otlphttp: 36 | endpoint: ${NEW_RELIC_OTLP_ENDPOINT} 37 | headers: 38 | api-key: ${NEW_RELIC_API_KEY} 39 | 40 | service: 41 | pipelines: 42 | metrics: 43 | receivers: [prometheus] 44 | processors: [batch] 45 | exporters: [otlphttp] 46 | --- 47 | apiVersion: v1 48 | kind: Pod 49 | metadata: 50 | name: collector 51 | namespace: nr-squid 52 | labels: 53 | app.kubernetes.io/name: collector 54 | spec: 55 | containers: 56 | - name: collector 57 | image: otel/opentelemetry-collector-contrib:0.98.0 58 | env: 59 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 60 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 61 | - name: NEW_RELIC_OTLP_ENDPOINT 62 | value: https://otlp.nr-data.net/ 63 | # The New Relic API key used to authenticate export requests. 64 | # Defined in secrets.yaml 65 | - name: NEW_RELIC_API_KEY 66 | valueFrom: 67 | secretKeyRef: 68 | name: nr-squid-secret 69 | key: NEW_RELIC_API_KEY 70 | # A unique identifier for the instance of the squid cache manager being monitored, used as the entity name in New Relic. 71 | - name: SQUID_CACHEMGR 72 | value: 73 | volumeMounts: 74 | - name: collector-config-vol 75 | mountPath: /etc/otelcol-contrib 76 | volumes: 77 | - name: collector-config-vol 78 | configMap: 79 | name: collector-config 80 | items: 81 | - key: collector-config 82 | path: config.yaml 83 | -------------------------------------------------------------------------------- /other-examples/collector/squid/k8s/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nr-squid-secret 5 | namespace: nr-squid 6 | stringData: 7 | # New Relic API key to authenticate the export requests. 8 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 9 | NEW_RELIC_API_KEY: 10 | -------------------------------------------------------------------------------- /other-examples/collector/squid/k8s/squid.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: squid 6 | namespace: nr-squid 7 | labels: 8 | app.kubernetes.io/name: squid 9 | spec: 10 | containers: 11 | - name: squid 12 | image: ubuntu/squid:5.2-22.04_beta 13 | env: 14 | - name: TZ 15 | value: UTC 16 | - name: squid-exporter 17 | image: boynux/squid-exporter 18 | env: 19 | - name: SQUID_HOSTNAME 20 | value: localhost 21 | - name: SQUID_PORT 22 | value: "3128" 23 | - name: SQUID_EXPORTER_LISTEN 24 | value: "0.0.0.0:9301" 25 | ports: 26 | - containerPort: 9301 27 | --- 28 | apiVersion: v1 29 | kind: Service 30 | metadata: 31 | name: squid 32 | namespace: nr-squid 33 | labels: 34 | app.kubernetes.io/name: squid 35 | spec: 36 | ports: 37 | - name: metrics 38 | port: 9301 39 | protocol: TCP 40 | selector: 41 | app.kubernetes.io/name: squid 42 | -------------------------------------------------------------------------------- /other-examples/collector/statsd/README.md: -------------------------------------------------------------------------------- 1 | # Monitoring StatsD with OpenTelemetry Collector 2 | 3 | This simple example demonstrates monitoring statsd sources with the [OpenTelemetry collector](https://opentelemetry.io/docs/collector/), using the [statsd receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/statsdreceiver) and sending the data to New Relic via OTLP. A simple load statsd load generator is configured to send dummy data to the statsd receiver. 4 | 5 | ## Requirements 6 | 7 | * You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. Docker desktop [includes a standalone Kubernetes server and client](https://docs.docker.com/desktop/kubernetes/) which is useful for local testing. 8 | * [A New Relic account](https://one.newrelic.com/) 9 | * [A New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key) 10 | 11 | ## Running the example 12 | 13 | 1. Update the `NEW_RELIC_API_KEY` value in [secrets.yaml](./k8s/secrets.yaml) to your New Relic license key. 14 | 15 | ```yaml 16 | # ...omitted for brevity 17 | stringData: 18 | # New Relic API key to authenticate the export requests. 19 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 20 | NEW_RELIC_API_KEY: 21 | ``` 22 | 23 | * Note, be careful to avoid inadvertent secret sharing when modifying `secrets.yaml`. To ignore changes to this file from git, run `git update-index --skip-worktree k8s/secrets.yaml`. 24 | 25 | * If your account is based in the EU, update the `NEW_RELIC_OTLP_ENDPOINT` value in [collector.yaml](./k8s/collector.yaml) the endpoint to: [https://otlp.eu01.nr-data.net](https://otlp.eu01.nr-data.net) 26 | 27 | ```yaml 28 | # ...omitted for brevity 29 | env: 30 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 31 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 32 | - name: NEW_RELIC_OTLP_ENDPOINT 33 | value: https://otlp.eu01.nr-data.net 34 | ``` 35 | 36 | 2. Run the application with the following command. 37 | 38 | ```shell 39 | kubectl apply -f k8s/ 40 | ``` 41 | 42 | * When finished, cleanup resources with the following command. This is also useful to reset if modifying configuration. 43 | 44 | ```shell 45 | kubectl delete -f k8s/ 46 | ``` 47 | 48 | ## Viewing your data 49 | 50 | To review your statsd data in New Relic, navigate to "New Relic -> Query Your Data". To list the metrics reported, query for: 51 | 52 | ``` 53 | FROM Metric SELECT uniques(metricName) WHERE otel.library.name = 'otelcol/statsdreceiver' LIMIT MAX 54 | ``` 55 | 56 | See [get started with querying](https://docs.newrelic.com/docs/query-your-data/explore-query-data/get-started/introduction-querying-new-relic-data/) for additional details on querying data in New Relic. 57 | 58 | ## Additional notes 59 | 60 | A simple load statsd load generator is configured to send dummy data to the statsd receiver, specified in [gen-statsd.yaml](./k8s/gen-statsd.yaml). To use in production, you'll need to configure your statsd data sources to point to the collector's statsd receiver endpoint. In this example, the collector's statsd receiver is listing for UDP on `0.0.0.0:8125`, which is exposed in a [service](https://kubernetes.io/docs/concepts/services-networking/service/). The load generator is configured point to this using service env vars set by kubernetes. 61 | -------------------------------------------------------------------------------- /other-examples/collector/statsd/k8s/collector.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: nr-statsd 6 | --- 7 | apiVersion: v1 8 | kind: ConfigMap 9 | metadata: 10 | name: collector-config 11 | namespace: nr-statsd 12 | labels: 13 | app.kubernetes.io/name: collector-config 14 | data: 15 | collector-config: | 16 | receivers: 17 | statsd: 18 | endpoint: 0.0.0.0:8125 19 | is_monotonic_counter: true 20 | 21 | processors: 22 | batch: 23 | 24 | exporters: 25 | otlphttp: 26 | endpoint: ${NEW_RELIC_OTLP_ENDPOINT} 27 | headers: 28 | api-key: ${NEW_RELIC_API_KEY} 29 | 30 | service: 31 | pipelines: 32 | metrics: 33 | receivers: [statsd] 34 | processors: [batch] 35 | exporters: [otlphttp] 36 | --- 37 | apiVersion: v1 38 | kind: Pod 39 | metadata: 40 | name: collector 41 | namespace: nr-statsd 42 | labels: 43 | app.kubernetes.io/name: collector 44 | spec: 45 | containers: 46 | - name: collector 47 | image: otel/opentelemetry-collector-contrib:0.98.0 48 | env: 49 | # The default US endpoint is set here. You can change the endpoint and port based on your requirements if needed. 50 | # docs: https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol 51 | - name: NEW_RELIC_OTLP_ENDPOINT 52 | value: https://otlp.nr-data.net/ 53 | # The New Relic API key used to authenticate export requests. 54 | # Defined in secrets.yaml 55 | - name: NEW_RELIC_API_KEY 56 | valueFrom: 57 | secretKeyRef: 58 | name: nr-statsd-secret 59 | key: NEW_RELIC_API_KEY 60 | volumeMounts: 61 | - name: collector-config-vol 62 | mountPath: /etc/otelcol-contrib 63 | ports: 64 | - containerPort: 8125 65 | protocol: UDP 66 | volumes: 67 | - name: collector-config-vol 68 | configMap: 69 | name: collector-config 70 | items: 71 | - key: collector-config 72 | path: config.yaml 73 | --- 74 | apiVersion: v1 75 | kind: Service 76 | metadata: 77 | name: collector 78 | namespace: nr-statsd 79 | labels: 80 | app.kubernetes.io/name: collector 81 | spec: 82 | ports: 83 | - name: statsd 84 | port: 8125 85 | protocol: UDP 86 | selector: 87 | app.kubernetes.io/name: collector 88 | -------------------------------------------------------------------------------- /other-examples/collector/statsd/k8s/gen-statsd.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: gen-statsd 6 | namespace: nr-statsd 7 | labels: 8 | app.kubernetes.io/name: gen-statsd 9 | spec: 10 | containers: 11 | - name: gen-statsd 12 | image: circonus/gen-statsd:1.0.0 13 | env: 14 | - name: STATSD_HOST 15 | value: $(COLLECTOR_SERVICE_HOST):$(COLLECTOR_SERVICE_PORT_STATSD) 16 | - name: PROTOCOL 17 | value: udp 18 | - name: AGENTS 19 | value: "1" 20 | -------------------------------------------------------------------------------- /other-examples/collector/statsd/k8s/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nr-statsd-secret 5 | namespace: nr-statsd 6 | stringData: 7 | # New Relic API key to authenticate the export requests. 8 | # docs: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#license-key 9 | NEW_RELIC_API_KEY: 10 | 11 | -------------------------------------------------------------------------------- /other-examples/dotnet/agent-nr-config/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /other-examples/dotnet/agent-nr-config/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace agent_nr_config.Controllers; 4 | 5 | [ApiController] 6 | [Route("[controller]")] 7 | public class WeatherForecastController : ControllerBase 8 | { 9 | private static readonly string[] Summaries = new[] 10 | { 11 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 12 | }; 13 | 14 | private readonly ILogger _logger; 15 | 16 | public WeatherForecastController(ILogger logger) 17 | { 18 | _logger = logger; 19 | } 20 | 21 | [HttpGet(Name = "GetWeatherForecast")] 22 | public IEnumerable Get() 23 | { 24 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 25 | { 26 | Date = DateTime.Now.AddDays(index), 27 | TemperatureC = Random.Shared.Next(-20, 55), 28 | Summary = Summaries[Random.Shared.Next(Summaries.Length)] 29 | }) 30 | .ToArray(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /other-examples/dotnet/agent-nr-config/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build 3 | # Download and unpack the agent 4 | # Refer to https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases for the available releases. 5 | RUN apt-get update && apt-get install unzip \ 6 | && wget "https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/download/v1.0.0-rc.2/opentelemetry-dotnet-instrumentation-linux-glibc.zip" -O /tracer-home.zip \ 7 | && unzip -d /tracer-home /tracer-home.zip 8 | WORKDIR /src 9 | 10 | COPY ["agent-nr-config.csproj", "."] 11 | RUN dotnet restore "./agent-nr-config.csproj" 12 | 13 | # Build the application in a framework dependent mode. 14 | # Automatic instrumentation is not currently supported for self-contained deployments or builds. 15 | COPY . . 16 | RUN dotnet build "agent-nr-config.csproj" -c Release -o /app/build 17 | 18 | FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS final 19 | WORKDIR /app 20 | # Copy the built application 21 | COPY --from=build /app/build . 22 | # Install the agent 23 | COPY --from=build /tracer-home /tracer-home 24 | # The most important environment variables are shown in this example. 25 | # For a complete list of options refer to the OpenTelemetry documenations available at 26 | # https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/blob/2f5e1fc2b30f444944966393fba1d2d45a69f08b/docs/config.md. 27 | # This env variable points to the installation directory for the agent 28 | ENV OTEL_DOTNET_AUTO_HOME="/tracer-home" 29 | ENV DOTNET_STARTUP_HOOKS="/tracer-home/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll" 30 | ENV DOTNET_ADDITIONAL_DEPS="/tracer-home/AdditionalDeps" 31 | ENV DOTNET_SHARED_STORE="/tracer-home/store" 32 | # These variables configure the metrics exporter to use "delta" temporality, which is required when sending data to NR 33 | ENV OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta" 34 | ENV OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION="base2_exponential_bucket_histogram" 35 | # This env variable points to the New Relic OTLP endpoint 36 | ENV OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp.nr-data.net" 37 | # This env variable configures the exporter to use the HTTP protocol. The default is gRPC. 38 | ENV OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" 39 | # This env variable adds your New Relic license key to the OTLP headers. 40 | # You should override this when running the container so that a valid license key is used. 41 | # The instructions in the README for this application shows how to override this value when starting the container. 42 | ENV OTEL_EXPORTER_OTLP_HEADERS="api-key=${NEW_RELIC_LICENSE_KEY}" 43 | # This env variable controls the name New Relic will use for your application 44 | ENV OTEL_SERVICE_NAME="agent-nr-config" 45 | # The env variables below can be used if byte-code instrumentation is desired. See 46 | # https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/blob/2f5e1fc2b30f444944966393fba1d2d45a69f08b/docs/config.md#instrumentations 47 | # for the list of available instrumentations and which ones require byte-code support. 48 | ENV CORECLR_ENABLE_PROFILING=1 49 | ENV CORECLR_PROFILER="{918728DD-259F-4A6A-AC2B-B85E1B658318}" 50 | ENV CORECLR_PROFILER_PATH="/tracer-home/linux-x64/OpenTelemetry.AutoInstrumentation.Native.so" 51 | ENTRYPOINT ["dotnet", "agent-nr-config.dll"] 52 | -------------------------------------------------------------------------------- /other-examples/dotnet/agent-nr-config/Program.cs: -------------------------------------------------------------------------------- 1 | var builder = WebApplication.CreateBuilder(args); 2 | 3 | // Add services to the container. 4 | 5 | builder.Services.AddControllers(); 6 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 7 | builder.Services.AddEndpointsApiExplorer(); 8 | builder.Services.AddSwaggerGen(); 9 | 10 | var app = builder.Build(); 11 | 12 | // Configure the HTTP request pipeline. 13 | if (app.Environment.IsDevelopment()) 14 | { 15 | app.UseSwagger(); 16 | app.UseSwaggerUI(); 17 | } 18 | 19 | app.UseHttpsRedirection(); 20 | 21 | app.UseAuthorization(); 22 | 23 | app.MapControllers(); 24 | 25 | app.Run(); 26 | -------------------------------------------------------------------------------- /other-examples/dotnet/agent-nr-config/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:15348", 8 | "sslPort": 44377 9 | } 10 | }, 11 | "profiles": { 12 | "agent_nr_config": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "https://localhost:7277;http://localhost:5045", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "IIS Express": { 23 | "commandName": "IISExpress", 24 | "launchBrowser": true, 25 | "launchUrl": "swagger", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /other-examples/dotnet/agent-nr-config/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Automatic Instrumentation (Agent) New Relic Config 2 | 3 | ## Introduction 4 | 5 | This project demonstrates a simple .NET application running with the OpenTelemetry Automatic Instrumentation (Agent) configured to write data to New Relic. Docker is leveraged so that it is easier to demonstrate the following and make it easier to run the example: 6 | 7 | - Where to download the agent. 8 | - How to install the agent. 9 | - How to configure the agent. 10 | - How to build and run the application being monitored by the agent. 11 | 12 | The project consists of two main components: 13 | 14 | 1. The default .NET Weather Forecast example application. ***This application does not directly contain any OpenTelemetry code or references, because the agent automatically instruments the application***. 15 | 2. [Dockerfile](./Dockerfile): Contains all of the setup code to download, install, and configure the agent so that it will monitor the example application when it is run within the container. 16 | 17 | ## Run 18 | 19 | This example only requires setting the environment variable: 20 | 21 | * `OTEL_EXPORTER_OTLP_HEADERS="api-key="` 22 | * Replace `` with your [Account License Key](https://one.newrelic.com/launcher/api-keys-ui.launcher). 23 | 24 | The other settings below have default values defined in the [Dockerfile](./Dockerfile), but can otherwise be overwritten/manually set: 25 | * `OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp.nr-data.net"` 26 | * `OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"` 27 | * `OTEL_SERVICE_NAME="my-test-service"` 28 | * Replace `my-test-service` with the name you wish to call the application. 29 | 30 | Additional configuration can be controlled using environment variables defined in the [Automatic Instrumentation config document](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/blob/2f5e1fc2b30f444944966393fba1d2d45a69f08b/docs/config.md). 31 | 32 | Run the application from a shell in the `agent-nr-config` directory via: 33 | ``` 34 | docker build . -t agent-nr-config 35 | docker run -d -p 8080:80 -e OTEL_EXPORTER_OTLP_HEADERS --name agent-nr-config agent-nr-config 36 | ``` 37 | 38 | The application exposes a simple endpoint at `http://localhost:8080/WeatherForecast`. 39 | 40 | Invoke it via: `curl http://localhost:8080/WeatherForecast` to generate trace data. 41 | 42 | Check your [New Relic account](https://one.newrelic.com) to confirm data is flowing. For EU users check your [account here](https://one.eu.newrelic.com). 43 | -------------------------------------------------------------------------------- /other-examples/dotnet/agent-nr-config/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | namespace agent_nr_config; 2 | 3 | public class WeatherForecast 4 | { 5 | public DateTime Date { get; set; } 6 | 7 | public int TemperatureC { get; set; } 8 | 9 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 10 | 11 | public string? Summary { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /other-examples/dotnet/agent-nr-config/agent-nr-config.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | agent_nr_config 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /other-examples/dotnet/agent-nr-config/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /other-examples/dotnet/agent-nr-config/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /other-examples/java/agent-nr-config/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Agent New Relic Config 2 | 3 | ## Introduction 4 | 5 | This project demonstrates a simple Java application running with the OpenTelemetry Java Agent configured to write data to New Relic. New Relic expects metric data in delta aggregation temporality, whereas the default for OpenTelemetry is cumulative. Delta temporality and several other configuration options are set via [application/build.gradle](./application/build.gradle). 6 | 7 | The project consists of two modules: 8 | 9 | 1. [application](./application): Contains a simple Spring Boot application configured to run with OpenTelemetry. 10 | 2. [config-extension](./config-extension): Contains SPI configuration code, which allows for optional additional configuration not available via environment variables. In this example, we use a sampler which is equivalent to the default `parentbased_always_on`, but which does not sample spring boot actuator endpoints with targets matching `/actuator.*`. samplerThe contents are packaged as a shadow jar, which the `application` module is configured to use as an extension jar. 11 | 12 | ## Run 13 | 14 | Set the following environment variables: 15 | * `OTEL_EXPORTER_OTLP_HEADERS=api-key=your_license_key` 16 | * Replace `your_license_key` with your [Account License Key](https://one.newrelic.com/launcher/api-keys-ui.launcher). 17 | * `OTEL_METRIC_EXPORT_INTERVAL=5000` 18 | * Optionally export metrics every 5000 ms instead of the default 60s. 19 | * `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=DELTA` 20 | * New Relic supports metrics in delta temporality, instead of the default cumulative. 21 | * `OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION=BASE2_EXPONENTIAL_BUCKET_HISTOGRAM` 22 | * Use exponential histogram instead of default explicit bucket histogram for better data compression. 23 | * `OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net` 24 | * Export data to New Relic's OTLP endpoint. 25 | * `OTEL_EXPORTER_OTLP_COMPRESSION=gzip` 26 | * Gzip compression has good performance and lowers data egress. 27 | * `OTEL_EXPERIMENTAL_EXPORTER_OTLP_RETRY_ENABLED=true` 28 | * Enable experimental export retry to help cope with the unreliability of the internet. 29 | * `OTEL_SERVICE_NAME=agent-nr-config` 30 | * Optionally replace `agent-nr-config` with the name you wish to call your application. 31 | * `OTEL_RESOURCE_ATTRIBUTES=service.instance.id=1234` 32 | * Give this application a unique instance id. 33 | * `OTEL_EXPERIMENTAL_RESOURCE_DISABLED_KEYS=process.command_line` 34 | * Disable the `process.command_line` resource attribute which often exceeds New Relic's maximum attribute length limit. 35 | * `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095` 36 | * New relic disallows attributes whose length exceeds 4095 characters. 37 | 38 | Additional configuration using standard autoconfiguration environment variables defined in the [autoconfigure module](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure). 39 | 40 | Run the application from a shell in the [java root](../) via: 41 | ``` 42 | export OTEL_EXPORTER_OTLP_HEADERS=api-key=your_license_key \ 43 | && export OTEL_METRIC_EXPORT_INTERVAL=5000 \ 44 | && export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=DELTA \ 45 | && export OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION=BASE2_EXPONENTIAL_BUCKET_HISTOGRAM \ 46 | && export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net \ 47 | && export OTEL_EXPORTER_OTLP_COMPRESSION=gzip \ 48 | && export OTEL_EXPERIMENTAL_EXPORTER_OTLP_RETRY_ENABLED=true \ 49 | && export OTEL_SERVICE_NAME=agent-nr-config \ 50 | && export OTEL_RESOURCE_ATTRIBUTES=service.instance.id=1234 \ 51 | && export OTEL_EXPERIMENTAL_RESOURCE_DISABLED_KEYS=process.command_line,process.command_args \ 52 | && export OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4095 53 | 54 | ./gradlew agent-nr-config:application:bootRun 55 | ``` 56 | 57 | The `bootRun` command will: 58 | - Build the `config-extension` shadow jar. 59 | - Build the application executable jar. 60 | - Run the application executable jar with jvmArgs that attach the OpenTelemetry Java agent. See the `bootRun` task config in [./application/build.gradle](./application/build.gradle) to see the jvmArg configuration. 61 | 62 | The application exposes a simple endpoint at `http://localhost:8080/ping`. 63 | 64 | Invoke it via: `curl http://localhost:8080/ping` to generate trace and metric data. 65 | 66 | Check your backend to confirm data is flowing. 67 | -------------------------------------------------------------------------------- /other-examples/java/agent-nr-config/application/build.gradle: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | 3 | plugins { 4 | id 'java-library' 5 | id 'org.springframework.boot' 6 | } 7 | 8 | configurations.all { 9 | exclude module: 'spring-boot-starter-logging' 10 | } 11 | 12 | configurations { 13 | agent 14 | } 15 | 16 | dependencies { 17 | implementation 'io.opentelemetry:opentelemetry-api' 18 | 19 | agent(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:${project.property('otelInstrumentationVersion')}")) 20 | agent("io.opentelemetry.javaagent:opentelemetry-javaagent") 21 | 22 | implementation platform(SpringBootPlugin.BOM_COORDINATES) 23 | implementation 'org.springframework.boot:spring-boot-starter-web' 24 | implementation 'org.springframework.boot:spring-boot-starter-log4j2' 25 | implementation 'org.springframework.boot:spring-boot-starter-actuator' 26 | } 27 | 28 | tasks.register("copyAgent", Copy) { 29 | from(configurations.agent.singleFile) 30 | into(layout.buildDirectory.dir('agent')) 31 | rename("opentelemetry-javaagent-.*\\.jar", "opentelemetry-javaagent.jar") 32 | } 33 | 34 | bootRun { 35 | mainClass.set 'com.newrelic.app.Application' 36 | 37 | // Before running, build the config-extension shadow jar 38 | dependsOn(":agent-nr-config:config-extension:shadowJar") 39 | // Before running, copy the agent to a reliable place in the build dir 40 | dependsOn("copyAgent") 41 | 42 | def extensionPath = project(":agent-nr-config:config-extension").buildDir.toString() + "/libs/config-extension.jar" 43 | 44 | def agentPath = project.buildDir.toString() + "/agent/opentelemetry-javaagent.jar" 45 | 46 | jvmArgs = [ 47 | // Set the opentelemetry-java-instrumentation agent as the javaagent 48 | "-javaagent:${agentPath}", 49 | // Use the config-extension shadowJar to configure the agent via SPI 50 | "-Dotel.javaagent.extensions=${extensionPath}" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /other-examples/java/agent-nr-config/application/src/main/java/com/newrelic/app/Application.java: -------------------------------------------------------------------------------- 1 | package com.newrelic.app; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /other-examples/java/agent-nr-config/application/src/main/java/com/newrelic/app/Controller.java: -------------------------------------------------------------------------------- 1 | package com.newrelic.app; 2 | 3 | import io.opentelemetry.api.GlobalOpenTelemetry; 4 | import io.opentelemetry.api.metrics.LongCounter; 5 | import io.opentelemetry.api.trace.Span; 6 | import java.util.Random; 7 | import org.apache.logging.log4j.LogManager; 8 | import org.apache.logging.log4j.Logger; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RestController 13 | public class Controller { 14 | 15 | private static final Logger LOGGER = LogManager.getLogger(Controller.class); 16 | 17 | private static final LongCounter MY_COUNTER = 18 | GlobalOpenTelemetry.get() 19 | .getMeter(Application.class.getName()) 20 | .counterBuilder("my-custom-counter") 21 | .build(); 22 | 23 | @GetMapping("/ping") 24 | public String ping() { 25 | // Demonstrate adding a custom attribute to the current span. 26 | Span.current().setAttribute("my-key", "my-value"); 27 | 28 | MY_COUNTER.add(new Random().nextInt(1000)); 29 | LOGGER.info("A sample log message!"); 30 | 31 | // Throw an exception ~25% of the time 32 | if (new Random().nextInt(4) == 0) { 33 | throw new IllegalStateException("Error!"); 34 | } 35 | 36 | return "pong"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /other-examples/java/agent-nr-config/config-extension/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | id 'com.github.johnrengelman.shadow' 4 | } 5 | 6 | tasks { 7 | assemble.dependsOn(shadowJar) 8 | } 9 | 10 | shadowJar { 11 | archiveClassifier.set("") 12 | } 13 | 14 | jar { 15 | // Disable standard jar 16 | enabled = false 17 | } 18 | 19 | dependencies { 20 | compileOnly 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure' 21 | 22 | implementation "io.opentelemetry.contrib:opentelemetry-samplers:1.40.0-alpha" 23 | } -------------------------------------------------------------------------------- /other-examples/java/agent-nr-config/config-extension/src/main/java/com/newrelic/otel/extension/Customizer.java: -------------------------------------------------------------------------------- 1 | package com.newrelic.otel.extension; 2 | 3 | import static io.opentelemetry.api.common.AttributeKey.stringKey; 4 | 5 | import io.opentelemetry.api.common.AttributeKey; 6 | import io.opentelemetry.api.trace.SpanKind; 7 | import io.opentelemetry.contrib.sampler.RuleBasedRoutingSampler; 8 | import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; 9 | import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; 10 | import io.opentelemetry.sdk.resources.Resource; 11 | import io.opentelemetry.sdk.trace.samplers.Sampler; 12 | import java.util.UUID; 13 | 14 | /** 15 | * Note this class is wired into SPI via {@code 16 | * resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider} 17 | */ 18 | public class Customizer implements AutoConfigurationCustomizerProvider { 19 | 20 | private static final AttributeKey SERVICE_INSTANCE_ID = stringKey("service.instance.id"); 21 | private static final AttributeKey HTTP_ROUTE = stringKey("http.route"); 22 | 23 | @Override 24 | public void customize(AutoConfigurationCustomizer autoConfiguration) { 25 | // Add additional resource attributes programmatically 26 | autoConfiguration.addResourceCustomizer( 27 | (resource, configProperties) -> 28 | resource.merge( 29 | Resource.builder().put(SERVICE_INSTANCE_ID, UUID.randomUUID().toString()).build())); 30 | 31 | // Set the sampler to be the default parentbased_always_on, but drop calls to spring 32 | // boot actuator endpoints 33 | autoConfiguration.addTracerProviderCustomizer( 34 | (sdkTracerProviderBuilder, configProperties) -> 35 | sdkTracerProviderBuilder.setSampler( 36 | Sampler.parentBased( 37 | RuleBasedRoutingSampler.builder(SpanKind.SERVER, Sampler.alwaysOn()) 38 | .drop(HTTP_ROUTE, "/actuator.*") 39 | .build()))); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /other-examples/java/agent-nr-config/config-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider: -------------------------------------------------------------------------------- 1 | com.newrelic.otel.extension.Customizer -------------------------------------------------------------------------------- /other-examples/java/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.diffplug.spotless' apply false 3 | } 4 | 5 | def otelInstrumentationVersion = "2.9.0-alpha"; 6 | 7 | subprojects { 8 | pluginManager.withPlugin('java') { 9 | apply plugin: 'com.diffplug.spotless' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(17) 14 | } 15 | } 16 | 17 | spotless { 18 | java { 19 | googleJavaFormat() 20 | } 21 | } 22 | 23 | repositories { 24 | mavenCentral() 25 | // Uncomment to access snapshots 26 | // maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } 27 | } 28 | 29 | test { 30 | useJUnitPlatform() 31 | } 32 | 33 | ext.otelInstrumentationVersion = otelInstrumentationVersion; 34 | 35 | dependencies { 36 | implementation platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:${otelInstrumentationVersion}") 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /other-examples/java/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newrelic/newrelic-opentelemetry-examples/30519f2658f077a35c2cd85afea610b7e2b59f7b/other-examples/java/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /other-examples/java/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=1b6b558be93f29438d3df94b7dfee02e794b94d9aca4611a92cdb79b6b88e909 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip 5 | networkTimeout=10000 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /other-examples/java/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /other-examples/java/logs-in-context-log4j2/.env: -------------------------------------------------------------------------------- 1 | NEW_RELIC_OTLP_ENDPOINT=https://otlp.nr-data.net 2 | NEW_RELIC_API_KEY= 3 | -------------------------------------------------------------------------------- /other-examples/java/logs-in-context-log4j2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:17 2 | 3 | RUN apt update && apt upgrade -y && apt install -y git 4 | 5 | WORKDIR / 6 | 7 | # Clone petclinic repo 8 | RUN git clone https://github.com/spring-projects/spring-petclinic.git 9 | 10 | WORKDIR /spring-petclinic 11 | 12 | # Copy logback config with structured logging 13 | COPY log4j2.xml src/main/resources/log4j2.xml 14 | COPY Log4j2EventLayout.json src/main/resources/Log4j2EventLayout.json 15 | 16 | # Modify build.gradle to include dependencies for JSON structured logging 17 | RUN sed -e '/dependencies {/a\ implementation "org.springframework.boot:spring-boot-starter-log4j2"' build.gradle > tmp; mv tmp build.gradle 18 | RUN sed -e '/dependencies {/a\ implementation "org.apache.logging.log4j:log4j-layout-template-json:2.20.0"' build.gradle > tmp; mv tmp build.gradle 19 | RUN echo "configurations.all {\n exclude module: 'spring-boot-starter-logging'\n}" >> build.gradle 20 | 21 | # Build the app 22 | RUN ./gradlew bootJar 23 | 24 | # Download the otel java agent 25 | RUN wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar 26 | 27 | CMD java -javaagent:opentelemetry-javaagent.jar -jar build/libs/*.jar 28 | 29 | -------------------------------------------------------------------------------- /other-examples/java/logs-in-context-log4j2/Log4j2EventLayout.json: -------------------------------------------------------------------------------- 1 | { 2 | "service.name": "${env:SERVICE_NAME:-logs-in-context}", 3 | "timestamp": { 4 | "$resolver": "timestamp" 5 | }, 6 | "thread.name": { 7 | "$resolver": "thread", 8 | "field": "name" 9 | }, 10 | "log.level": { 11 | "$resolver": "level", 12 | "field": "name" 13 | }, 14 | "logger.name": { 15 | "$resolver": "logger", 16 | "field": "name" 17 | }, 18 | "class.name": { 19 | "$resolver": "source", 20 | "field": "className" 21 | }, 22 | "method.name": { 23 | "$resolver": "source", 24 | "field": "methodName" 25 | }, 26 | "line.number": { 27 | "$resolver": "source", 28 | "field": "lineNumber" 29 | }, 30 | "trace_id": { 31 | "$resolver": "mdc", 32 | "key": "trace_id" 33 | }, 34 | "span_id": { 35 | "$resolver": "mdc", 36 | "key": "span_id" 37 | }, 38 | "message": { 39 | "$resolver": "message", 40 | "stringified": true 41 | }, 42 | "error.class": { 43 | "$resolver": "exception", 44 | "field": "className" 45 | }, 46 | "error.message": { 47 | "$resolver": "exception", 48 | "field": "message" 49 | }, 50 | "error.stack": { 51 | "$resolver": "exception", 52 | "field": "stackTrace", 53 | "stackTrace": { 54 | "stringified": true 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /other-examples/java/logs-in-context-log4j2/README.md: -------------------------------------------------------------------------------- 1 | # Logs In Context With Log4j2 2 | 3 | ## Introduction 4 | 5 | This project contains a Java application configured to use [Log4j2](https://logging.apache.org/log4j/2.x/) to write JSON structured logs that propagate OpenTelemetry trace context onto log messages. It also contains a [docker-compose.yaml](./docker-compose.yaml) which illustrates how to forward these logs to an OpenTelemetry Collector, and onto New Relic. 6 | 7 | The [log4j2.xml](./log4j2.xml) configures the application to log out to the console with a [JSON Template Layout](https://logging.apache.org/log4j/2.x/manual/json-template-layout.html) defined in [Log4j2EventLayout.json](./Log4j2EventLayout.json). 8 | 9 | The application uses the [OpenTelemetry Log4j2 Integration](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure) to inject trace context to Log4j2 [thread context](https://logging.apache.org/log4j/2.x/manual/thread-context.html). 10 | 11 | The result is JSON structured logs, with one JSON object per line, which have the `span_id` and `trace_id` from OpenTelemetry included: 12 | 13 | ```json 14 | { 15 | "timestamp": "2021-05-19T15:51:16.063-05:00", 16 | "thread.name": "http-nio-8080-exec-1", 17 | "log.level": "INFO", 18 | "logger.name": "...", 19 | "message": "...", 20 | "trace_id": "6aae93314fe034149cd85f07eac24bc5", 21 | "span_id": "f1be31bc6e4471d8", 22 | "service.name": "logs-in-context" 23 | } 24 | ``` 25 | 26 | The OpenTelemetry Log specification defines that when propagating [trace context in legacy formats](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/compatibility/logging_trace_context.md), `trace_id` and `span_id` should be used. However, [New Relic structured logging conventions](https://github.com/newrelic/newrelic-exporter-specs/tree/master/logging) expect trace context to be propagated as `trace.id` and `span.id`. The [transform](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/transformprocessor) processor is defined in the collector config to replace `trace_id` => `trace.id`, and `span_id` => `span.id`. Alternatively, this mapping could be done in the [Log4j2 JSON layout](./Log4j2EventLayout.json), which may be more performant. 27 | 28 | ## Run 29 | 30 | The application runs with Docker. The [docker-compose.yaml](./docker-compose.yaml) contains service definitions for the application and an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/). The application is configured to use the [Fluentd logging driver](https://docs.docker.com/config/containers/logging/fluentd/) to forward logs the collector. The collector is configured to receive Fluentd logs and forward them to New Relic over OTLP. 31 | 32 | The following image illustrates a similar example using FluentBit: 33 | 34 | ![](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/img/app-to-file-logs-fb.png?raw=true) 35 | 36 | Next, build and run the application: 37 | 38 | ```shell 39 | // Export your New Relic API key as an environment variable 40 | export NEW_RELIC_API_KEY= 41 | 42 | // Build and run the application 43 | docker compose up --build 44 | ``` 45 | 46 | Navigate to the app in a browser at `http://localhost:8080`. 47 | 48 | To exercise such that a trace is committed with logs in context, navigate to `http://localhost:8080/oups`. 49 | 50 | You should be able to see a mix of trace and log data flowing through the collector. If you navigate to the distributed traces of the application in [New Relic One](https://one.newrelic.com/), you should be able to find traces related to the call to `GET /oups`, and see the logs in context: 51 | 52 | _Trace With Logs_ 53 | ![](trace-with-logs.png) 54 | 55 | _Trace Logs In Context_ 56 | ![](trace-logs-in-context.png) 57 | -------------------------------------------------------------------------------- /other-examples/java/logs-in-context-log4j2/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | app: 4 | build: ./ 5 | environment: 6 | OTEL_SERVICE_NAME: 'logs-in-context' 7 | # Logs are forwarded to collector using fluentd 8 | OTEL_LOGS_EXPORTER: none 9 | OTEL_EXPORTER_OTLP_ENDPOINT: 'http://collector:4317' 10 | OTEL_EXPERIMENTAL_RESOURCE_DISABLED_KEYS: 'process.command_line,process.command_args' 11 | OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: 'delta' 12 | OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT: 4095 13 | ports: 14 | - '8080:8080' 15 | logging: 16 | driver: fluentd 17 | options: 18 | fluentd-address: localhost:8006 19 | depends_on: 20 | - collector 21 | 22 | collector: 23 | image: otel/opentelemetry-collector-contrib:0.92.0 24 | volumes: 25 | - ./otel-config.yaml:/otel-config.yaml 26 | command: ["--config=/otel-config.yaml"] 27 | environment: 28 | LOG_EXPORTER_LOG_VERBOSITY: "detailed" 29 | NEW_RELIC_OTLP_ENDPOINT: ${NEW_RELIC_OTLP_ENDPOINT} 30 | NEW_RELIC_API_KEY: '${NEW_RELIC_API_KEY}' 31 | ports: 32 | - '4317:4317' # OTLP gRPC receiver 33 | - '4318:4318' # OTLP HTTP receiver 34 | - '13133:13133' # health_check 35 | - '8006:8006' # Fluentd forward receiver 36 | - '8006:8006/udp' # Fluentd forward receiver 37 | -------------------------------------------------------------------------------- /other-examples/java/logs-in-context-log4j2/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /other-examples/java/logs-in-context-log4j2/otel-config.yaml: -------------------------------------------------------------------------------- 1 | extensions: 2 | health_check: {} 3 | receivers: 4 | otlp: 5 | protocols: 6 | grpc: 7 | http: 8 | fluentforward: 9 | endpoint: 0.0.0.0:8006 10 | processors: 11 | batch: 12 | transform: 13 | log_statements: 14 | - context: log 15 | statements: 16 | # The OpenTelemetry log SDK says the trace context should be encoded in trace_id and span_id, 17 | # but New Relic conventions expects the fields to be dot delimited trace.id and span.id. We 18 | # use the transform processor to replace trace_id => trace.id, span_id => span.id. 19 | # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/README.md#trace-context-in-legacy-formats 20 | - replace_pattern(body, "\"trace_id\":", "\"trace.id\":") 21 | - replace_pattern(body, "\"span_id\":", "\"span.id\":") 22 | exporters: 23 | debug: 24 | verbosity: $LOG_EXPORTER_LOG_VERBOSITY 25 | otlphttp: 26 | endpoint: $NEW_RELIC_OTLP_ENDPOINT 27 | headers: 28 | api-key: $NEW_RELIC_API_KEY 29 | service: 30 | extensions: [health_check] 31 | pipelines: 32 | metrics: 33 | receivers: [otlp] 34 | processors: [batch] 35 | exporters: [ otlphttp] 36 | traces: 37 | receivers: [otlp] 38 | processors: [ batch ] 39 | exporters: [ debug, otlphttp] 40 | logs: 41 | receivers: [fluentforward] 42 | processors: [ transform, batch ] 43 | exporters: [debug, otlphttp] 44 | -------------------------------------------------------------------------------- /other-examples/java/logs-in-context-log4j2/trace-logs-in-context.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newrelic/newrelic-opentelemetry-examples/30519f2658f077a35c2cd85afea610b7e2b59f7b/other-examples/java/logs-in-context-log4j2/trace-logs-in-context.png -------------------------------------------------------------------------------- /other-examples/java/logs-in-context-log4j2/trace-with-logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newrelic/newrelic-opentelemetry-examples/30519f2658f077a35c2cd85afea610b7e2b59f7b/other-examples/java/logs-in-context-log4j2/trace-with-logs.png -------------------------------------------------------------------------------- /other-examples/java/micrometer-shim/README.md: -------------------------------------------------------------------------------- 1 | # Micrometer Shim Example 2 | 3 | This is a modified version of the example from [opentelemetry-java-examples/micrometer-shim](https://github.com/open-telemetry/opentelemetry-java-examples/tree/main/micrometer-shim), configured to export data to New Relic via OTLP. 4 | 5 | This example demonstrates a typical use case 6 | of [micrometer shim](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/micrometer/micrometer-1.5/library). 7 | 8 | It consists of a spring boot application with: 9 | 10 | - A simple web API available at `GET http://localhost:8080/ping` 11 | - Instrumented with the spring boot actuator and micrometer 12 | - Micrometer metrics bridged to OpenTelemetry using the micrometer shim 13 | - OpenTelemetry metrics exported to New Relic via OTLP 14 | 15 | # How to run 16 | 17 | Run the application from a shell in the [java root](../) via: 18 | 19 | ```shell 20 | # Set New Relic license key as environment variable 21 | export NEW_RELIC_LICENSE_KEY= 22 | 23 | ./gradlew micrometer-shim:bootRun 24 | ``` 25 | 26 | Exercise the application by calling its endpoint 27 | 28 | ```shell 29 | curl http://localhost:8080/ping 30 | ``` 31 | 32 | Check New Relic to confirm data is flowing. 33 | -------------------------------------------------------------------------------- /other-examples/java/micrometer-shim/build.gradle: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | 3 | plugins { 4 | id 'java-library' 5 | id 'org.springframework.boot' 6 | } 7 | 8 | bootRun { 9 | mainClass.set 'io.opentelemetry.example.micrometer.Application' 10 | } 11 | 12 | dependencies { 13 | implementation 'io.opentelemetry:opentelemetry-api' 14 | implementation 'io.opentelemetry:opentelemetry-sdk' 15 | implementation 'io.opentelemetry:opentelemetry-exporter-otlp' 16 | 17 | //alpha modules 18 | implementation 'io.opentelemetry.instrumentation:opentelemetry-micrometer-1.5' 19 | 20 | //spring modules 21 | implementation platform(SpringBootPlugin.BOM_COORDINATES) 22 | implementation 'org.springframework.boot:spring-boot-starter-web' 23 | implementation 'org.springframework.boot:spring-boot-starter-actuator' 24 | implementation 'org.springframework.boot:spring-boot-starter-aop' 25 | } 26 | -------------------------------------------------------------------------------- /other-examples/java/micrometer-shim/src/main/java/io/opentelemetry/example/micrometer/Application.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.micrometer; 2 | 3 | import io.micrometer.core.aop.TimedAspect; 4 | import io.micrometer.core.instrument.MeterRegistry; 5 | import io.opentelemetry.api.OpenTelemetry; 6 | import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; 7 | import io.opentelemetry.instrumentation.micrometer.v1_5.OpenTelemetryMeterRegistry; 8 | import io.opentelemetry.sdk.OpenTelemetrySdk; 9 | import io.opentelemetry.sdk.metrics.Aggregation; 10 | import io.opentelemetry.sdk.metrics.InstrumentType; 11 | import io.opentelemetry.sdk.metrics.SdkMeterProvider; 12 | import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; 13 | import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; 14 | import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; 15 | import io.opentelemetry.sdk.resources.Resource; 16 | import java.time.Duration; 17 | import java.util.Optional; 18 | import org.springframework.boot.SpringApplication; 19 | import org.springframework.boot.autoconfigure.SpringBootApplication; 20 | import org.springframework.context.annotation.Bean; 21 | 22 | @SpringBootApplication 23 | public class Application { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(Application.class, args); 27 | } 28 | 29 | // Enable @Timed annotation 30 | @Bean 31 | public TimedAspect timedAspect(MeterRegistry registry) { 32 | return new TimedAspect(registry); 33 | } 34 | 35 | @Bean 36 | public OpenTelemetry openTelemetry() { 37 | return OpenTelemetrySdk.builder() 38 | .setMeterProvider( 39 | SdkMeterProvider.builder() 40 | .setResource( 41 | Resource.getDefault().toBuilder() 42 | .put("service.name", "micrometer-shim") 43 | // Include instrumentation.provider=micrometer to enable micrometer metrics 44 | // experience in New Relic 45 | .put("instrumentation.provider", "micrometer") 46 | .build()) 47 | .registerMetricReader( 48 | PeriodicMetricReader.builder( 49 | OtlpHttpMetricExporter.builder() 50 | .setEndpoint("https://otlp.nr-data.net/v1/metrics") 51 | .addHeader( 52 | "api-key", 53 | Optional.ofNullable(System.getenv("NEW_RELIC_LICENSE_KEY")) 54 | .filter(str -> !str.isEmpty() && !str.isBlank()) 55 | .orElseThrow()) 56 | // IMPORTANT: New Relic requires metrics to be delta temporality 57 | .setAggregationTemporalitySelector( 58 | AggregationTemporalitySelector.deltaPreferred()) 59 | // Use exponential histogram aggregation for histogram instruments 60 | // to 61 | // produce better data and compression 62 | .setDefaultAggregationSelector( 63 | DefaultAggregationSelector.getDefault() 64 | .with( 65 | InstrumentType.HISTOGRAM, 66 | Aggregation.base2ExponentialBucketHistogram())) 67 | .build()) 68 | // Match default micrometer collection interval of 60 seconds 69 | .setInterval(Duration.ofSeconds(60)) 70 | .build()) 71 | .build()) 72 | .build(); 73 | } 74 | 75 | @Bean 76 | public MeterRegistry meterRegistry(OpenTelemetry openTelemetry) { 77 | return OpenTelemetryMeterRegistry.builder(openTelemetry).build(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /other-examples/java/micrometer-shim/src/main/java/io/opentelemetry/example/micrometer/Controller.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.micrometer; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | public class Controller { 9 | 10 | @Autowired private Service service; 11 | 12 | @GetMapping("/ping") 13 | public String ping() throws InterruptedException { 14 | service.doWork(); 15 | return "pong"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /other-examples/java/micrometer-shim/src/main/java/io/opentelemetry/example/micrometer/Service.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.micrometer; 2 | 3 | import io.micrometer.core.annotation.Timed; 4 | import java.util.Random; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class Service { 9 | 10 | @Timed("dowork.time") 11 | void doWork() throws InterruptedException { 12 | Thread.sleep(new Random().nextInt(1000)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /other-examples/java/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | plugins { 3 | id 'com.diffplug.spotless' version '6.25.0' 4 | id 'org.springframework.boot' version '3.3.4' 5 | id 'com.github.johnrengelman.shadow' version '8.1.1' 6 | } 7 | } 8 | 9 | rootProject.name = "newrelic-opentelemetry-examples-java" 10 | include 'agent-nr-config:application' 11 | include 'agent-nr-config:config-extension' 12 | include 'logs-in-context-log4j2' 13 | include 'micrometer-shim' 14 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/dotnet/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | .aws-sam -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/dotnet/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Lambda .NET Example 2 | 3 | This repo contains a simple AWS Lambda .NET function instrumented with OpenTelemetry. 4 | 5 | ## Prerequisites 6 | 7 | This example assumes you have the following: 8 | 9 | * A New Relic account. If you don't have one, [create one for free](https://newrelic.com/signup). 10 | * An AWS account. If you don't have one, [create one for free](https://aws.amazon.com/). 11 | * A [New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#ingest-keys) from your New Relic account. 12 | 13 | It also assumes you have the following installed: 14 | 15 | * [.NET](https://dotnet.microsoft.com/en-us/download) 16 | * [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 17 | 18 | ## Run 19 | 20 | Set the following environment variable: 21 | 22 | ``` 23 | export NEW_RELIC_LICENSE_KEY= 24 | ``` 25 | 26 | Replacing `` with your New Relic license key. 27 | 28 | Then build the example function: 29 | 30 | ``` 31 | sam build 32 | ``` 33 | 34 | Then deploy it to your AWS account: 35 | 36 | ``` 37 | sam deploy \ 38 | --capabilities CAPABILITY_NAMED_IAM \ 39 | --parameter-overrides "newRelicLicenseKey=${NEW_RELIC_LICENSE_KEY}" \ 40 | --resolve-s3 \ 41 | --stack-name newrelic-example-opentelemetry-lambda-dotnet 42 | ``` 43 | 44 | The deploy will output an `apiEndpoint` which you can use to invoke the function: 45 | 46 | ``` 47 | curl https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/api/ 48 | ``` 49 | 50 | ## View your data in the New Relic UI 51 | 52 | After invoking the function you should see `newrelic-example-opentelemetry-lambda-dotnet` under `Services - OpenTelemetry` in your New Relic account. 53 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/dotnet/src/collector.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | grpc: 5 | http: 6 | 7 | exporters: 8 | logging: 9 | loglevel: debug 10 | otlp: 11 | endpoint: ${NEW_RELIC_OPENTELEMETRY_ENDPOINT} 12 | headers: 13 | api-key: ${NEW_RELIC_LICENSE_KEY} 14 | 15 | service: 16 | telemetry: 17 | logs: 18 | level: debug 19 | pipelines: 20 | traces: 21 | receivers: [otlp] 22 | exporters: [logging,otlp] 23 | metrics: 24 | receivers: [otlp] 25 | exporters: [logging,otlp] 26 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/dotnet/src/function.cs: -------------------------------------------------------------------------------- 1 | using Amazon.Lambda.APIGatewayEvents; 2 | using Amazon.Lambda.Core; 3 | using Amazon.S3; 4 | using OpenTelemetry; 5 | using OpenTelemetry.Contrib.Instrumentation.AWSLambda.Implementation; 6 | using OpenTelemetry.Trace; 7 | using System; 8 | using System.IO; 9 | using System.Text.Json; 10 | 11 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 12 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] 13 | 14 | namespace Example 15 | { 16 | public class Response 17 | { 18 | public string traceId { get; set; } 19 | } 20 | 21 | public class Function 22 | { 23 | public static TracerProvider tracerProvider; 24 | 25 | static Function() 26 | { 27 | AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); 28 | 29 | tracerProvider = Sdk.CreateTracerProviderBuilder() 30 | .AddAWSInstrumentation() 31 | .AddOtlpExporter() 32 | .AddAWSLambdaConfigurations() 33 | .Build(); 34 | } 35 | 36 | // use AwsSdkSample::AwsSdkSample.Function::TracingFunctionHandler as input Lambda handler instead 37 | public APIGatewayProxyResponse TracingFunctionHandler(APIGatewayProxyRequest request, ILambdaContext context) 38 | { 39 | return AWSLambdaWrapper.Trace(tracerProvider, FunctionHandler, request, context); 40 | } 41 | 42 | /// 43 | /// A simple function that takes a APIGatewayProxyRequest and returns a APIGatewayProxyResponse 44 | /// 45 | /// 46 | /// 47 | /// 48 | public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context) 49 | { 50 | var S3Client = new AmazonS3Client(); 51 | _ = S3Client.ListBucketsAsync().Result; 52 | 53 | var response = new Response 54 | { 55 | traceId = Environment.GetEnvironmentVariable("_X_AMZN_TRACE_ID") 56 | }; 57 | string body = JsonSerializer.Serialize(response); 58 | 59 | return new APIGatewayProxyResponse() { StatusCode = 200, Body = body }; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/dotnet/src/function.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp3.1 4 | true 5 | Lambda 6 | 7 | 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Always 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/dotnet/template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: 'AWS::Serverless-2016-10-31' 3 | Description: New Relic Example OpenTelemetry .NET Lambda Function 4 | 5 | Parameters: 6 | newRelicLicenseKey: 7 | Type: String 8 | Description: A New Relic license key. 9 | newRelicEndpoint: 10 | Type: String 11 | Description: New Relic OpenTelemetry endpoint to use. 12 | Default: otlp.nr-data.net:4317 13 | 14 | Resources: 15 | api: 16 | Type: AWS::Serverless::Api 17 | Properties: 18 | OpenApiVersion: 3.0.2 19 | StageName: api 20 | # This enables AWS X-Ray tracing within API Gateway which is necessary for 21 | # propagating a trace context downstream 22 | TracingEnabled: true 23 | 24 | function: 25 | Type: AWS::Serverless::Function 26 | Properties: 27 | CodeUri: ./src 28 | Description: New Relic Example OpenTelemetry .NET Lambda Function 29 | Environment: 30 | Variables: 31 | # These values get plugged into the collector.yaml file, which is the 32 | # OpenTelemetry Collector's config. 33 | NEW_RELIC_LICENSE_KEY: !Ref newRelicLicenseKey 34 | NEW_RELIC_OPENTELEMETRY_ENDPOINT: !Ref newRelicEndpoint 35 | # This overrides the default location for the OpenTelemetry Collector config 36 | # file, which is /opt/config.yaml by default. This points to the 37 | # collector.yaml in the src directory, which gets deployed along with the 38 | # function itself. 39 | OPENTELEMETRY_COLLECTOR_CONFIG_FILE: /var/task/collector.yaml 40 | OTEL_SERVICE_NAME: newrelic-example-opentelemetry-lambda-dotnet 41 | Events: 42 | getEndpoint: 43 | Type: Api 44 | Properties: 45 | Method: GET 46 | Path: / 47 | RestApiId: !Ref api 48 | FunctionName: newrelic-example-opentelemetry-lambda-dotnet 49 | Handler: function::Example.Function::TracingFunctionHandler 50 | Layers: 51 | # This is a layer managed by AWS that provides the OpenTelemetry Collector 52 | - !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:901920570463:layer:aws-otel-collector-ver-0-39-0:1 53 | MemorySize: 512 54 | Policies: 55 | - AWSLambdaBasicExecutionRole 56 | - AWSLambda_ReadOnlyAccess 57 | - AWSXrayWriteOnlyAccess 58 | - AmazonS3ReadOnlyAccess 59 | - AmazonDynamoDBFullAccess 60 | Runtime: dotnetcore3.1 61 | Timeout: 30 62 | # This is required to enable additional AWS X-Ray tracing within AWS Distro. We 63 | # export these traces to New Relic instead of writing them to AWS X-Ray. 64 | Tracing: Active 65 | 66 | logs: 67 | Type: AWS::Logs::LogGroup 68 | Properties: 69 | LogGroupName: {"Fn::Join": ["", ["/aws/lambda/", {"Ref": "function"}]]} 70 | # We override log retention since by default there is no retention limit which 71 | # is both wasteful and expensive. This log group gets created by AWS Lambda 72 | # automatically, so we need to explicitly create it ourselves to ensure a sensible 73 | # retention period. 74 | RetentionInDays: 7 75 | 76 | Outputs: 77 | apiEndpoint: 78 | Description: API Endpoint 79 | Value: !Sub "https://${api}.execute-api.${AWS::Region}.amazonaws.com/api/" 80 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/java/.gitignore: -------------------------------------------------------------------------------- 1 | .aws-sam 2 | .DS_Store 3 | .idea 4 | .gradle 5 | build 6 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/java/ExampleFunction/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | dependencies { 10 | //aws 11 | implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' 12 | implementation 'com.amazonaws:aws-lambda-java-events:3.6.0' 13 | implementation 'software.amazon.awssdk:s3:2.17.112' 14 | implementation 'software.amazon.awssdk:dynamodb:2.17.112' 15 | 16 | //okhttp 17 | implementation 'com.squareup.okhttp3:okhttp:4.9.3' 18 | 19 | //logback 20 | implementation 'ch.qos.logback:logback-classic:1.2.3' 21 | 22 | //jetbrains 23 | implementation 'org.jetbrains:annotations:20.1.0' 24 | 25 | //otel 26 | implementation 'io.opentelemetry:opentelemetry-api:1.10.1' 27 | implementation 'io.opentelemetry:opentelemetry-api-metrics:1.10.0-alpha-rc.1' 28 | implementation 'io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0:1.10.1-alpha' 29 | } 30 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/java/ExampleFunction/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newrelic/newrelic-opentelemetry-examples/30519f2658f077a35c2cd85afea610b7e2b59f7b/other-examples/serverless/aws-lambda/java/ExampleFunction/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/java/ExampleFunction/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/java/ExampleFunction/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/java/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Lambda Java Example 2 | 3 | This repo contains a simple AWS Lambda Java function instrumented with OpenTelemetry. 4 | 5 | ## Prerequisites 6 | 7 | This example assumes you have the following: 8 | 9 | * A New Relic account. If you don't have one, [create one for free](https://newrelic.com/signup). 10 | * An AWS account. If you don't have one, [create one for free](https://aws.amazon.com/). 11 | * A [New Relic license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#ingest-keys) from your New Relic account. 12 | 13 | It also assumes you have the following installed: 14 | 15 | * [Java 11](https://www.codejava.net/java-se/download-and-install-java-11-openjdk-and-oracle-jdk) 16 | * [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 17 | 18 | ## Run 19 | 20 | Set the following environment variable: 21 | 22 | ``` 23 | export NEW_RELIC_LICENSE_KEY= 24 | ``` 25 | 26 | Replacing `` with your New Relic license key. 27 | 28 | Then build the example function: 29 | 30 | ``` 31 | sam build 32 | cp collector.yaml .aws-sam/build/function/collector.yaml 33 | ``` 34 | 35 | Then deploy it to your AWS account: 36 | 37 | ``` 38 | sam deploy \ 39 | --capabilities CAPABILITY_NAMED_IAM \ 40 | --parameter-overrides "newRelicLicenseKey=${NEW_RELIC_LICENSE_KEY}" \ 41 | --resolve-s3 \ 42 | --stack-name newrelic-example-opentelemetry-lambda-java 43 | ``` 44 | 45 | The deploy will output an `apiEndpoint` which you can use to invoke the function: 46 | 47 | ``` 48 | curl https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/api/ 49 | ``` 50 | 51 | ## View your data in the New Relic UI 52 | 53 | After invoking the function you should see `newrelic-example-opentelemetry-lambda-java` under `Services - OpenTelemetry` in your New Relic account. 54 | -------------------------------------------------------------------------------- /other-examples/serverless/aws-lambda/java/collector.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | grpc: 5 | http: 6 | 7 | exporters: 8 | logging: 9 | loglevel: debug 10 | sampling_initial: 5 11 | sampling_thereafter: 200 12 | otlphttp: 13 | endpoint: ${NEW_RELIC_OPENTELEMETRY_ENDPOINT} 14 | headers: 15 | api-key: ${NEW_RELIC_LICENSE_KEY} 16 | 17 | service: 18 | telemetry: 19 | logs: 20 | level: debug 21 | pipelines: 22 | traces: 23 | receivers: [otlp] 24 | exporters: [logging,otlphttp] 25 | metrics: 26 | receivers: [otlp] 27 | exporters: [logging,otlphttp] 28 | logs: 29 | receivers: [otlp] 30 | processors: [] 31 | exporters: [logging,otlphttp] -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/.funcignore: -------------------------------------------------------------------------------- 1 | *.js.map 2 | *.ts 3 | .git* 4 | .vscode 5 | local.settings.json 6 | test 7 | tsconfig.json -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/.gitignore: -------------------------------------------------------------------------------- 1 | # Preserve .vscode directory 2 | !.vscode/ 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | 12 | # Diagnostic reports (https://nodejs.org/api/report.html) 13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # TypeScript v1 declaration files 47 | typings/ 48 | 49 | # Optional npm cache directory 50 | .npm 51 | 52 | # Optional eslint cache 53 | .eslintcache 54 | 55 | # Optional REPL history 56 | .node_repl_history 57 | 58 | # Output of 'npm pack' 59 | *.tgz 60 | 61 | # Yarn Integrity file 62 | .yarn-integrity 63 | 64 | # dotenv environment variables file 65 | .env 66 | .env.test 67 | 68 | # parcel-bundler cache (https://parceljs.org/) 69 | .cache 70 | 71 | # next.js build output 72 | .next 73 | 74 | # nuxt.js build output 75 | .nuxt 76 | 77 | # vuepress build output 78 | .vuepress/dist 79 | 80 | # Serverless directories 81 | .serverless/ 82 | 83 | # FuseBox cache 84 | .fusebox/ 85 | 86 | # DynamoDB Local files 87 | .dynamodb/ 88 | 89 | # TypeScript output 90 | dist 91 | out 92 | 93 | # Azure Functions artifacts 94 | bin 95 | obj 96 | appsettings.json 97 | local.settings.json 98 | 99 | # Azurite artifacts 100 | __blobstorage__ 101 | __queuestorage__ 102 | __azurite_db*__.json 103 | -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions" 4 | ] 5 | } -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to Node Functions", 6 | "type": "node", 7 | "request": "attach", 8 | "port": 9229, 9 | "preLaunchTask": "func: host start" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.deploySubpath": ".", 3 | "azureFunctions.postDeployTask": "npm install (functions)", 4 | "azureFunctions.projectLanguage": "JavaScript", 5 | "azureFunctions.projectRuntime": "~4", 6 | "debug.internalConsoleOptions": "neverOpen", 7 | "azureFunctions.preDeployTask": "npm prune (functions)", 8 | } 9 | -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "func", 6 | "label": "func: host start", 7 | "command": "host start", 8 | "problemMatcher": "$func-node-watch", 9 | "isBackground": true, 10 | "dependsOn": "npm install (functions)" 11 | }, 12 | { 13 | "type": "shell", 14 | "label": "npm install (functions)", 15 | "command": "npm install" 16 | }, 17 | { 18 | "type": "shell", 19 | "label": "npm prune (functions)", 20 | "command": "npm prune --production", 21 | "problemMatcher": [] 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/HttpTriggerExample/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "function", 5 | "type": "httpTrigger", 6 | "direction": "in", 7 | "name": "req", 8 | "methods": [ 9 | "get", 10 | "post" 11 | ] 12 | }, 13 | { 14 | "type": "http", 15 | "direction": "out", 16 | "name": "res" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/HttpTriggerExample/index.js: -------------------------------------------------------------------------------- 1 | const { instrumentHttpFunction } = require('../open-telemetry/tracing'); 2 | 3 | // Patches function to keep primary function implementation untouched. 4 | // Can directly instrument within function without patching. 5 | module.exports = instrumentHttpFunction(httpFunction); 6 | 7 | async function httpFunction(context, req) { 8 | context.log('JavaScript HTTP trigger function processed a request.'); 9 | 10 | const name = (req.query.name || (req.body && req.body.name)); 11 | const responseMessage = name 12 | ? "Hello, " + name + ". This HTTP triggered function executed successfully." 13 | : "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."; 14 | 15 | context.res = { 16 | // status: 200, /* Defaults to 200 */ 17 | body: responseMessage 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/HttpTriggerExample/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Azure" 3 | } -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingSettings": { 6 | "isEnabled": true, 7 | "excludedTypes": "Request" 8 | } 9 | } 10 | }, 11 | "extensionBundle": { 12 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 13 | "version": "[3.*, 4.0.0)" 14 | } 15 | } -------------------------------------------------------------------------------- /other-examples/serverless/azure-functions/node/http-trigger-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http-trigger-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "func start", 7 | "dev": "func start --port 11002", 8 | "test": "echo \"No tests yet...\"" 9 | }, 10 | "dependencies": { 11 | "@opentelemetry/api": "^1.3.0", 12 | "@opentelemetry/exporter-trace-otlp-grpc": "^0.34.0", 13 | "@opentelemetry/instrumentation-http": "^0.34.0", 14 | "@opentelemetry/resources": "^1.8.0", 15 | "@opentelemetry/sdk-trace-node": "^1.8.0", 16 | "uuid": "^9.0.0" 17 | }, 18 | "devDependencies": {} 19 | } 20 | --------------------------------------------------------------------------------