pax_global_header 0000666 0000000 0000000 00000000064 15240576456 0014530 g ustar 00root root 0000000 0000000 52 comment=ea9dca1df161b87d48c1c9fb04c052a4062dff3e
open-telemetry-opentelemetry-injector-ea9dca1/ 0000775 0000000 0000000 00000000000 15240576456 0021757 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/.chloggen/ 0000775 0000000 0000000 00000000000 15240576456 0023623 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/.chloggen/TEMPLATE.yaml 0000664 0000000 0000000 00000002246 15240576456 0025726 0 ustar 00root root 0000000 0000000 # Use this changelog template to create an entry for release notes.
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type:
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component:
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note:
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: []
# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with "chore" or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: []
open-telemetry-opentelemetry-injector-ea9dca1/.chloggen/config.yaml 0000664 0000000 0000000 00000002156 15240576456 0025760 0 ustar 00root root 0000000 0000000 # The directory that stores individual changelog entries.
# Each entry is stored in a dedicated yaml file.
# - 'chloggen new' will copy the 'template_yaml' to this directory as a new entry file.
# - 'chloggen validate' will validate that all entry files are valid.
# - 'chloggen update' will read and delete all entry files in this directory, and update 'changelog_md'.
# Specify as relative path from root of repo.
# (Optional) Default: .chloggen
entries_dir: .chloggen
# This file is used as the input for individual changelog entries.
# Specify as relative path from root of repo.
# (Optional) Default: .chloggen/TEMPLATE.yaml
template_yaml: .chloggen/TEMPLATE.yaml
summary_template: .chloggen/summary.tmpl
# The CHANGELOG file or files to which 'chloggen update' will write new entries
# (Optional) Default filename: CHANGELOG.md
change_logs:
user: CHANGELOG.md
# The default change_log or change_logs to which an entry should be added.
# If 'change_logs' is specified in this file, and no value is specified for 'default_change_logs',
# then 'change_logs' MUST be specified in every entry file.
default_change_logs: [user]
open-telemetry-opentelemetry-injector-ea9dca1/.chloggen/summary.tmpl 0000664 0000000 0000000 00000002155 15240576456 0026221 0 ustar 00root root 0000000 0000000 {{- define "entry" -}}
- `{{ .Component }}`: {{ .Note }} (
{{- range $i, $issue := .Issues }}
{{- if $i }}, {{ end -}}
#{{ $issue }}
{{- end -}}
)
{{- if .SubText }}
{{ .SubText | indent 2 }}
{{- end }}
{{- end }}
## {{ .Version }}
{{- if .BreakingChanges }}
### 🛑 Breaking changes 🛑
{{- range $i, $change := .BreakingChanges }}
{{- if eq $i 0}}
{{end}}
{{ template "entry" $change }}
{{- end }}
{{- end }}
{{- if .Deprecations }}
### 🚩 Deprecations 🚩
{{- range $i, $change := .Deprecations }}
{{- if eq $i 0}}
{{end}}
{{ template "entry" $change }}
{{- end }}
{{- end }}
{{- if .NewComponents }}
### 🚀 New components 🚀
{{- range $i, $change := .NewComponents }}
{{- if eq $i 0}}
{{end}}
{{ template "entry" $change }}
{{- end }}
{{- end }}
{{- if .Enhancements }}
### 💡 Enhancements 💡
{{- range $i, $change := .Enhancements }}
{{- if eq $i 0}}
{{end}}
{{ template "entry" $change }}
{{- end }}
{{- end }}
{{- if .BugFixes }}
### 🧰 Bug fixes 🧰
{{- range $i, $change := .BugFixes }}
{{- if eq $i 0}}
{{end}}
{{ template "entry" $change }}
{{- end }}
{{- end }}
open-telemetry-opentelemetry-injector-ea9dca1/.github/ 0000775 0000000 0000000 00000000000 15240576456 0023317 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/.github/CODEOWNERS 0000664 0000000 0000000 00000001141 15240576456 0024707 0 ustar 00root root 0000000 0000000 #####################################################
#
# List of approvers for OpenTelemetry Proto repository
#
#####################################################
#
# Learn about membership in OpenTelemetry community:
# https://github.com/open-telemetry/community/blob/main/community-membership.md
#
#
# Learn about CODEOWNERS file format:
# https://help.github.com/en/articles/about-code-owners
#
# Global owners, will be the owners for everything in the repo. Membership is tracked via https://github.com/open-telemetry/community/blob/main/community-members.md
* @open-telemetry/injector-approvers
open-telemetry-opentelemetry-injector-ea9dca1/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 15240576456 0025502 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/.github/ISSUE_TEMPLATE/bug_report.yaml 0000664 0000000 0000000 00000005110 15240576456 0030533 0 ustar 00root root 0000000 0000000 name: Bug report
description: Create a report to help us improve
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! Please make sure to fill out the entire form below, providing as much context as you can in order to help us triage and track down your bug as quickly as possible.
Before filing a bug, please be sure you have searched through [existing bugs](https://github.com/open-telemetry/opentelemetry-injector/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Abug) to see if an existing issue covers your bug.
- type: textarea
attributes:
label: What happened?
description: Please provide as much detail as you reasonably can.
value: |
**Describe the bug**
**Steps to reproduce**
**What did you expect to see?**
**What did you see instead?**
validations:
required: true
- type: input
attributes:
label: Version
description: What version did you use? (e.g., `v0.4.0`, `1eb551b`, etc)
validations:
required: true
- type: textarea
attributes:
label: Environment information
description: Please provide any additional information about your installation.
value: |
## Environment
OS: (e.g., "Ubuntu 20.04")
Compiler(if manually compiled): (e.g., "go 14.2")
- type: textarea
attributes:
label: Log output
description: |
Please copy and paste any relevant log output.
render: shell
- type: textarea
attributes:
label: Additional context
description: Any additional information you think may be relevant to this issue.
- type: dropdown
attributes:
label: Tip
description: This element is static, used to render a helpful sub-heading for end-users and community members to help prioritize issues. Please leave as is.
options:
- [React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with � to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/).
default: 0
open-telemetry-opentelemetry-injector-ea9dca1/.github/ISSUE_TEMPLATE/feature_request.yaml 0000664 0000000 0000000 00000002752 15240576456 0031577 0 ustar 00root root 0000000 0000000 name: Feature request
description: Suggest an idea for this project
labels: ["feature request"]
body:
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...].
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.
- type: dropdown
attributes:
label: Tip
description: This element is static, used to render a helpful sub-heading for end-users and community members to help prioritize issues. Please leave as is.
options:
- [React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with � to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/).
default: 0
open-telemetry-opentelemetry-injector-ea9dca1/.github/ISSUE_TEMPLATE/other.yaml 0000664 0000000 0000000 00000001613 15240576456 0027510 0 ustar 00root root 0000000 0000000 name: Other issue
description: Create a new issue to help us improve
body:
- type: textarea
attributes:
label: Describe the issue you're reporting
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: true
- type: dropdown
attributes:
label: Tip
description: This element is static, used to render a helpful sub-heading for end-users and community members to help prioritize issues. Please leave as is.
options:
- [React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with � to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/).
default: 0
open-telemetry-opentelemetry-injector-ea9dca1/.github/lychee.toml 0000664 0000000 0000000 00000000275 15240576456 0025471 0 ustar 00root root 0000000 0000000 include_fragments = "full"
accept = ["200..=299", "429"]
exclude = [
"^http(s)?://localhost",
"^http(s)?://example.com"
]
# better to be safe and avoid failures
max_retries = 6
open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/ 0000775 0000000 0000000 00000000000 15240576456 0025354 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/build.yml 0000664 0000000 0000000 00000005051 15240576456 0027177 0 ustar 00root root 0000000 0000000 name: Build
on:
push:
branches:
- main
tags:
- "v[0-9]+.[0-9]+.[0-9]+**"
pull_request:
permissions:
contents: read
jobs:
verify-and-build-binary:
runs-on: ${{ matrix.ARCH == 'amd64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }}
strategy:
matrix:
ARCH: [ "amd64", "arm64"]
steps:
- name: Check out the codebase.
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1
- name: lint source code
run: |
make lint
- name: Run Zig unit tests
run: make zig-unit-tests ARCH=${{ matrix.ARCH }}
- name: Build binary
run: make dist ARCH=${{ matrix.ARCH }}
- name: Run Injector integration tests
run: make injector-integration-tests-for-one-architecture ARCH=${{ matrix.ARCH }}
- name: Upload binary
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: libotelinject-${{ matrix.ARCH }}
path: ./dist/*.so
if-no-files-found: error
publish-stable:
runs-on: ubuntu-24.04
if: startsWith(github.ref, 'refs/tags/') && github.repository == 'open-telemetry/opentelemetry-injector'
needs: verify-and-build-binary
permissions:
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- run: mkdir -p artifacts
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: ./artifacts/
- name: Prepare release notes
run: ./.github/workflows/scripts/prepare-release-notes.sh
env:
RELEASE_TAG: ${{ steps.github_tag.outputs.tag }}
- name: debug release artifacts
shell: bash
run: |
set -x
pwd
ls -la .
ls -laR /home/runner/work/opentelemetry-injector/opentelemetry-injector/artifacts || true
ls -laR artifacts || true
- name: Release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
with:
body_path: release-notes.md
fail_on_unmatched_files: true
# RC tags (e.g. v0.10.0-rc.1) land as a draft release so maintainers
# can review the notes and artifacts before publishing; stable tags
# publish immediately.
draft: ${{ contains(github.ref_name, '-rc.') }}
files: |
artifacts/**/*
open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/changelog.yml 0000664 0000000 0000000 00000007570 15240576456 0030037 0 ustar 00root root 0000000 0000000 # This action requires that any PR targeting the main branch should add a
# yaml file to the ./.chloggen/ directory. If a CHANGELOG entry is not required,
# or if performing maintenance on the Changelog, add either "chore" to the title
# of the pull request or add the \"Skip Changelog\" label to disable this action.
name: Changelog
on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
branches:
- main
permissions: read-all
env:
# Make sure to exit early if cache segment download times out after 2 minutes.
# We limit cache download as a whole to 5 minutes.
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 2
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true
jobs:
changelog:
runs-on: ubuntu-24.04
if: |
${{ github.event_name == 'pull_request' &&
github.actor != 'dependabot[bot]' &&
!contains(github.event.pull_request.labels.*.name, 'dependencies') &&
!contains(github.event.pull_request.labels.*.name, 'Skip Changelog') &&
!startsWith(github.event.pull_request.title, 'chore') &&
!startsWith(github.event.pull_request.title, 'ci') &&
!startsWith(github.event.pull_request.title, 'test')
}}
env:
PR_HEAD: ${{ github.event.pull_request.head.sha }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: 1.26.6
cache: false
- name: Cache Go
id: go-cache
timeout-minutes: 5
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/go/bin
~/go/pkg/mod
key: changelog-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
- name: Ensure no changes to the CHANGELOG.md or CHANGELOG-API.md
run: |
if [[ $(git diff --name-only $(git merge-base origin/main $PR_HEAD) $PR_HEAD ./CHANGELOG*.md) ]]
then
echo "CHANGELOG.md and CHANGELOG-API.md should not be directly modified."
echo "Please add a .yaml file to the ./.chloggen/ directory."
echo "See CONTRIBUTING.md for more details."
echo "Alternately, add either \"chore\" to the title of the pull request or add the \"Skip Changelog\" label if this job should be skipped."
false
else
echo "CHANGELOG.md and CHANGELOG-API.md were not modified."
fi
- name: Ensure ./.chloggen/*.yaml addition(s)
run: |
if [[ 1 -gt $(git diff --diff-filter=A --name-only $(git merge-base origin/main $PR_HEAD) $PR_HEAD ./.chloggen | grep -c \\.yaml) ]]
then
echo "No changelog entry was added to the ./.chloggen/ directory."
echo "Please add a .yaml file to the ./.chloggen/ directory."
echo "See CONTRIBUTING.md for more details."
echo "Alternately, add either \"chore\" to the title of the pull request or add the \"Skip Changelog\" label if this job should be skipped."
false
else
echo "A changelog entry was added to the ./.chloggen/ directory."
fi
- name: Validate ./.chloggen/*.yaml changes
run: |
make chlog-validate \
|| { echo "New ./.chloggen/*.yaml file failed validation."; exit 1; }
# In order to validate any links in the yaml file, render the config to markdown
- name: Render .chloggen changelog entries
run: make chlog-preview > changelog_preview.md
- name: Link Checker
id: lychee
uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0
with:
args: "--verbose --no-progress ./changelog_preview.md --config .github/lychee.toml"
failIfEmpty: false
open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/create-tag-for-release.yml 0000664 0000000 0000000 00000003324 15240576456 0032317 0 ustar 00root root 0000000 0000000 name: Automation - Create Tag for Release
on:
push:
branches:
- main
permissions:
contents: write
jobs:
create-tag-for-release:
runs-on: ubuntu-24.04
steps:
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: otelbot-token
with:
client-id: ${{ vars.OTELBOT_INJECTOR_CLIENT_ID }}
private-key: ${{ secrets.OTELBOT_INJECTOR_PRIVATE_KEY }}
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 2
# We are deliberately not using the default secrets.GITHUB_TOKEN here, since events from that token do not
# trigger subsequent workflows, see
# https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow#triggering-a-workflow-from-a-workflow.
# I.e., creating and pushing the tag would not trigger the workflow .github/workflows/build.yml. We do need to
# trigger the workflow for the tag we are creating here though, as the job publish-stable from build.yaml
# actually creates the release and uploads the assets.
# See https://github.com/open-telemetry/community/blob/9eaa934620638a2f5537d3d74372b389098a8f5e/assets.md#otelbot.
#
# Providing the token to the checkout action will result in the token being used in all subsequent git
# operations, in particular for creating the tag in .github/workflows/scripts/create-tag-for-release.sh.
token: ${{ steps.otelbot-token.outputs.token }}
- name: Create tag for release
run: .github/workflows/scripts/create-tag-for-release.sh
open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/fossa.yml 0000664 0000000 0000000 00000000622 15240576456 0027212 0 ustar 00root root 0000000 0000000 name: FOSSA scanning
on:
push:
branches:
- main
permissions:
contents: read
jobs:
fossa:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: fossas/fossa-action@29693cc50323968e039056be419b32989fc5880c # v2.0.0
with:
api-key: ${{secrets.FOSSA_API_KEY}}
team: OpenTelemetry
open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/ossf-scorecard.yml 0000664 0000000 0000000 00000003027 15240576456 0031016 0 ustar 00root root 0000000 0000000 name: OSSF Scorecard
on:
push:
branches:
- main
schedule:
- cron: "39 12 * * 2" # once a week
workflow_dispatch:
permissions:
contents: read
jobs:
analysis:
runs-on: ubuntu-latest
permissions:
# Needed for Code scanning upload
security-events: write
# Needed for GitHub OIDC token if publish_results is true
id-token: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
with:
results_file: results.sarif
results_format: sarif
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable
# uploads of run results in SARIF format to the repository Actions tab.
# https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts
- name: "Upload artifact"
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
sarif_file: results.sarif
open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/prepare-release.yml 0000664 0000000 0000000 00000004234 15240576456 0031156 0 ustar 00root root 0000000 0000000 name: Automation - Prepare Release
on:
workflow_dispatch:
inputs:
override:
description: |
Override the auto-derived bump. Leave as "auto" to derive from
chloggen entries in .chloggen/, or force a specific bump kind.
required: true
default: auto
type: choice
options:
- auto
- major
- minor
- patch
prerelease:
description: |
When true, release the next release candidate for the computed
version instead of the stable release, tagging v-rc.
where N is one greater than the highest existing rc index for the
same base version (or 1 if no prior rc exists).
required: false
default: false
type: boolean
permissions:
contents: read
jobs:
# Releasing opentelemetry-injector
prepare-release:
permissions:
contents: write # required for pushing changes in prepare-release.sh
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-tags: true
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.26.6"
cache: false
- name: Determine next release version
id: version
env:
OVERRIDE: ${{ inputs.override }}
PRERELEASE: ${{ inputs.prerelease }}
working-directory: ./tooling/nextversion
run: |
go run . \
-override "$OVERRIDE" \
-prerelease="$PRERELEASE" \
-chloggen-dir ../../.chloggen
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: otelbot-token
with:
client-id: ${{ vars.OTELBOT_CLIENT_ID }}
private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }}
- name: Prepare release for injector
env:
GITHUB_TOKEN: ${{ steps.otelbot-token.outputs.token }}
REPO: open-telemetry/opentelemetry-injector
VERSION: ${{ steps.version.outputs.version }}
run: ./.github/workflows/scripts/prepare-release.sh
open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/scripts/ 0000775 0000000 0000000 00000000000 15240576456 0027043 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/scripts/create-tag-for-release.sh 0000775 0000000 0000000 00000001742 15240576456 0033624 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/../../.."
# Get the most recent commit message
COMMIT_MSG=$(git log -1 --pretty=%B)
# Check if commit message matches release pattern and extract version
if [[ "$COMMIT_MSG" =~ ^docs:\ update\ changelog\ to\ prepare\ release\ (v[0-9]+\.[0-9]+\.[0-9]+(-[[:alnum:]]+)?).*$ ]]; then
VERSION="${BASH_REMATCH[1]}"
echo "Found release commit for version: $VERSION."
# Create and push tag
echo "Creating tag for version $VERSION."
# See https://github.com/open-telemetry/community/blob/9eaa934620638a2f5537d3d74372b389098a8f5e/assets.md#otelbot
git config user.name otelbot
git config user.email 197425009+otelbot@users.noreply.github.com
git tag "$VERSION"
git push origin "$VERSION"
echo "Successfully created and pushed tag: $VERSION."
else
echo "The most recent commit does not seem to be a release commit."
exit 0
fi
open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/scripts/prepare-release-notes.sh 0000775 0000000 0000000 00000000551 15240576456 0033605 0 ustar 00root root 0000000 0000000 #!/bin/bash -ex
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
touch release-notes.md
echo "## Changelog" >> release-notes.md
awk '//,//' CHANGELOG.md > tmp-chlog.md # select changelog of latest version only
sed '1,3d' tmp-chlog.md >> release-notes.md # delete first 3 lines of file
open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/scripts/prepare-release.sh 0000775 0000000 0000000 00000002202 15240576456 0032452 0 ustar 00root root 0000000 0000000 #!/bin/bash -ex
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
# Usage: VERSION=v1.2.3 ./prepare-release.sh
# Calls make chlog-update to compile all changelog entries from .chloggen and add them to the main CHANGELOG.md file,
# then creates a PR with this change.
PATTERN="^v[0-9]+\.[0-9]+\.[0-9]+.*"
if [[ "$VERSION" == [0-9]* ]]; then
# normalize the VERSION input without leading "v"
VERSION="v$VERSION"
fi
if ! [[ ${VERSION} =~ $PATTERN ]]
then
echo "VERSION should follow the semver format (with a leading v), i.e. v1.2.3 or v1.2.3-qualifier."
exit 1
fi
git config user.name opentelemetrybot
git config user.email 107717825+opentelemetrybot@users.noreply.github.com
BRANCH="prepare-release-prs/${VERSION}"
git checkout -b "${BRANCH}"
make chlog-update VERSION="${VERSION}"
git add --all
git commit -m "docs: update changelog to prepare release ${VERSION}"
git push --set-upstream origin "${BRANCH}"
gh pr create --head "$(git branch --show-current)" --title "chore: prepare release ${VERSION}" --body "
The following commands were run to prepare this release:
- make chlog-update VERSION=${VERSION}
"
open-telemetry-opentelemetry-injector-ea9dca1/.github/workflows/tooling.yml 0000664 0000000 0000000 00000001442 15240576456 0027553 0 ustar 00root root 0000000 0000000 name: Tooling
on:
push:
branches:
- main
paths:
- "tooling/**"
- ".github/workflows/tooling.yml"
pull_request:
paths:
- "tooling/**"
- ".github/workflows/tooling.yml"
permissions:
contents: read
jobs:
nextversion:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.26.6"
cache: true
cache-dependency-path: tooling/nextversion/go.sum
- name: go vet
working-directory: ./tooling/nextversion
run: go vet ./...
- name: go test
working-directory: ./tooling/nextversion
run: go test -race -count=1 ./...
open-telemetry-opentelemetry-injector-ea9dca1/.gitignore 0000664 0000000 0000000 00000000046 15240576456 0023747 0 ustar 00root root 0000000 0000000 .zig-cache
zig-out
so/
dist/
.tools/ open-telemetry-opentelemetry-injector-ea9dca1/.shellcheckrc 0000664 0000000 0000000 00000000107 15240576456 0024410 0 ustar 00root root 0000000 0000000 enable=useless-use-of-cat
disable=SC2164 # cd/popd/push failure check
open-telemetry-opentelemetry-injector-ea9dca1/.vscode/ 0000775 0000000 0000000 00000000000 15240576456 0023320 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/.vscode/settings.json 0000664 0000000 0000000 00000000176 15240576456 0026057 0 ustar 00root root 0000000 0000000 {
"zig.testArgs": [
"test",
"-lc",
"--test-filter",
"${filter}",
"${path}"
]
} open-telemetry-opentelemetry-injector-ea9dca1/CHANGELOG.md 0000664 0000000 0000000 00000045727 15240576456 0023607 0 ustar 00root root 0000000 0000000
# Changelog
## v0.11.0
### 💡 Enhancements 💡
- `dotnet`: Make the minimum .NET major version required for injection configurable. (#409)
The injector inspects the `*.runtimeconfig.json` file of the target application and skips the injection of the
.NET auto-instrumentation if the application does not target a supported .NET version. The minimum supported .NET
major version (previously hardcoded to 8) can now be configured via the configuration file key
`dotnet_auto_instrumentation_minimum_dotnet_major_version` or the environment variable
`DOTNET_AUTO_INSTRUMENTATION_MINIMUM_DOTNET_MAJOR_VERSION`. The default remains 8, matching the .NET versions
supported by the upstream OpenTelemetry .NET auto-instrumentation. Distributions of the .NET auto-instrumentation
that support older .NET versions can lower this threshold accordingly.
- `injector`: Remove architecture gate from .NET injection; delegate SDK availability checks to downstream adopters. (#411)
Previously the injector refused to inject .NET on any architecture other than `amd64` and `arm64`.
The injector now constructs the expected SDK path for any architecture and relies on the existing
file-existence check to skip injection when the SDK is absent, consistent with how every other
runtime (Node.js, Python, JVM, Ruby) behaves.
Downstream adopters (system packages, the OpenTelemetry Operator) can install a .NET SDK for any
architecture under the standard path and have it picked up automatically.
## v0.10.1
### 🧰 Bug fixes 🧰
- `injector`: Fix integer overflow panic when a GNU hash bucket is empty during the second-pass library scan on glibc < 2.34 systems. (#399)
On pre-glibc-2.34 systems (e.g. RHEL 8, Debian Bullseye) the injector's second-pass scan of
`/proc/self/maps` calls `ElfDynLib.lookupAddress` on every mapped shared object. If the GNU
hash bloom filter false-positives for a looked-up symbol and the corresponding bucket value is
zero (empty bucket) or otherwise less than `symoffset`, the `u32` subtraction underflows and
triggers a ReleaseSafe `panic: integer overflow` that aborts the host process with `SIGABRT`
before its own code runs. The fix mirrors glibc's `dl-lookup` behaviour: treat any bucket
value below `symoffset` as "symbol not present" and return `null`.
## v0.10.0
### 🛑 Breaking changes 🛑
- `packaging`: The DEB and RPM system packages for the OpenTelemetry Injector have moved to open-telemetry/opentelemetry-packaging. This repository no longer builds or releases .deb / .rpm artifacts; tagged releases from here now contain only the raw libotelinject_.so shared library. (#395)
Download the DEB and RPM packages from https://github.com/open-telemetry/opentelemetry-packaging/releases.
Packaging bugs and feature requests should be filed at https://github.com/open-telemetry/opentelemetry-packaging.
The port over was tracked in open-telemetry/opentelemetry-packaging#5.
### 💡 Enhancements 💡
- `ruby`: Add support for injecting the Ruby OpenTelemetry auto-instrumentation via RUBYOPT. (#367)
When a Ruby auto-instrumentation agent path is configured (via ruby_auto_instrumentation_agent_path_prefix
or the RUBY_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX environment variable), the injector sets RUBYOPT to
require the agent's entry file and OTEL_RUBY_ADDITIONAL_GEM_PATH so the gem can locate its bundled
dependencies. The path is resolved per libc flavor (glibc/musl).
## v0.9.2
### 🧰 Bug fixes 🧰
- `injector`: Silently fall back to defaults when `/proc/self/environ` is unreadable. (#361)
When the host process drops privileges before the injector runs (e.g. a package
postinst script that switches to a service user before starting a daemon), opening
`/proc/self/environ` fails with `AccessDenied`. This previously bubbled up as an
error-level log entry in the host process's own log stream. The injector now
treats `AccessDenied` the same as any other read failure and silently falls back
to the default log level and disabled state.
## v0.9.1
### 💡 Enhancements 💡
- `injector`: Add a build-time option to override which environment variable prefixes are accepted from `all_auto_instrumentation_agents_env_path`. (#351)
### 🧰 Bug fixes 🧰
- `injection`: Skip .NET injection for unsupported runtime versions. (#360)
- `injector`: Parse quoted values in injector configuration files with bash-style semantics. (#373)
Values in `default_env.conf` and other injector configuration files were previously
used verbatim after whitespace trimming, so `KEY="value"` would inject a literal `"`
into the target process environment. The parser now follows bash quoting rules for
well-formed input: a matching pair of surrounding double or single quotes is stripped;
inside double quotes, the escapes `\"`, `\\`, `\$`, and `` \` `` are processed while
other backslash sequences (`\n`, `\t`, `\z`, ...) are kept literally; inside single
quotes, no escape processing is performed.
For malformed input the parser deliberately diverges from shell semantics: values
with stray or unbalanced quote characters (e.g. `KEY="value`) are passed through
literally rather than rejected, because the parser is line-oriented and cannot
continue reading past a newline to find a matching closing quote. A warning is
emitted in that case so the mistake is visible.
## v0.9.0
### 🧰 Bug fixes 🧰
- `injector`: Fix injection failure on glibc < 2.34 when the target binary uses copy relocation on environ (#348)
The injector previously resolved `__environ` (a data symbol) from the ELF symbol table, which returned
a null pointer on binaries with copy relocation (e.g. Node.js on Debian Bullseye / glibc 2.31), causing
pre-existing values of `NODE_OPTIONS`, `OTEL_RESOURCE_ATTRIBUTES`, etc. to be overwritten rather than
merged. The fix switches to resolving `getenv` (a function), which is not subject to copy relocation.
## v0.8.0
### 🧰 Bug fixes 🧰
- `injector`: Do not overwrite existing .NET profiler and startup-hook environment variables when deciding whether to inject .NET auto-instrumentation (#270)
If the target process already defines `CORECLR_ENABLE_PROFILING`, `CORECLR_PROFILER`,
`CORECLR_PROFILER_PATH`, `DOTNET_ADDITIONAL_DEPS`, `DOTNET_SHARED_STORE`, or
`DOTNET_STARTUP_HOOKS`, the injector now stands down for .NET instead of overwriting those
values. `OTEL_DOTNET_AUTO_HOME` alone does not block injection.
- `injection`: Skip .NET auto-instrumentation for applications that already reference OpenTelemetry packages. (#267)
- `injector`: Fix libc detection failure on glibc < 2.34 systems (e.g. RHEL 8) for binaries that do not link libdl.so (#311)
On glibc < 2.34 (e.g. RHEL 8 / glibc 2.28), `dlsym` is exported by `libdl.so` rather than
`libc.so` itself. Binaries that do not link `libdl.so` (such as `grep`, simple C utilities, and
many other system programs) would produce a `failed to identify libc` warning and receive no
instrumentation. The fix adds a fallback that looks up `setenv` and `__environ` directly from the
ELF symbol table when `dlsym` is not found, which succeeds for `libc.so` on all glibc versions.
## v0.7.0
### 🛑 Breaking changes 🛑
- `config`: use a directory structure with multiple files as config source (#291)
Breaking change: The in-code defaults for the auto-instrumentation agent paths are now empty. Paths must be provided
via external configuration. Users who use the injector binary directly, but do not use the system packages published
by this project, and who also have previously relied on the default auto-instrumentation agent paths must now explicitly
configure the agent paths.
This can be done either via the main configuration file (default: `/etc/opentelemetry/injector/injector.conf`), or
conf.d-style files in the configuration directory (i.e. files under `/etc/opentelemetry/injector.d`), or via
environment variables.
The configuration now moves under `/etc/opentelemetry/injector/`, with the main configuration file as
`/etc/opentelemetry/injector/injector.conf`, merging with drop-in files under `/etc/opentelemetry/injector/conf.d/`.
The environment variable configuration file also moves from `/etc/opentelemetry/default_auto_instrumentation_env.conf` to
`/etc/opentelemetry/injector/default_env.conf`.
## v0.6.0
### 🧰 Bug fixes 🧰
- `injector`: Evaluate include/exclude process filters before attempting libc detection, eliminating spurious "failed to identify libc" warnings for filtered-out processes. (#311)
- `injector`: Fix bug where `include_paths` was ignored when `include_with_arguments` was not configured. Each non-empty include/exclude setting now adds an independent condition (AND across settings, OR within entries). (#312)
## v0.5.0
### 💡 Enhancements 💡
- update all auto-instrumentation agents:
| Package | Change |
|---------|--------|
| [@opentelemetry/auto-instrumentations-node](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/auto-instrumentations-node#readme) ([source](https://redirect.github.com/open-telemetry/opentelemetry-js-contrib/tree/HEAD/packages/auto-instrumentations-node)) | `v0.59.0` → `0.72.0` |
| [open-telemetry/opentelemetry-dotnet-instrumentation](https://redirect.github.com/open-telemetry/opentelemetry-dotnet-instrumentation) | `v1.11.0` → `v1.14.1` |
| [open-telemetry/opentelemetry-java-instrumentation](https://redirect.github.com/open-telemetry/opentelemetry-java-instrumentation) | `v2.16.0` → `v2.26.1` |
## v0.4.0
### 💡 Enhancements 💡
- `injection`: Read `OTEL_INJECTOR_DISABLED` before detecting the libc flavor (#268)
Read the environment variable `OTEL_INJECTOR_DISABLED` earlier, before
attempting to detect the libc flavor. The advantage is that
`OTEL_INJECTOR_DISABLED` can now be used as an escape hatch if the libc
detection code causes issues.
## v0.3.0
### 💡 Enhancements 💡
- `injection`: Add option to disable auto-instrumentation for specific runtimes or all runtimes (#240)
When the config file option `auto_instrumentation_disabled` or the environment variable `OTEL_INJECTOR_AUTO_INSTRUMENTATION_DISABLED` is set to `*`, auto-instrumentation for all runtimes will be disabled. When set to a comma-separated list of runtimes, auto-instrumentation for the listed runtimes will be disabled. In contrast to `OTEL_INJECTOR_DISABLED=true` which disables the injector wholesale, injection of additional resource attributes via `OTEL_RESOURCE_ATTRIBUTES` still happens when `auto_instrumentation_disabled` or `OTEL_INJECTOR_AUTO_INSTRUMENTATION_DISABLED` are used.
## v0.2.0
### 💡 Enhancements 💡
- `injection`: Add option to completely disable the injector with an environment variable (#240)
When OTEL_INJECTOR_DISABLED is set to "true" no environment variables will be set by the injector
## v0.1.0
### 💡 Enhancements 💡
- `logging`: Adds process id to each log line (#200)
- `python`: Add opt-in support for Python auto-instrumentation (#216)
Add support for prepending to PYTHONPATH to enable Python auto-instrumentation. For now, auto-instrumentation for
Python is off by default and no default Python auto-instrumentation agent is included in the system packages.
Python auto-instrumentation needs to be enabled explicitly by providing a Python auto-instrumentation agent and a
custom otelinject.conf file with python_auto_instrumentation_agent_path_prefix set or by setting
PYTHON_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX.
Be aware that it is not always safe to inject the existing zero-code instrumentation for Python due to possible
dependency conflicts (protobuf etc.)
## v0.0.3-20260109
### 🛑 Breaking changes 🛑
- `injector`: Remove link-time dependency on `__environ`, inject environment variables once at startup via setenv instead of overriding libc's getenv function. (#166)
This removes the declaration `extern var __environ: [*]u8` from the injector, that is, the dependency on the `__environ`
pointer symbol exported by libc.
Motivation: The injector may be linked to binaries that, while dynamically linked, do not link any libc. This would
result in the injector preventing the program from starting due to a linker error, effectively crashing the
application under monitoring.
This change introduces a way to look up the `dlsym` symbol, and then in turn through `dlsym` the `__environ` and
`setenv` symbols. This happens at runtime in an initialization step, by inspecting the process' memory and
finding the `dlsym` symbol in memory. This allows us to read and manipulate the process environment without depending
on any external symbols at link time. More importantly, we have the option to stand down if looking up
`dlsym`/`__environ`/`setenv` fails, and let the host process continue, instead of crashing it at startup.
Also, the injector now no longer overrides libc's `getenv` to inject environment variables but instead unconditionally
injects all environment variables by calling `setenv` at startup. This change is necessary, because even when removing
the dependency on the `__environ` symbol (see above), there would still be potential to break certain executables:
- For example, on some older distributions (Debian 11/bullseye is one), `libc` and `libdl` are two distinct libary
files, with `libdl` containing `dlopen`, `dlcose`, `dlsym` and `dlerror`. When a binary only binds `libc`, but not
`libdl`, we would not find the `dlsym` symbol (because it is actually really not loaded into memory), hence we
wouldn't be able to find the `__environ` or `setenv` symbols. As a consequence, we would not be able to backfill
the injector-internal representation of the environment (std.os.environ/std.posix.getenv in the Zig code) and
_all_ calls to `getenv` would return null; i.e. we would effectively obliterate the environment of the process.
- Another issue is that, if a binary binds `libcrypto` (i.e. uses OpenSSL), it will try to look up the
`OPENSSL_armcap` environment variable before the injector init code even has ran. With the `getenv` override, this
would always return null, even if `OPENSSL_armcap` is set (independent of the `libdl` issue described above).
Hence, overriding `getenv` would break some of OpenSSL's assumptions.
- Many runtimes do not use `getenv` to read environment variables. E.g. the JVM as well as the CLR use `getenv` in
their native startup code, but when environment variables are read from with the runtime, the reading bypasses
`getenv`. Hence, overriding getenv is not feasible to inject reliably into these runtimes. The same is true for
Python. Injecting via `setenv` solves this problem.
Last but not least, we no longer inject resource attributes into the JVM via the workaround of adding
`-Dotel.resource.attributes` to `JAVA_TOOL_OPTIONS`. This was only necessary because the JVM does not read
`OTEL_RESOURCE_ATTRIBUTES` via `getenv` (see previous paragraph), hence this was a necessary workaround with the
override-getenv approach. With the switch to `setenv`, it is no longer necessary.
### 💡 Enhancements 💡
- `environment`: Limit all_auto_instrumentation_agents_env_path env vars to entries prefixed with OTEL_. (#176)
- `config`: add OTEL_INJECTOR_CONFIG_FILE to set config file location (#188)
This adds support for a new environment variable `OTEL_INJECTOR_CONFIG_FILE` that determines from which path the
injector's configuration file is read. If the variable is not set or empty, the configuration file is read from the
default path `/etc/opentelemetry/otelinject.conf`.
This is useful in environments where you want to provide a configuration file, but you do not want to make any
assumptions about the underlying file system's structure. I.e. you want to keep all assets of the injector (injector
binary, auto-instrumentation agents and the injector configuration) completely separate from standard OS directories
like `/etc`.
### 🧰 Bug fixes 🧰
- `environment`: Fix out of index error when leveraging all_auto_instrumentation_agents_env_path with more than one env var. (#173)
- `config`: Fix handling of overly long lines in config file (#174)
Continue to read the rest of the config file after discarding an overly long line
## v0.0.2-20251216
### 🛑 Breaking changes 🛑
- `systemd`: Remove systemd instructions (#68)
We can remove systemD instructions as the LD_PRELOAD solution works just as well and applies to any software.
### 💡 Enhancements 💡
- `injector`: Adds support for selectively applying instrumentation to subset of programs running on a system (#84)
The change allows users to implement filters on what to instrument based on the executable name and the command line arguments
- `environment`: Add option to pass custom environment variables to agents (#82)
Now it is possible to pass custom environment variables to agents.
New `all_auto_instrumentation_agents_env_path` configuration option is used to specify path to
the `auto_instrumentation_env.conf` - where custom environment variables could be specified.
Injector will pass these variables to agents.
### 🧰 Bug fixes 🧰
- `nodejs`: test nodeJS support (#127)
Testing identified issues with the RPM and Debian packages.
The Debian and RPM packages now contain the nodeJS dependencies organized in a folder structure rather than an archive.
The configuration points correctly to the file to load to launch autoinstrumentation.
NodeJS tests now run as part of CI.
## v0.0.1-20251030
### 🛑 Breaking changes 🛑
- `injector`: Replace the C-based OpenTelemetry injector with an injector written in Zig, donated by Dash0. (#230)
This new injector will be the foundation for future enhancements of LD_PRELOAD based auto-instrumentation.
It replaces the current injector (written in C) with its setenv-based approach with a new injector (written in Zig)
that overrides getenv.
The previous injector was built in a way that binds to a libc. This works when the injector is distributed as an RPM
or DEB package, but is not suitable for instrumenting workloads on systems where the libc flavor (glibc or musl)
is not known ahead of time, e.g. instrumenting arbitrary Kubernetes workloads.
Furthermore, the new injector behaves more gracefully when the environment variable that is to be injected (e.g.
JAVA_TOOL_OPTIONS, or NODE_OPTIONS) is already present, as it merges existing options with the key-value pairs it
injects.
Since this change is a complete rewrite, it is marked as a breaking change.
open-telemetry-opentelemetry-injector-ea9dca1/CONTRIBUTING.md 0000664 0000000 0000000 00000007663 15240576456 0024224 0 ustar 00root root 0000000 0000000 # How to Contribute to the OpenTelemetry Injector
We'd love your help!
This project is [Apache 2.0 licensed](LICENSE) and accepts contributions via GitHub pull requests. This document outlines some of the conventions on development workflow, contact points and other resources to make it easier to get your contribution accepted.
We gratefully welcome improvements to documentation as well as to code.
## Getting Started
### Pre-requisites
* Docker version 23.0.0 or greater.
### Local development
The injector is written in [Zig](https://ziglang.org/). To work on the injector [source code](src) it is recommended to
install Zig on your machine.
You can find the installation instructions [here](https://ziglang.org/download/).
Install the version referenced in [zig-version](zig-version).
The [Zig Version Manager](https://github.com/tristanisham/zvm) is also a good alternative to installing one specific
version of Zig.
See the page [Zig Learn](https://ziglang.org/learn/) for more information about the language.
### Makefile commands
* `make zig-build` to build the injector binary locally on your machine
* Set a comma-separated list of allowed environment variable prefixes using `ALLOWED_ENV_VAR_PREFIXES`, e.g.: `OTEL_,CUSTOM_PREFIX_`, to allow additional env var prefixes in a custom build. Default value is `OTEL_`.
* `make watch-zig-build` to continually rebuild the Zig sources on every change (requires [`fd`](https://github.com/sharkdp/fd) and [`entr`](https://github.com/eradman/entr) to be installed)
* `make zig-unit-tests` to run the unit tests
* `watch-zig-unit-tests` to continually run the Zig unit tests on every change (requires [`fd`](https://github.com/sharkdp/fd) and [`entr`](https://github.com/eradman/entr) to be installed)
* `make tests` to run the unit tests and the injector integration tests
The DEB and RPM system packages that bundle the injector with the auto-instrumentation agents for supported runtimes live in [open-telemetry/opentelemetry-packaging](https://github.com/open-telemetry/opentelemetry-packaging).
Please open packaging bugs, feature requests, and pull requests against that repository.
### Github PR Workflow
It is recommended to follow the ["GitHub Workflow"](https://guides.github.com/introduction/flow/). When using [GitHub's CLI](https://github.com/cli/cli), here's how it typically looks like:
```bash
gh repo fork github.com/open-telemetry/opentelemetry-injector
git checkout -b your-feature-branch
# do your changes
git commit -sam "Add feature X"
gh pr create
```
## Contributing
Your contribution is welcome! For it to be accepted, we have a few standards that must be followed.
### New features
Before starting the development of a new feature, please create an issue and discuss it with the project maintainers. Features should come with documentation and enough tests (unit and/or end-to-end).
### Bug fixes
Every bug fix should be accompanied by a unit test, so that we can prevent regressions.
### Documentation, typos, ...
They are mostly welcome!
### Adding a Changelog Entry
The [CHANGELOG.md](./CHANGELOG.md) file in this repo is autogenerated from `.yaml` files in the `./.chloggen` directory.
Your pull request should add a new `.yaml` file to this directory. The name of your file must be unique since the last release.
During the collector release process, all `./.chloggen/*.yaml` files are transcribed into `CHANGELOG.md` and then deleted.
If a changelog entry is not required, add the `"Skip Changelog"` label to disable this action.
If your pull request title starts with `chore`, `test`, or `ci`, the action is skipped automatically.
**Recommended Steps**
1. Create an entry file using `make chlog-new`. This generates a file based on your current branch (e.g. `./.chloggen/my-branch.yaml`)
2. Fill in all fields in the new file
3. Run `make chlog-validate` to ensure the new file is valid
4. Commit and push the file
Alternately, copy `./.chloggen/TEMPLATE.yaml`, or just create your file from scratch.
open-telemetry-opentelemetry-injector-ea9dca1/DESIGN.md 0000664 0000000 0000000 00000052310 15240576456 0023253 0 ustar 00root root 0000000 0000000 ## OpenTelemetry Injector Design
The OpenTelemetry injector is a shared library (written in [Zig](https://ziglang.org/)) that is intended to be
used via the environment variable [`LD_PRELOAD`](https://man7.org/linux/man-pages/man8/ld.so.8.html#ENVIRONMENT), the
[`/etc/ld.so.preload`](https://man7.org/linux/man-pages/man8/ld.so.8.html#FILES) file, or similar mechanisms to inject
environment variables into processes at startup.
See [README.md](README.md) for a general purpose overview.
This document focusses on the technical design and the design constraints leading to the approach taken by this project.
In the remainder of this document `LD_PRELOAD` and `/etc/ld.so.preload` are used interchangeably.
## Design Constraints
* The injector must work seamlessly with the two dominant CPU architectures found with Linux workloads, x86_64 and
arm64.
It should be possible to extend the support to other CPU architectures later on.
(Note: When distributed as a container image, it is trivial to achieve this, by compiling the injector binary for all
supported CPU architectures and building a multi-platform image.)
* The injector must work seamlessly with both libc flavors, the [GNU C library](https://sourceware.org/glibc/) (or glibc
for short) and [musl](https://musl.libc.org/).
When adding the injector via `LD_PRELOAD` to systems where the libc flavor is not known ahead of time, this is
crucial to ensure that the injector does not crash executables at startup.
Specifically in a Kubernetes context, tools like Kubernetes operators do typically not know the libc flavor of
container images used in pods, and have no reliable way of finding out.
* The injector must be able to inject environment variables into any dynamically linked, ELF-based Linux executable.
Other formats besides ELF (which are very rare on Linux) are out of scope.
Other operating systems (Windows, macOS, BSD, etc.) are out of scope as well.
* While it is out of scope for this project to inject environment variables into freestanding executables, libc-free
executables, or statically linked executables etc. (only dynamically linked executables are supported because of the
reliance on `LD_PRELOAD`), the injector must not break these types of executables.
That is, using the injector as a system-wide `LD_PRELOAD` setting must not prohibit any executable on the system from
starting correctly.
* As an extension, to the previous point, it is also not acceptable to interfere with the environment of executables
except for the desired modifications.
For example, if the executable reads `JAVA_TOOL_OPTIONS` at startup, it must see the modified value that includes
the `-javaagent` flag added by the injector.
But if the executable reads an unrelated environment variable like `PATH`, it must see exactly what it would see
without the injector being present.
* In general, the injector must not alter the observed behavior of the executable, except for the desired modifications.
* In short, it must always be safe to set up the injector as a system-wide `LD_PRELOAD` hook.
* As a stretch goal, it would be desirable to not pollute the environment with unrelated environment variables, that is,
do not set `NODE_OPTIONS` for a JVM process, or `JAVA_TOOL_OPTIONS` for a Node.js process, etc.
The currently implemented approach does not achieve this.
All known approaches that satisfy this have other, more severe limitations.
Note: Statically linked executables will not be affected by `LD_PRELOAD` at all, but there are
[binaries](#dynamically-linked-libc-free-binaries) that are dynamically linked and affected by `LD_PRELOAD`, but do
_not_ link against any libc.
Binaries of this type require special consideration.
## Design
The approach taken by the OpenTelemetry injector is as follows:
* It assumes it is added as a shared object to the process via `LD_PRELOAD` or `/etc/ld.so.preload`.
When set up this way, whenever a Linux process starts up that is subject to dynamic linking (that is, it uses shared
objects like the C standard library `libc`), the OpenTelemetry injector code is loaded at process startup.
* The OpenTelemetry injector (`libotelinject.so`), via ELF's `.init_array`, executes the following steps at the startup
of the executable, that is, before the actual `main()` function of the executable is called:
* Find out which libc flavor we are dealing with - glibc or musl:
* Read the ELF header section from `/proc/self/exe`, and the dynamic symbol table in particular, then find the
`DT_NEEDED` entries in the dynamic symbol section.
* Inspect the `DT_NEEDED` entries.
If one of them contains the string `musl`, we know that this binary was linked against musl libc at build time.
If one of them contains `libc.so.6`, we know that this binary was linked against glibc at build time.
* Next, we try to find the location of the [`dlsym`](https://www.man7.org/linux/man-pages/man3/dlsym.3.html) symbol in
the mapped memory of the process.
This happens as follows:
* Read `/proc/self/maps` and look for a memory segment that contains the libc shared object.
The libc name found in the previous step facilitates this.
Once a matching memory segment is found, check whether it contains the `dlsym` symbol, i.e. look up the memory
address of that symbol.
If this lookup is successful, we can use it to actually call the `dlsym` function (without declaring a direct
dependency on it).
* Finally, use `dlsym` to find the location of `setenv` and `getenv`.
On glibc < 2.34 (e.g. RHEL 8, Debian Bullseye), `dlsym` is provided by `libdl.so` rather than `libc.so` itself.
If the binary does not link `libdl.so`, `dlsym` will not be found in the libc memory range.
In that case, the injector falls back to looking up `setenv` and `getenv` directly from the ELF symbol table of
the libc memory range, which works because both symbols are always exported directly by `libc.so` on all glibc
versions. Unlike `__environ` (a data symbol), `getenv` is a function and is not subject to copy relocation, so
looking it up from the ELF symbol table is safe regardless of how the executable was linked.
* Use `getenv` to read the existing environment variables for the process.
* Use `setenv` to set or modify the required environment variables (`NODE_OPTIONS`, `JAVA_TOOL_OPTIONS`,
`OTEL_RESOURCE_ATTRIBUTES` etc.)
For .NET, the injector applies an additional check before setting the profiler
and startup-hook related environment variables. It resolves the target application and inspects the adjacent
`*.runtimeconfig.json` file when available, using `runtimeOptions.tfm` to decide
whether the target is a compatible .NET application. It stands down when the application clearly
targets an older framework, but missing, unreadable, malformed, or incomplete runtimeconfig files remain fail-open.
Following that check, the injector also inspects the adjacent `*.deps.json` file when available
and stands down only when the dependency graph already references `OpenTelemetry*` packages. This keeps the injector
fail-open while still reducing the risk of double-instrumentation.
If this sounds convoluted, and more complex than it should be, read on!
The next section outlines which alternative approaches have been considered, and the shortcomings of each of them.
## Alternative Approaches
### Using `setenv` and `getenv` directly
A very simple approach to implementing an injector would be to just declare a dependency on symbools like `setenv` and
`getenv`.
This would require that the injector is compiled and linked against a specific libc flavor, either glibc or musl.
When used as an `LD_PRELOAD` hook on a system that uses a different libc flavor, this would crash all processes at
startup.
For example, if the injector would be linked against musl, the injector binary would explicitly request musl in its ELF
header (e.g. `libc.musl-aarch64.so.1`).
When added via `LD_PRELOAD` on a glibc based system, the kernel would look for this dependency, fail to find it, and
refuse to start the executable.
For the same reason, we can also not declare a direct dependency on `dlsym`.
Another alternative would be to really only declare a dependency on these symbols (e.g. via `extern`) and not provide
it at compile time, relying on the linker/loader to resolve the symbol at process startup.
This way, the injector would work on glibc- as well as musl-based systems, as long as the symbols are present in memory
at process startup.
However, this will approach would crash [binaries](#dynamically-linked-libc-free-binaries) that are subject to dynamic
linking but do not link against any libc.
At startup, the linker/loader would not be able to resolve the symbols the injector declares as dependencies, and refuse
to start the executable.
### Export `getenv`
Instead of trying to depend on existing symbols from libc, the injector could _export_ its own `getenv` symbol to
override libc's `getenv` function.
When a process starts up, and the executable declares that it needs the `getenv` function, the dynamic linker/loader
finds the `getenv` symbol provided by the injector first.
In effect, whenever the process calls `getenv`, the injector's `getenv` implementation is called instead of the original
libc version of that function.
For environment variables that the injector does not care about, it returns the original value, and for the
"interesting" environment variables, it modifies the value on the fly before returning it.
In fact, this strategy would get us 99% of the way, and it has been used in previous incarnations of the OpenTelemetry injector.
To make this work, the injector needs to be able to read the process environment on its own, since it cannot rely
on libc functionality to get the environment.
(And it obviously needs to know the environment to be able to return the original values for environment variables it
does not want to modify and also for appending to the ones it needs to modify, if they are already set.)
One way of doing that is to declare a dependency on the `__environ` symbol (e.g. `extern char **__environ`), which is a
pointer to the in-memory storage of the environment.
Again, this will crash [binaries](#dynamically-linked-libc-free-binaries) that are subject to dynamic linking but do not
link against any libc.
At startup, the linker/loader would not be able to resolve the `__environ` symbol, and refuse to start the executable.
Another way of getting the environment would be to read the file `/proc/self/environ`, which contains the environment
variables as a null-separated list of `KEY=VALUE` strings.
This would solve the problem of the missing `__environ` symbol at startup.
Unfortunately, there are still issues with the approach to export `getenv`:
* Most importantly, a lot of runtimes do not use `getenv` consistently to read environment variables.
Instead, they declare a dependency on the `__environ` symbol (or one of its aliases like `_environ` or `environ`)
directly and read directly from the content of this symbol.
This includes the JVM, Python, and .NET.
Often, this way of reading environment variables without using `getenv` is only is used for in-runtime lookups of
environment variables.
That is, at startup, the native code the runtime is implemented in will actually use `getenv` -- for example, the JVM
reads `JAVA_TOOL_OPTIONS` via `getenv`, the common language runtime for .NET reads `CORECLR_ENABLE_PROFILING`,
`CORECLR_PROFILER` etc. via `getenv` and so on.
But once the runtime is up and running, it will use the content of the `__environ` array (or a copy of that content)
directly for any further lookups of environment variables that are made within Java or .NET code.
This renders the `getenv` override ineffective for injecting `OTEL_RESOURCE_ATTRIBUTES` into the JVM, the CLR or
Python.
(The reason for this is that `OTEL_RESOURCE_ATTRIBUTES` is read within the runtime by the respective OpenTelemetry
SDK, not by the runtime implementation itself.
For the JVM there would be a workaround for `OTEL_RESOURCE_ATTRIBUTES` by adding a `-Dotel.resource.attributes`
to `JAVA_TOOL_OPTIONS`, but there is no generalized workaround that also works for .NET and Python.)
* When using the approach of exporting `getenv`, one has to also take care of modifications of the environment at
runtime.
Imagine the following sequence of events:
* the process calls `getenv("SOME_ENV_VAR"`),
* the injector's `getenv` override returns the value of `SOME_ENV_VAR` from its own memory, which has been
populated (maybe from `__environ` or from `/proc/self/environ` or otherwise) at startup,
* the process later modifies the environment variable (e.g. calls `setenv("SOME_ENV_VAR", "new-value", 1)`,
* the process calls `getenv("SOME_ENV_VAR"`) again,
* the injector's `getenv` override must make sure to return the new value.
This is trivial when declaring a dependency on `__environ` (which has its own problems), but not when
initializing the environment from `/proc/self/environ` at startup, in which case it would probably be required to also
override `setenv`, `putenv`, `clearenv` etc.
### Export the `__environ` symbol
The backing in-memory storage for `getenv`, `setenv` etc. is the symbol `__environ`, a pointer to a list of pointers,
each of which is a string in the form of `KEY=VALUE`.
What if, instead of exporting `getenv`, the injector would export the `__environ` symbol (and its aliases, that is,
`_environ` and `environ`)?
It could initialize that array the same way as libc would do it, by reading the file `/proc/self/environ` (which is
a null-separated list of `KEY=VALUE` strings) at startup, and then populate its own `__environ` array from that.
Then, if the executable declares a dependency on `__environ` (or `_environ` or `environ`), the injector's `__environ`
array would be used instead of the libc version.
This would solve all issues mentioned in the section [export `getenv`](#export-getenv) -- no `extern` dependency on any
libc symbol, consistent behavior when `__environ` is modified after startup, no problems injecting into code that
bypasses `getenv`.
Theoretically, this should also work for the `__environ` symbol used in the libc's implementation of `getenv`, `setenv`
etc., because of how the symbol resolution of the linker works.
However, after some experiments, this approach turned out to be unfeasible.
An injector with this approach can successfully inject environment variables into _some_ binaries.
In particular, this worked with some shells.
Since shells are used as entrypoints in many container images, it may seem as if this works reliably, because the
injector modifies the environment of the shell entrypoint successfully, and then any process started from that shell
inherits the modified environment.
However, when using container images which use the binary (e.g. the JVM, Node.js, ...) as their entrypoint directly,
without using a shell entrypoint, this approach fails to work for some binaries.
The reason is that libc will override the content of `__environ` with the value of `envp` in its own initialization
procedure, or in the `execve` system call, that is, after the injector has set up the `__environ` content, but before
the application's `main()` function is called.
There is currently no known way an `LD_PRELOAD`-based injector can hook into this process.
### Look up `setenv` and `__environ` at runtime, and still override `getenv`
With the current approach outlined in the [design](#design) section, we can solve all requirements without breaking
any executables.
But since the approach makes its modifications via `setenv`, it will pollute the environment of all processes with
all environment variables it sets, even if they are not relevant for the specific binary.
That is, all process will see `NODE_OPTIONS`, `JAVA_TOOL_OPTIONS` and all the .NET related environment variables, even
if it is not a Node.js, JVM or .NET process.
Could we not export and override libc's `getenv` and handle the injection of `NODE_OPTIONS`, `JAVA_TOOL_OPTIONS` etc.
(which are read via `getenv`) that way, and only use `setenv` for injecting `OTEL_RESOURCE_ATTRIBUTES` (which is not
read via `getenv` by some runtimes, as explained above)?
That would give us all the benefits of the `getenv` override approach (less environment variable pollution), without any
of the drawbacks described in the section [export `getenv`](#export-getenv).
There is an issue that makes this particular strategy prohibitive:
there can be shared libraries that look up environment variables very early in the startup process, even before the
injector had a chance to run its initialization code.
A prominent example is OpenSSL, which is used by many runtimes and applications.
The OpenSSL code, when run on arm64 CPUS, reads `OPENSSL_armcap` (a capabilities bitmask) before the injector's init
code runs, that is, before it even had the chance to find the `__environ` pointer and read the process environment.
This would lead to the injector reporting `OPENSSL_armcap=null` to OpenSSL, even if it is actually set.
Obviously, this is also not acceptable, hence exporting `getenv` is not a viable approach.
In the end, avoiding the risk of breaking assumptions about the environment is deemed much more critical than not adding
irrelevant environment variables to the environment of all processes, which is effectively more an aesthetics concern.
If an executable does not read `NODE_OPTIONS` (because it is not Node.js), or `JAVA_TOOL_OPTIONS` (because it is not a
JVM), it effectively makes no difference that these variables are added.
## Dynamically Linked libc-free Binaries
Several of the sections above make reference to binaries that are dynamically linked, but do not link against any libc,
and how that is problematic for an `LD_PRELOAD`-based injector, especially when it declares a dependency on any symbol
that is usually provided by libc, like `setenv`, `getenv` or `__environ`.
But does something like this actually exist out in the wild? Yes, it does.
One example is the `aws-vpc-cni` binary (and probably other related `aws-` binaries that are built in the same way),
from the suite of CNI network plug-ins, which runs in Kubernetes pods in the `kube-system` namespace in EKS clusters.
Here is how this binary is
[built](https://github.com/aws/amazon-vpc-cni-k8s/blob/4ee9789484258d1ae8f6bf36859ea325097d5d7b/Makefile#L149-L152):
It is written in Go and built with `-buildmode=pie` and `-ldflags '-s -w'`.
There is also a [trivial test application](injector-integration-tests/apps/no-getenv-symbol) that is built in the
same way, contained in this repository.
When using an `LD_PRELOAD`-based injector that declares a dependency on `__environ` (or any other libc symbol), a binary
built in this way will crash at startup with an error message like this:
```
/app/aws-vpc-cni: symbol lookup error: /path/to/libotelinject.so: undefined symbol: __environ
```
This is because the binary is dynamically linked, hence it is affected by `LD_PRELOAD`, but it does not link against
any libc, hence the `__environ` symbol cannot be resolved.
This was a known issue in a previous version of the injector, the current implementation has solved this problem by
not declaring any direct dependencies on external symbols.
## Why Zig?
Desirable characteristics for the programming language for the injector:
* No dependency on libc: In particular when using the injector in a container environment, you cannot know ahead of time
whether the processes the injector attaches to are based on glibc or musl.
Binding the injector itself to a specific libc flavor or version would be problematic, as it would crash processes
that bind a different libc.
* Provide a rich enough set of standard functionality, without depending on a libc.
A lot of compiled languages can be built without binding libc, but they then also usually lack basic functions, like
string comparisons etc. and you end up re-implementing these basics.
* Manual memory management: The injector needs to introduce as little overhead as possible to the system and the
processes it attaches to, in terms of memory, CPU usage, and startup time.
Manual memory management ensures the injector code is very deliberate about the memory it allocates.
Not relying on garbage collection also works in favor of avoiding accidental CPU usage overhead.
Zig has combination of characteristics that make it a good match for the items listed above:
* It does not bind a libc flavor, but still provides a rich standard library.
* It does not have automatic memory management, but relies on manual memory management instead.
Let's compare this to some other programming languages that might be used for the injector:
* The preference for manual memory management rules out Go.
* Rust is also brought up fairly often, but it binds libc by default.
`#![no_std]` is available, but that also removes access to basic functionality (printing, working with strings).
* Traditionally, similar technology has been written in C++ or plain C.
This is possible, but again, without binding to libc, you would have to rewrite a lot of basic functionality.
Also, Zig avoids a lot of the footguns that C code can introduce, that is, code written in Zig is probably usually
safer than C.
* Zig also supposedly compiles fairly [fast](https://mitchellh.com/writing/zig-builds-getting-faster), making it
pleasant to work with (that said, the injector code base is quite small, so compiler perfomance is not very crucial).
open-telemetry-opentelemetry-injector-ea9dca1/Dockerfile 0000664 0000000 0000000 00000001116 15240576456 0023750 0 ustar 00root root 0000000 0000000 ARG DOCKER_REPO=docker.io
FROM ${DOCKER_REPO}/alpine:3.24.1@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b AS build-injector
RUN apk add --no-cache make
ARG ZIG_ARCHITECTURE
RUN mkdir -p /opt/zig
WORKDIR /opt/zig
COPY zig-version .
RUN . /opt/zig/zig-version && \
wget -q -O /tmp/zig.tar.gz https://ziglang.org/download/${ZIG_VERSION%-*}/zig-${ZIG_ARCHITECTURE}-linux-${ZIG_VERSION}.tar.xz && \
tar --strip-components=1 -xf /tmp/zig.tar.gz
ENV PATH="$PATH:/opt/zig"
WORKDIR /libotelinject
COPY Makefile .
COPY build.zig .
COPY build.zig.zon .
COPY src src
open-telemetry-opentelemetry-injector-ea9dca1/LICENSE 0000664 0000000 0000000 00000026135 15240576456 0022773 0 ustar 00root root 0000000 0000000 Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
open-telemetry-opentelemetry-injector-ea9dca1/Makefile 0000664 0000000 0000000 00000014670 15240576456 0023427 0 ustar 00root root 0000000 0000000 ARCH?=amd64
VERSION?=0.0.0-dev
ALLOWED_ENV_VAR_PREFIXES?=OTEL_
INSTALL_DIR:=/usr/lib/opentelemetry/otelinject
DIST_DIR_BINARY:=dist
BINARY_NAME_PREFIX:=libotelinject
BINARY_NAME_NO_ARCH:=$(BINARY_NAME_PREFIX).so
BINARY_NAME:=$(BINARY_NAME_PREFIX)_$(ARCH).so
# Docker repository used.
DOCKER_REPO?=docker.io
DIST_SRCS:=\
$(wildcard src/*.*) \
build.zig \
build.zig.zon \
Dockerfile \
zig-version
DIST_TARGET:=$(DIST_DIR_BINARY)/$(BINARY_NAME)
.PHONY: all
all: so/$(BINARY_NAME_NO_ARCH)
so:
@mkdir -p so
obj:
@mkdir -p obj
.PHONY: clean
clean:
rm -rf so $(DIST_DIR_BINARY) zig-out .zig-cache
so/$(BINARY_NAME_NO_ARCH): so
zig build -Dcpu-arch=${ARCH} -Dallowed-env-var-prefixes='$(ALLOWED_ENV_VAR_PREFIXES)' --prominent-compile-errors --summary none
$(DIST_TARGET): $(DIST_SRCS)
@echo building the injector binary for architecture $(ARCH)
@set -e
@mkdir -p $(DIST_DIR_BINARY)
if [[ "$(ARCH)" = arm64 ]]; then \
ZIG_ARCHITECTURE=aarch64; \
elif [[ "$(ARCH)" = amd64 ]]; then \
ZIG_ARCHITECTURE=x86_64; \
fi; \
docker buildx build --platform linux/$(ARCH) --build-arg DOCKER_REPO=$(DOCKER_REPO) --build-arg ZIG_ARCHITECTURE=$$ZIG_ARCHITECTURE -o type=image,name=libotelinject-builder:$(ARCH),push=false .
docker rm -f libotelinject-builder 2>/dev/null || true
docker run -d --platform linux/$(ARCH) --name libotelinject-builder libotelinject-builder:$(ARCH) sleep inf
docker exec libotelinject-builder make ARCH=$(ARCH) ALLOWED_ENV_VAR_PREFIXES='$(ALLOWED_ENV_VAR_PREFIXES)' SHELL=/bin/sh all
docker cp libotelinject-builder:/libotelinject/so/$(BINARY_NAME_NO_ARCH) $(DIST_DIR_BINARY)/$(BINARY_NAME)
docker rm -f libotelinject-builder
.PHONY: dist
dist: $(DIST_TARGET)
# Run this to install and enable the auto-instrumentation files. Mostly intended for development.
.PHONY: install
install: all uninstall
mkdir -p $(INSTALL_DIR)
cp javaagent.jar $(INSTALL_DIR)
cp so/$(BINARY_NAME_NO_ARCH) $(INSTALL_DIR)
echo $(INSTALL_DIR)/$(BINARY_NAME_NO_ARCH) > /etc/ld.so.preload
.PHONY: uninstall
uninstall:
rm -f /etc/ld.so.preload
rm -f $(INSTALL_DIR)/javaagent.jar
rm -f $(INSTALL_DIR)/$(BINARY_NAME_NO_ARCH)
# Run this from with this directory to build and run the development container.
# Once you have a command line inside the container, you can run make zig-build, make zig-unit-tests,
# make watch-zig-build, make watch-zig-unit-tests etc.
# Alternatively, you can also use the same commands directly on your development machine, without using the development
# container.
# By explicitly setting ARCH=arm64 or ARCH=amd64 you can run and test on different CPU platforms.
# Mostly intended for development.
.PHONY: docker-dev-run
docker-dev-run:
ARCH=$(ARCH) ./start-injector-dev-container.sh
.PHONY: check-zig-installed
check-zig-installed:
@set +x
@if ! zig version > /dev/null; then \
echo "error: zig is not installed. Run 'brew install zig' or similar."; \
exit 1; \
fi
.PHONY: zig-build
zig-build: check-zig-installed
@mkdir -p so
@(zig build -Dcpu-arch=${ARCH} -Dallowed-env-var-prefixes='$(ALLOWED_ENV_VAR_PREFIXES)' --prominent-compile-errors --summary none && echo $(shell date) build successful) || (echo $(shell date) build failed && exit 1)
.PHONY: watch-zig-build
watch-zig-build: check-zig-installed
@fd -e zig | entr make zig-build
.PHONY: zig-unit-tests
zig-unit-tests: check-zig-installed
@(zig build test -Dcpu-arch=${ARCH} -Dallowed-env-var-prefixes='$(ALLOWED_ENV_VAR_PREFIXES)' --prominent-compile-errors --summary none && echo $(shell date) tests successful) || (echo $(shell date) tests failed && exit 1)
.PHONY: watch-zig-unit-tests
watch-zig-unit-tests: check-zig-installed
@fd -e zig | entr make zig-unit-tests
.PHONY: tests
tests: zig-unit-tests injector-integration-tests-for-one-architecture
.PHONY: injector-integration-tests-for-one-architecture
injector-integration-tests-for-one-architecture:
ARCHITECTURES=$(ARCH) injector-integration-tests/scripts/test-all.sh
.PHONY: injector-integration-tests-for-all-architectures
injector-integration-tests-for-all-architectures:
injector-integration-tests/scripts/test-all.sh
.PHONY: lint
lint: zig-fmt-check zig-validate-test-imports shellcheck-lint
.PHONY: zig-fmt-check
zig-fmt-check: check-zig-installed
@zig fmt --check src
# Run this to auto-format Zig code.
.PHONY: zig-fmt
zig-fmt: check-zig-installed
zig fmt src
.PHONY: zig-validate-test-imports
zig-validate-test-imports:
@set -e; \
files=$$(cd src && grep -l 'test "' ./*.zig 2>/dev/null || true); \
[ -n "$$files" ] || { echo "None of the .zig files contain any tests, this is likely an error in the zig-validate-test-imports make recipe."; exit 1; }; \
echo $$names; \
names=$$(printf '%s\n' $$files | sed -e 's|.*/||'); \
missing=0; \
for n in $$names; do \
if ! grep -q "@import(\"$$n\")" src/test.zig; then \
echo "- The file \"src/test.zig\" is missing an import for \"$$n\", tests in \"$$n\" will ignored."; \
missing=1; \
fi; \
done; \
if [ $$missing -gt 0 ]; then \
echo ;\
echo "The file \"src/test.zig\" is missing imports to files with Zig unit tests, see above. Please add all files with test cases to \"src/test.zig\"."; \
exit 1; \
fi
.PHONY: check-shellcheck-installed
check-shellcheck-installed:
@set +x
@if ! shellcheck --version > /dev/null; then \
echo "error: shellcheck is not installed. See https://github.com/koalaman/shellcheck?tab=readme-ov-file#installing for installation instructions."; \
exit 1; \
fi
.PHONY: shellcheck-lint
shellcheck-lint: check-shellcheck-installed
@echo "linting shell scripts with shellcheck"
find . -name \*.sh | xargs shellcheck -x
SHELL = /bin/bash
.SHELLFLAGS = -o pipefail -c
# SRC_ROOT is the top of the source tree.
SRC_ROOT := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
TOOLS_BIN_DIR := $(SRC_ROOT)/.tools
CHLOGGEN_CONFIG := .chloggen/config.yaml
CHLOGGEN := $(TOOLS_BIN_DIR)/chloggen
$(TOOLS_BIN_DIR):
mkdir -p $@
$(CHLOGGEN): $(TOOLS_BIN_DIR)
GOBIN=$(TOOLS_BIN_DIR) go install go.opentelemetry.io/build-tools/chloggen@v0.23.1
FILENAME?=$(shell git branch --show-current)
.PHONY: chlog-new
chlog-new: $(CHLOGGEN)
$(CHLOGGEN) new --config $(CHLOGGEN_CONFIG) --filename $(FILENAME)
.PHONY: chlog-validate
chlog-validate: $(CHLOGGEN)
$(CHLOGGEN) validate --config $(CHLOGGEN_CONFIG)
.PHONY: chlog-preview
chlog-preview: $(CHLOGGEN)
$(CHLOGGEN) update --config $(CHLOGGEN_CONFIG) --dry
.PHONY: chlog-update
chlog-update: $(CHLOGGEN)
$(CHLOGGEN) update --config $(CHLOGGEN_CONFIG) --version $(VERSION)
list:
@grep '^[^#[:space:]].*:' Makefile
open-telemetry-opentelemetry-injector-ea9dca1/README.md 0000664 0000000 0000000 00000065025 15240576456 0023246 0 ustar 00root root 0000000 0000000 ## OpenTelemetry Injector
> [!IMPORTANT]
> **The DEB and RPM packages for the OpenTelemetry Injector have moved.**
> They are now built and released from
> [open-telemetry/opentelemetry-packaging](https://github.com/open-telemetry/opentelemetry-packaging).
> Download the latest `.deb` / `.rpm` from that repository's
> [releases page](https://github.com/open-telemetry/opentelemetry-packaging/releases).
>
> This repository publishes only the raw `libotelinject.so` shared library.
> Please open packaging bugs and feature requests against `opentelemetry-packaging`.
The OpenTelemetry injector is a shared library (written in [Zig](https://ziglang.org/)) that is intended to be
used via the environment variable [`LD_PRELOAD`](https://man7.org/linux/man-pages/man8/ld.so.8.html#ENVIRONMENT), the
[`/etc/ld.so.preload`](https://man7.org/linux/man-pages/man8/ld.so.8.html#FILES) file, or similar mechanisms to inject
environment variables into processes at startup.
It serves two main purposes:
* Inject an OpenTelemetry auto-instrumentation agent into the process to capture and report distributed traces and
metrics to the [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) for supported runtimes.
* Set resource attributes automatically (for example Kubernetes related resource attributes and service related
resource attributes in environments where this is applicable).
The injector can be used to enable automatic zero-touch instrumentation of processes.
For this to work, the injector binary needs to be bundled together with the OpenTelemetry auto-instrumentation agents
for the target runtimes.
Official RPM and DEB packages that bundle the injector together with auto-instrumentation
agents for supported runtimes are built and published from the
[open-telemetry/opentelemetry-packaging](https://github.com/open-telemetry/opentelemetry-packaging) repository.
The OpenTelemetry injector Debian/RPM packages install the OpenTelemetry auto-instrumentation agents, the
`libotelinject.so` shared object library, and a default configuration file to automatically instrument applications and
services to capture and report distributed traces and metrics to the
[OpenTelemetry Collector](https://opentelemetry.io/docs/collector/).
This repository publishes only the raw `libotelinject.so` shared library.
The `opentelemetry-injector` deb/rpm package installs and supports configuration of the following auto-instrumentation
agents:
- [Java](https://opentelemetry.io/docs/zero-code/java/)
- [Node.js](https://opentelemetry.io/docs/zero-code/js/)
- [.NET](https://opentelemetry.io/docs/zero-code/dotnet/)
- [Ruby](https://github.com/open-telemetry/opentelemetry-ruby-instrumentation)
- Python (disabled by default, see [Enabling Auto-Instrumentation for Python](#enabling-auto-instrumentation-for-python))
## Activation and Configuration
This method requires `root` privileges.
1. Add the path of the provided `/usr/lib/opentelemetry/libotelinject.so` shared object library to the
[`/etc/ld.so.preload`](https://man7.org/linux/man-pages/man8/ld.so.8.html#FILES) file to activate auto-
instrumentation for ***all*** supported processes on the system. For example:
```
echo /usr/lib/opentelemetry/libotelinject.so >> /etc/ld.so.preload
```
Alternatively, set the environment variable `LD_PRELOAD=/usr/lib/opentelemetry/libotelinject.so` for a specific
process to activate auto-instrumentation for that process. For example:
```
LD_PRELOAD=/usr/lib/opentelemetry/libotelinject.so node myapp.js
```
2. The default configuration file `/etc/opentelemetry/injector/injector.conf` includes the required settings, i.e. the paths to
the respective auto-instrumentation agents per runtime:
```
dotnet_auto_instrumentation_agent_path_prefix=/usr/lib/opentelemetry/dotnet
jvm_auto_instrumentation_agent_path=/usr/lib/opentelemetry/jvm/javaagent.jar
nodejs_auto_instrumentation_agent_path=/usr/lib/opentelemetry/nodejs/node_modules/@opentelemetry/auto-instrumentations-node/build/src/register.js
```
You can override the location of the configuration file by setting `OTEL_INJECTOR_CONFIG_FILE`.
You may want to modify this file for a couple of reasons:
- You want to provide your own instrumentation files.
- You want to selectively disable auto-instrumentation, either for all runtimes or for a subset of runtimes.
See
[Disabling auto-instrumentation for all runtimes or specific runtimes](#disabling-auto-instrumentation-for-all-runtimes-or-specific-runtimes)
for more information.
- You want to selectively enable (or disable) auto-instrumentation for a subset of programs (services) on your system.
For example, you may want to only enable instrumentation of services that match a specific executable path pattern, or
to programs that do not contain certain arguments on the command line.
See [details on configuring the program inclusion and exclusion criteria](#details-on-configuring-the-program-inclusion-and-exclusion-criteria) for more information.
The values set in the configuration file can be overridden with environment variables.
- `DOTNET_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX`: the path to the directory containing the .NET auto-instrumentation
agent files
- `DOTNET_AUTO_INSTRUMENTATION_MINIMUM_DOTNET_MAJOR_VERSION`: the minimum .NET major version an application (as
determined by inspecting its `*.runtimeconfig.json` file) needs to target to be eligible for .NET
auto-instrumentation; can also be set via the configuration file key
`dotnet_auto_instrumentation_minimum_dotnet_major_version`. The default is `8`, matching the .NET versions
supported by the upstream OpenTelemetry .NET auto-instrumentation. Distributions of the .NET
auto-instrumentation that support older .NET versions can lower this threshold accordingly.
- `JVM_AUTO_INSTRUMENTATION_AGENT_PATH`: the path to the Java auto-instrumentation agent JAR file
- `NODEJS_AUTO_INSTRUMENTATION_AGENT_PATH`: the path to the Node.js auto-instrumentation agent registration file
- `PYTHON_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX`: the path to the directory containing the Python auto-instrumentation agent files (Python is disabled by default, see [Enabling Auto-Instrumentation for Python](#enabling-auto-instrumentation-for-python))
- `RUBY_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX`: the path to the directory containing the Ruby auto-instrumentation gem bundle
- `OTEL_INJECTOR_INCLUDE_PATHS`: a comma-separated list of glob patterns to match executable paths
- `OTEL_INJECTOR_EXCLUDE_PATHS`: a comma-separated list of glob patterns to exclude executable paths
- `OTEL_INJECTOR_INCLUDE_WITH_ARGUMENTS`: a comma-separated list of glob patterns to match process arguments
- `OTEL_INJECTOR_EXCLUDE_WITH_ARGUMENTS`: a comma-separated list of glob patterns to exclude process arguments
- `OTEL_INJECTOR_AUTO_INSTRUMENTATION_DISABLED`: either `*` to disable all auto-instrumentation for all runtimes,
or a comma-separated list of runtimes for which to disable auto-instrumentation, see
[Disabling auto-instrumentation for all runtimes or specific runtimes](#disabling-auto-instrumentation-for-all-runtimes-or-specific-runtimes)
3. (Optional) The default env agent configuration file `/etc/opentelemetry/injector/default_env.conf` is empty (use
`all_auto_instrumentation_agents_env_path` option to specify a different path). Environment variables added to this file
will be passed to all agents' environments. **NOTE**: by default, environment variables which do not start with
`OTEL_` are ignored. If you need to allow additional prefixes in a custom build, compile the injector with
`zig build -Dallowed-env-var-prefixes=OTEL_,CUSTOM_PREFIX_`. This setting is build-time only.
The `auto_instrumentation_env.conf` file format is the same as other configurations:
```
OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317
OTEL_PROPAGATORS=tracecontext,baggage
```
4. Reboot the system or restart the applications/services for any changes to take effect. The `libotelinject.so` shared
object library will then be preloaded for all subsequent processes and inject the environment variables from the
`/etc/opentelemetry/injector/injector.conf` configuration files for the process types you've configured (Java, .Net, Node.js or Ruby).
When providing your own instrumentation files (for example via environment variables like `DOTNET_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX`) the following directory structure is expected:
- `JVM_AUTO_INSTRUMENTATION_AGENT_PATH`: This path must point to the Java auto-instrumentation agent JAR file `opentelemetry-javaagent.jar`.
- `NODEJS_AUTO_INSTRUMENTATION_AGENT_PATH`: The path to an installation of the npm module `@opentelemetry/auto-instrumentations-node`.
- `RUBY_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX`: this path must be a directory containing `glibc` and `musl` subdirectories. Depending on the libc flavor that the injector detects at startup, the matching subdirectory (a gem home with the `opentelemetry-auto-instrumentation.rb` entry point) is used.
- `DOTNET_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX`: this path must be a directory that contains the following
subdirectories and files:
- For `x86_64` systems using `glibc`:
- `glibc/linux-x64/OpenTelemetry.AutoInstrumentation.Native.so`
- `glibc/AdditionalDeps`
- `glibc/store`
- `glibc/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll`
- For `x86_64` systems using `musl`:
- `musl/linux-musl-x64/OpenTelemetry.AutoInstrumentation.Native.so`
- `musl/AdditionalDeps`
- `musl/store`
- `musl/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll`
- For `arm64` systems using `glibc`:
- `glibc/linux-arm64/OpenTelemetry.AutoInstrumentation.Native.so`
- `glibc/AdditionalDeps`
- `glibc/store`
- `glibc/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll`
- For `arm` systems using `musl`:
- `musl/linux-musl-arm64/OpenTelemetry.AutoInstrumentation.Native.so`
- `musl/AdditionalDeps`
- `musl/store`
- `musl/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll`
Note that the defaults provided by the RPM and Debian packages from
[open-telemetry/opentelemetry-packaging](https://github.com/open-telemetry/opentelemetry-packaging) take care of all of that, and it is not necessary to edit `/etc/opentelemetry/injector/injector.conf` or set any of the above environment variables.
Check the following for details about the auto-instrumentation agents and further configuration options:
- [Java](https://opentelemetry.io/docs/zero-code/java/agent/configuration/)
- [Node.js](https://opentelemetry.io/docs/zero-code/js/configuration/)
- [.NET](https://opentelemetry.io/docs/zero-code/dotnet/configuration/)
- [Ruby](https://github.com/open-telemetry/opentelemetry-ruby-instrumentation)
### Environment Modifications
Here is an overview of the modifications that the injector will apply:
* It sets (or appends to) `NODE_OPTIONS` to activate the Node.js instrumentation agent.
* It sets (or prepends to) `RUBYOPT` to require the Ruby auto-instrumentation gem, and sets `OTEL_RUBY_ADDITIONAL_GEM_PATH` so the gem can locate its bundled dependencies. If `OTEL_RUBY_ADDITIONAL_GEM_PATH` is already set in the process's environment, the injector respects that value and also skips modifying `RUBYOPT` (the two variables are a coupled pair — injecting only the `-r` flag would make the gem look for its dependencies in the user-provided path and fail with `LoadError`).
* It adds a `-javaagent` flag to `JAVA_TOOL_OPTIONS` to activate the Java OTel SDK.
* It conditionally sets the required environment variables for activating the OpenTelemetry SDK for .NET:
* `CORECLR_ENABLE_PROFILING`
* `CORECLR_PROFILER`
* `CORECLR_PROFILER_PATH`
* `DOTNET_ADDITIONAL_DEPS`
* `DOTNET_SHARED_STORE`
* `DOTNET_STARTUP_HOOKS`
* `OTEL_DOTNET_AUTO_HOME`
* Note that the injector will not append to existing environment variables but overwrite them unconditionally if
they are already set.
In contrast to other runtimes, .NET does not support adding multiple agents.
* The injector first inspects the adjacent `*.runtimeconfig.json` file of the target application when it is
available.
* The injector stands down if the specified runtime version does not target a supported .NET version. By
default, the minimum supported .NET major version is 8, matching the .NET versions supported by the upstream
OpenTelemetry .NET auto-instrumentation; it can be changed via the configuration file key
`dotnet_auto_instrumentation_minimum_dotnet_major_version` or the environment variable
`DOTNET_AUTO_INSTRUMENTATION_MINIMUM_DOTNET_MAJOR_VERSION`.
* If the `.runtimeconfig.json` file is missing, unreadable, malformed, or missing the expected fields, the
injector proceeds with additional .NET checks.
* To reduce the risk of double-instrumentation, the injector then inspects the adjacent `*.deps.json` file of the
target application when it is available.
* The injector stands down if that `.deps.json` file already references `OpenTelemetry*` packages.
* If the `.deps.json` file is missing, unreadable, malformed, or missing the expected fields, the
injector proceeds with .NET injection.
* It inspects specific existing environment variables and populates `OTEL_RESOURCE_ATTRIBUTES` with additional resource
attributes. These environment variables need to be set externally (for example by a Kubernetes operator with a mutating
webhook on the pod spec template of the workload). If `OTEL_RESOURCE_ATTRIBUTES` is already set, the additional
key-value pairs are appended to the existing value of `OTEL_RESOURCE_ATTRIBUTES`. Existing key-value pairs are not
overwritten, that is if e.g. `OTEL_RESOURCE_ATTRIBUTES` already has a key-value pair for `k8s.pod.name`, the existing
key-value pair takes priority.
The following environment variables and resource attributes are supported:
* `OTEL_INJECTOR_RESOURCE_ATTRIBUTES` is expected to contain key-value pairs
(e.g. `my.resource.attribute=value,my.other.resource.attribute=another-value`) and will be added as-is.
* `OTEL_INJECTOR_SERVICE_NAME` will be translated to `service.name`
* `OTEL_INJECTOR_SERVICE_VERSION` will be translated to `service.version`
* `OTEL_INJECTOR_SERVICE_NAMESPACE` will be translated to `service.namespace`
* `OTEL_INJECTOR_K8S_NAMESPACE_NAME` will be translated to `k8s.namespace.name`
* `OTEL_INJECTOR_K8S_POD_NAME` will be translated to `k8s.pod.name`
* `OTEL_INJECTOR_K8S_POD_UID` will be translated to `k8s.pod.uid`
* `OTEL_INJECTOR_K8S_CONTAINER_NAME` will be translated to `k8s.container.name`
#### Mapping Kubernetes Resource Attributes
While you can set all resource attributes with `OTEL_INJECTOR_RESOURCE_ATTRIBUTES`, the additional environment
variables controlling individual resource attributes (like `OTEL_INJECTOR_SERVICE_NAME` or
`OTEL_INJECTOR_K8S_NAMESPACE_NAME`) are useful in Kubernetes for deriving resource attributes via
[field selectors](https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/#use-pod-fields-as-values-for-environment-variables),
e.g. by adding a snippet like this to the pod spec template:
```
- name: OTEL_INJECTOR_SERVICE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.labels['app.kubernetes.io/name']
```
The following provides an overview of the intended mappings:
| Environment Variable | Intended Mapping |
| ---------------------------------- | ---------------- |
| `OTEL_INJECTOR_K8S_NAMESPACE_NAME` | `valueFrom.fieldRef.fieldPath: metadata.namespace` |
| `OTEL_INJECTOR_K8S_POD_NAME` | `valueFrom.fieldRef.fieldPath: metadata.name` |
| `OTEL_INJECTOR_K8S_POD_UID` | `valueFrom.fieldRef.fieldPath: metadata.uid` |
| `OTEL_INJECTOR_K8S_CONTAINER_NAME` | The container's name (no field selector) |
| `OTEL_INJECTOR_SERVICE_NAME` | `valueFrom.fieldRef.fieldPath: metadata.labels['app.kubernetes.io/name']` |
| `OTEL_INJECTOR_SERVICE_VERSION` | `valueFrom.fieldRef.fieldPath: metadata.labels['app.kubernetes.io/version']` |
| `OTEL_INJECTOR_SERVICE_NAMESPACE` | `valueFrom.fieldRef.fieldPath: metadata.labels['app.kubernetes.io/part-of']` |
The environment variable `OTEL_INJECTOR_RESOURCE_ATTRIBUTES` can be set to key-value pairs derived from the
annotations `resource.opentelemetry.io/*`, to support mapping annotations like
`resource.opentelemetry.io/service.namespace`, `resource.opentelemetry.io/service.name` to their respective resource
attributes.
See also:
* https://opentelemetry.io/docs/specs/semconv/resource/k8s/
* https://opentelemetry.io/docs/specs/semconv/non-normative/k8s-attributes/
* https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/#use-pod-fields-as-values-for-environment-variables
### Enabling Auto-Instrumentation for Python
Python auto-instrumentation is currently disabled by default and no default Python auto-instrumentation agent is
included in the system packages.
Python instrumentation needs to be enabled explicitly by providing a Python auto-instrumentation agent and a
custom injector.conf file with python_auto_instrumentation_agent_path_prefix set or by setting
PYTHON_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX.
The configured path is expected to contain two directories, `glibc` and `musl`.
Depending on the libc flavor that the injector detects at startup, either the `glibc` or the `musl` directory will be
prepended to `PYTHONPATH`, and thus loaded first by the Python interpreter.
Be aware that it is not always safe to inject the additional Python packages due to possible dependency conflicts.
### Configure the Injector's Logging
By default, the injector only logs errors.
Set the environment variable `OTEL_INJECTOR_LOG_LEVEL` to change the log level.
Valid values are:
- `debug`
- `info`
- `warn`
- `error` - this is the default value
- `none` - suppress all log output from the injector; this is useful for scenarios where you pipe `stderr` into another
process and parse it.
The injector's log message will be written to `stderr` of the process that is being instrumented.
### Details on configuring the program inclusion and exclusion criteria
If you want to selectively enable (or disable) auto-instrumentation for a subset of programs (services) on your system,
the configuration file provides a couple of settings which can be used alone or in combination to produce
the desired outcome.
By default, all processes are instrumented. Each non-empty include setting adds a condition that a process
must satisfy to be instrumented — all such conditions must be met (AND across settings). Within a single
setting, entries are ORed: any one matching pattern is sufficient to satisfy that setting. Exclusions take
precedence over inclusions.
- `include_paths` - A comma-separated list of glob patterns to match executable paths.
- `exclude_paths` - A comma-separated list of glob patterns to exclude executable paths.
- `include_with_arguments` - A comma-separated list of glob patterns to match process arguments.
- `exclude_with_arguments` - A comma-separated list of glob patterns to exclude process arguments.
For example, in the following configuration, all program executables in the
`/app/system/` directory will not be instrumented, even though the `/app` directory is
included for instrumentation:
```
dotnet_auto_instrumentation_agent_path_prefix=/usr/lib/opentelemetry/dotnet
jvm_auto_instrumentation_agent_path=/usr/lib/opentelemetry/jvm/javaagent.jar
nodejs_auto_instrumentation_agent_path=/usr/lib/opentelemetry/nodejs/node_modules/@opentelemetry/auto-instrumentations-node/build/src/register.js
include_paths=/app/*,/utilities/*
exclude_paths=/app/system/*
```
To give you an idea of what types of inclusion and exclusion criteria can be defined, let's
look at the following example:
```
dotnet_auto_instrumentation_agent_path_prefix=/usr/lib/opentelemetry/dotnet
jvm_auto_instrumentation_agent_path=/usr/lib/opentelemetry/jvm/javaagent.jar
nodejs_auto_instrumentation_agent_path=/usr/lib/opentelemetry/nodejs/node_modules/@opentelemetry/auto-instrumentations-node/build/src/register.js
include_paths=/app/*,/utilities/*,*.exe
exclude_with_arguments=-javaagent:*,*@opentelemetry-js*,-Xmx?m
include_with_arguments=*MyProject*.jar,*app.js
```
In the example above, both `include_paths` and `include_with_arguments` are configured, so a process
must satisfy **both** to be instrumented. We'll instrument programs that:
- run from the `/app` or `/utilities` directories, or have an `.exe` extension (`include_paths`)
- **and** have a command line argument matching `*MyProject*.jar` or ending in `app.js` (`include_with_arguments`)
- however, even if both include conditions are met, the injector **will avoid** programs that have:
- a command line argument starting with `-javaagent:`
- a command line argument containing `@opentelemetry-js`
- a maximum memory argument matching `-Xmx?m` (single digit megabytes)
The example above illustrates how we avoid telemetry from unwanted applications or
injecting auto-instrumentation to programs that are already instrumented. If you have a
standard way of deploying all of your applications, you can create a default `injector.conf`
file that will ensure you get only the telemetry you want.
Multiple lines of the same setting are combined as a union (OR). This means that if you define multiple
lines of `include_paths`, for example, the resulting patterns list will be a union of all of the lines.
This allows for easier manipulation of the configuration file with automated tools. Essentially, you can
list each pattern on a separate line. Note that different settings (e.g. `include_paths` and
`include_with_arguments`) are ANDed together — a process must satisfy each configured include setting.
For example, the following two configuration files have an identical outcome:
```
include_paths=/app/*,/utilities/*,*.exe
```
is the same as:
```
include_paths=/app/*
include_paths=/utilities/*
include_paths=*.exe
```
### Disabling auto-instrumentation for all runtimes or specific runtimes
To disable auto-instrumentation for all runtimes, set `auto_instrumentation_disabled=*` in the configuration file,
or set `OTEL_INJECTOR_AUTO_INSTRUMENTATION_DISABLED=*` as an environment variable.
To selectively disable auto-instrumentation for one or more specific runtimes, set `auto_instrumentation_disabled`
or `OTEL_INJECTOR_AUTO_INSTRUMENTATION_DISABLED` to a comma-separated list of runtime names.
Valid runtime names are:
- `dotnet`
- `jvm`
- `nodejs`
- `python`
- `ruby`
The injector will log a warning for unknown runtime names in the comma-separated list.
For example, the following configuration file would leave JVM and Node.js auto-instrumentation active, while disabling
.NET and Python auto-instrumentation:
```
jvm_auto_instrumentation_agent_path=/usr/lib/opentelemetry/jvm/javaagent.jar
nodejs_auto_instrumentation_agent_path=/usr/lib/opentelemetry/nodejs/node_modules/@opentelemetry/auto-instrumentations-node/build/src/register.js
auto_instrumentation_disabled=dotnet,python
```
You can also disable a specific runtime by setting its agent-path environment variable (or configuration-file key)
to the empty string. For example, `RUBY_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX=` disables Ruby auto-instrumentation
for a single process without touching the shared configuration. The same applies to `PYTHON_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX`,
`DOTNET_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX`, `JVM_AUTO_INSTRUMENTATION_AGENT_PATH`, and `NODEJS_AUTO_INSTRUMENTATION_AGENT_PATH`.
Note that the injector might still add additional resource attributes to applications, by adding or extending
`OTEL_RESOURCE_ATTRIBUTES`, even when auto-instrumentation is disabled.
See [Disabling the injector completely for specific workloads](#disabling-the-injector-completely-for-specific-workloads)
for an option that also disables this part.
### Disabling the injector completely for specific workloads
The injector can be installed globally on the host in [`/etc/ld.so.preload`](https://man7.org/linux/man-pages/man8/ld.so.8.html#FILES)
or for all workloads in a Kubernetes cluster/namespace. Therefore, we provide an option for you to disable the
injector for a specific program launch or workload by setting the environment variable `OTEL_INJECTOR_DISABLED=true`.
When `OTEL_INJECTOR_DISABLED` is set to `true`, no environment variables will be modified by the injector.
## Design
This is a short summary of how the injector works internally:
1. Find out which libc the process binds, if any. This is usually either glibc or musl.
(Some OpenTelemetry SDKs need to be injected differently, e.g. using different binaries depending on the libc
flavor.)
2. If the process does not bind a libc, or it cannot be identified, the injector aborts injection and hands back control
to the host process.
3. Find the location of the `dlsym` function in the loaded libc (in memory), reading ELF metadata.
4. Use the libc's `dlsym` handle to look up more symbols in memory, in particular `getenv` and `setenv`.
5. Again, if looking up any of the symbols fails, the injector aborts injection and hands back control to the host
process.
6. Use the `getenv` function to read the current environment of the process (before adding or modifying any environment
variables).
7. Use the `setenv` function to add or modify environment variables to add and activate OpenTelemetry
SDKs/auto-instrumentation agents for supported runtimes (e.g. `NODE_OPTIONS`, `JAVA_TOOL_OPTIONS`,
`CORECLR_PROFILER`).
8. Use the pointer to the `setenv` symbol to add or modify `OTEL_RESOURCE_ATTRIBUTES`.
There is a much more detailed explanation of this approach, and on alternative approaches and the intricate design
constraints in [DESIGN.md](DESIGN.md).
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md).
### Maintainers
- [Antoine Toulme](https://github.com/atoulme), [Splunk](https://www.splunk.com/)
- [Bastian Krol](https://github.com/basti1302), [Dash0](https://www.dash0.com/)
- [Jack Berg](https://github.com/jack-berg), [Grafana Labs](https://grafana.com/)
- [Jacob Aronoff](https://github.com/jaronoff97), [Tero](https://www.usetero.com/)
- [Michele Mancioppi](https://github.com/mmanciop), [Dash0](https://www.dash0.com/)
- [Nikola Grcevski](https://github.com/grcevski), [Grafana Labs](https://grafana.com/)
For more information about the maintainer role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer).
### Project History
The code project was initially donated by [Splunk](https://www.splunk.com/) and later replaced with another code donation
by [Dash0](https://www.dash0.com/).
open-telemetry-opentelemetry-injector-ea9dca1/RELEASING.md 0000664 0000000 0000000 00000003722 15240576456 0023616 0 ustar 00root root 0000000 0000000 # Releasing the injector
An approver or maintainer can run the GitHub action to [prepare the release from the GitHub Actions page of the repository](https://github.com/open-telemetry/opentelemetry-injector/actions/workflows/prepare-release.yml).
The action asks for an `override` input with the choices `auto` (default), `major`, `minor`, or `patch`. When left as `auto`, the release-tooling program at [tooling/nextversion](tooling/nextversion) derives the bump from the `change_type` of the chloggen entries in [.chloggen](.chloggen) (`breaking` -> major, `deprecation`/`new_component`/`enhancement` -> minor, `bug_fix` -> patch; while the current release is on `0.y.z`, a `breaking` change is bumped as minor per the semver 0.x convention). Any of `major`, `minor`, `patch` overrides the auto-derived bump. The action then bumps the appropriate component of the most recent stable `vX.Y.Z` tag, so there is no need to type out the full version.
The action will trigger the creation of a pull request for review by project approvers ([example](https://github.com/open-telemetry/opentelemetry-injector/pull/112)).
Approvers approve the changelog and merge the PR.
(The person approving and merging the changelog PR can be the same person who triggered the `prepare-release` action.)
Merging the PR will trigger the workflow `.github/workflows/create-tag-for-release.yml` which will create a tag with the
version number.
Creating the tag will trigger the `build` GitHub action workflow, which will then create the GitHub release in the last
job (`publish-stable`).
(This can take a couple of minutes.)
Releases from this repository publish only the raw `libotelinject_.so` shared library.
The DEB and RPM system packages are released independently from [open-telemetry/opentelemetry-packaging](https://github.com/open-telemetry/opentelemetry-packaging) on its own cadence.
## Announce the release
Make sure to drop the good news of the release to the CNCF slack #otel-injector channel!
open-telemetry-opentelemetry-injector-ea9dca1/build.zig 0000664 0000000 0000000 00000013251 15240576456 0023573 0 ustar 00root root 0000000 0000000 // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
const std = @import("std");
// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) !void {
const optimize = std.builtin.OptimizeMode.ReleaseSafe;
const target_cpu = b.option(SupportedCpuArch, "cpu-arch", "The system architecture to compile the injector for; valid options are 'amd64' and 'arm64' (default)") orelse .arm64;
const allowed_env_var_prefixes = b.option(
[]const u8,
"allowed-env-var-prefixes",
"Comma-separated env var prefixes allowed in the file pointed by all_auto_instrumentation_agents_env_path (default: OTEL_)",
) orelse "OTEL_";
const target = b.resolveTargetQuery(.{
.cpu_arch = target_cpu.arch(),
// Skip cpu model detection because the automatic detection for transpiling fails in build
.cpu_model = .{ .explicit = target_cpu.model() },
.os_tag = .linux,
});
// Creates a "module", which represents a collection of source files alongside
// some compilation options, such as optimization mode and linked system libraries.
// Every executable or library we compile will be based on one or more modules.
const lib_mod = b.createModule(.{
// `root_source_file` is the Zig "entry point" of the module. If a module
// only contains e.g. external object files, you can make this `null`.
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
.link_libc = false,
.pic = true,
.strip = false,
// Avoid a dependency from `__tls_get_addr` when compiling for x86
.single_threaded = true,
});
const build_options = b.addOptions();
build_options.addOption(
[]const u8,
"allowed_env_var_prefixes",
allowed_env_var_prefixes,
);
lib_mod.addOptions("build_options", build_options);
// Create a dynamically linked library based on the module created above.
// This creates a `std.Build.Step.Compile`, which is the build step responsible
// for actually invoking the compiler.
const lib = b.addLibrary(.{
.linkage = .dynamic,
.name = "injector",
.root_module = lib_mod,
});
lib.setVersionScript(b.path("src/injector.exports.map"));
b.getInstallStep().dependOn(&b.addInstallArtifact(lib, .{ .dest_dir = .{ .override = .{ .custom = "." } } }).step);
var copy_injector_to_bin = b.step("copy_file", "Copy injector file");
copy_injector_to_bin.makeFn = copyInjectorFile;
// make the copy step depend in the install step, which then makes it transitively depend on the compile step
copy_injector_to_bin.dependOn(b.getInstallStep());
// Make copying the injector shared library binary to its final location the default step. This wil also implictly
// trigger building the library as a dependent build step.
b.default_step = copy_injector_to_bin;
// TESTING
const test_filters = b.option([][]const u8, "test-filter", "Match tests to execute");
const testTarget = b.standardTargetOptions(.{});
const test_mod = b.createModule(.{
.root_source_file = b.path("src/test.zig"),
.target = testTarget,
.optimize = optimize,
// For some reason, setting link_libc = false does not seem to be effective on Darwin, and the tests run with
// builtin.link_libc=true anyway. This in turn makes makes std.posix.getenv use std.c.environ under the hood
// instead of std.os.environ.
// Also, on Linux (that is, on CI or with the development Docker container (devel.Dockerfile)) the tests crash
// with
// /opt/hostedtoolcache/zig/0.14.0/x64/lib/std/c.zig:1:1: error: dependency on libc must be explicitly
// specified in the build command
// when accessing std.c.environ and link_libc is set to false here. This needs more investigation. For now, we
// simply always set .link_libc = true for the tests, even if the production code is built with
// .link_libc = false.
.link_libc = true,
.pic = true,
.strip = false,
});
test_mod.addOptions("build_options", build_options);
const unit_tests = b.addTest(.{
.root_module = test_mod,
.filters = test_filters orelse &.{},
});
const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
}
fn copyInjectorFile(step: *std.Build.Step, _: std.Build.Step.MakeOptions) anyerror!void {
const source_path = step.owner.pathFromRoot("./zig-out/libinjector.so");
const dest_path = step.owner.pathFromRoot("so/libotelinject.so");
const dest_dir = step.owner.pathFromRoot("so");
std.fs.cwd().makePath(dest_dir) catch |err| {
if (err != error.PathAlreadyExists) return err;
};
try std.fs.copyFileAbsolute(source_path, dest_path, .{});
}
const SupportedCpuArch = enum {
amd64,
arm64,
const Self = @This();
fn arch(self: Self) std.Target.Cpu.Arch {
return switch (self) {
.amd64 => std.Target.Cpu.Arch.x86_64,
.arm64 => std.Target.Cpu.Arch.aarch64,
};
}
fn model(self: Self) *const std.Target.Cpu.Model {
return switch (self) {
.amd64 => std.Target.Cpu.Model.generic(std.Target.Cpu.Arch.x86_64),
.arm64 => std.Target.Cpu.Model.generic(std.Target.Cpu.Arch.aarch64),
};
}
};
open-telemetry-opentelemetry-injector-ea9dca1/build.zig.zon 0000664 0000000 0000000 00000010400 15240576456 0024371 0 ustar 00root root 0000000 0000000 // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
.{
// This is the default name used by packages depending on this one. For
// example, when a user runs `zig fetch --save `, this field is used
// as the key in the `dependencies` table. Although the user can choose a
// different name, most users will stick with this provided value.
//
// It is redundant to include "zig" in this name because it is already
// within the Zig package namespace.
.name = .injector,
// This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication.
.version = "0.0.0",
// Together with name, this represents a globally unique package
// identifier. This field is generated by the Zig toolchain when the
// package is first created, and then *never changes*. This allows
// unambiguous detection of one package being an updated version of
// another.
//
// When forking a Zig project, this id should be regenerated (delete the
// field and run `zig build`) if the upstream project is still maintained.
// Otherwise, the fork is *hostile*, attempting to take control over the
// original project's identity. Thus it is recommended to leave the comment
// on the following line intact, so that it shows up in code reviews that
// modify the field.
.fingerprint = 0xafb77859b87ae2a1, // Changing this has security and trust implications.
// Tracks the earliest Zig version that the package considers to be a
// supported use case.
// Keep this in sync with ./zig-version.
.minimum_zig_version = "0.15.2",
// This field is optional.
// Each dependency must either provide a `url` and `hash`, or a `path`.
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
// Once all dependencies are fetched, `zig build` no longer requires
// internet connectivity.
.dependencies = .{
// See `zig fetch --save ` for a command-line interface for adding dependencies.
//.example = .{
// // When updating this field to a new URL, be sure to delete the corresponding
// // `hash`, otherwise you are communicating that you expect to find the old hash at
// // the new URL. If the contents of a URL change this will result in a hash mismatch
// // which will prevent zig from using it.
// .url = "https://example.com/foo.tar.gz",
//
// // This is computed from the file contents of the directory of files that is
// // obtained after fetching `url` and applying the inclusion rules given by
// // `paths`.
// //
// // This field is the source of truth; packages do not come from a `url`; they
// // come from a `hash`. `url` is just one of many possible mirrors for how to
// // obtain a package matching this `hash`.
// //
// // Uses the [multihash](https://multiformats.io/multihash/) format.
// .hash = "...",
//
// // When this is provided, the package is found in a directory relative to the
// // build root. In this case the package's hash is irrelevant and therefore not
// // computed. This field and `url` are mutually exclusive.
// .path = "foo",
//
// // When this is set to `true`, a package is declared to be lazily
// // fetched. This makes the dependency only get fetched if it is
// // actually used.
// .lazy = false,
//},
},
// Specifies the set of files and directories that are included in this package.
// Only files and directories listed here are included in the `hash` that
// is computed for this package. Only files listed here will remain on disk
// when using the zig package manager. As a rule of thumb, one should list
// files required for compilation plus any license(s).
// Paths are relative to the build root. Use the empty string (`""`) to refer to
// the build root itself.
// A directory listed here means that all files within, recursively, are included.
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}
open-telemetry-opentelemetry-injector-ea9dca1/devel.Dockerfile 0000664 0000000 0000000 00000002745 15240576456 0025057 0 ustar 00root root 0000000 0000000 # This Dockerfile is intended to serve as a development environment for the injector, i.e. mounting the injector
# directory as a volume to the container and then running the image with `-it` to have a fast feeback cycle when working
# on injector changes.
# It also enables running unit tests on different architectures (x86_64 vs aarm64).
# Use `make docker-run` build and run the container.
ARG base_image=debian:13@sha256:34cd9e9fd437c0a095ec39cb2e73422c9f30821b0d0848ed74fd0d43bae4d958
FROM ${base_image}
ARG zig_architecture
RUN apt-get update && \
apt-get install -y --no-install-recommends \
autoconf \
binutils \
build-essential \
ca-certificates \
default-jre \
entr \
fd-find \
gdb \
less \
locales \
nodejs \
tmux \
rsyslog \
vim \
wget \
&& \
apt-get clean && \
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
ENV LANG=en_US.utf8
RUN ln -s $(which fdfind) /usr/local/bin/fd
RUN echo 'alias ll="ls -lah"' >> ~/.bashrc
# install Zig tooling.
RUN mkdir -p /opt/zig
WORKDIR /opt/zig
COPY zig-version .
RUN . /opt/zig/zig-version && \
wget -q -O /tmp/zig.tar.gz https://ziglang.org/download/${ZIG_VERSION%-*}/zig-${zig_architecture}-linux-${ZIG_VERSION}.tar.xz && \
tar --strip-components=1 -xf /tmp/zig.tar.gz
ENV PATH="$PATH:/opt/zig"
# to see syslogs, run the following in the container
# apt install rsyslog
# service rsyslog start
WORKDIR /injector
open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/ 0000775 0000000 0000000 00000000000 15240576456 0027255 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/README.md 0000664 0000000 0000000 00000005127 15240576456 0030541 0 ustar 00root root 0000000 0000000 Injector Integration Tests
==========================
This directory contains integration tests for the injector binary.
The tests in this folder do not use a multi-platform image; instead, an injector binary is build (in a container)
per CPU architecture, and then used for testing.
Note that the Zig source code in `src` also contains Zig unit tests. The integration tests for the DEB and RPM system
packages live in [open-telemetry/opentelemetry-packaging](https://github.com/open-telemetry/opentelemetry-packaging).
The available test cases for the injector integration tests are listed in the files
`injector-integration-tests/tests/*.tests`.
Usage
-----
* `scripts/test-all.sh` to run all tests.
* `ARCHITECTURES=arm64,amd64 scripts/test-all.sh` to run tests for a subset of CPU architectures.
Can be combined with `LIBC_FLAVORS` and other flags.
* `LIBC_FLAVORS=glibc,musl scripts/test-all.sh` to run tests for a subset of libc flavors.
Can be combined with `ARCHITECTURES` and other flags.
* `TEST_SETS=default,nodejs,jvm,sdk-does-not-exist,sdk-cannot-be-accessed` to only run a subset of test sets. The test
set names are the different `injector-integration-tests/tests/*.tests` files. Can be combined with `ARCHITECTURES`,
`LIBC_FLAVORS` etc.
* `TEST_CASES="injects NODE_OPTIONS if it is not present" scripts/test-all.sh` to only run test cases whose names
_exactly match_ one of the provided strings.
The test cases are listed in the different test sets, i.e. the `injector-integration-tests/tests/*.tests` files.
Can be combined with `ARCHITECTURES`, `LIBC_FLAVORS` etc., cannot be combined with `TEST_CASES_CONTAINING`.
* `TEST_CASES_CONTAINING=OTEL_RESOURCE_ATTRIBUTES,OTEL_RESOURCE_ATTRIBUTES scripts/test-all.sh` to only run tests cases
whose names _contain_ one of the provided strings as a substring.
The test cases are listed in the different `scripts/*.tests` files.
Can be combined with `ARCHITECTURES`, `LIBC_FLAVORS` etc., cannot be combined with `TEST_CASES`.
* Set `VERBOSE=true` to set `OTEL_INJECTOR_LOG_LEVEL=debug` when running test cases and to always include the output
from running the test case. Otherwise, the default log level (`error`) is used, and output is only printed to stdout
when a test case fails.
* Set `INTERACTIVE=true` to get a shell into the container under test, instead of running a test. Best used when working
on a test for one specific app/test set, you would usually want to combine this with something like
`ARCHITECTURES=arm64 LIBC_FLAVORS=glibc TEST_SETS=dotnet INTERACTIVE=true scripts/test-all.sh` to narrow down the
scope to one container under test.
open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/ 0000775 0000000 0000000 00000000000 15240576456 0030220 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/binary-validation/ 0000775 0000000 0000000 00000000000 15240576456 0033634 5 ustar 00root root 0000000 0000000 Dockerfile 0000664 0000000 0000000 00000002066 15240576456 0035553 0 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/binary-validation # Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
# Dockerfile for binary validation tests.
# Uses a minimal Debian image with binutils installed for readelf.
ARG base_image_run="debian:bookworm-slim"
FROM ${base_image_run}
ARG injector_binary
RUN if [ -z "$injector_binary" ]; then \
echo "Error: build argument injector_binary is required but not set."; \
exit 1; \
fi
# Install binutils (provides readelf) for binary validation tests.
# Detect package manager and install accordingly (apt for Debian, apk for Alpine).
RUN apt-get update && apt-get install -y --no-install-recommends binutils
RUN mkdir -p /etc/opentelemetry/injector/conf.d && chmod -R 777 /etc/opentelemetry
WORKDIR /usr/src/otel/injector/
COPY injector-integration-tests/apps/binary-validation app
COPY injector-integration-tests/scripts/*.sh scripts/
COPY injector-integration-tests/tests/*.tests tests/
COPY injector-integration-tests/common/ common/
COPY dist/${injector_binary} /injector/libotelinject.so
CMD ["scripts/run-tests-within-container.sh"]
main.sh 0000775 0000000 0000000 00000004740 15240576456 0035045 0 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/binary-validation #!/usr/bin/env sh
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
set -eu
command=${1:-}
if [ -z "$command" ]; then
echo "Error: command parameter is required"
exit 1
fi
injector_binary=/injector/libotelinject.so
check_no_weak_dynamic_symbols() {
# Use readelf to get dynamic symbols and check for WEAK binding
weak_symbols=$(readelf --dyn-syms "$injector_binary" 2>/dev/null | grep -E "WEAK" || true)
if [ -n "$weak_symbols" ]; then
echo "The injector binary contains weak dynamic symbols, which is not allowed."
echo "Weak symbols found:"
echo "$weak_symbols"
exit 1
else
echo "test no weak dynamic symbols successful"
exit 0
fi
}
check_no_global_undefined_symbols() {
# Use readelf to get dynamic symbols and check for GLOBAL binding with UNDEFINED (UND) section
global_undefined_symbols=$(readelf --dyn-syms "$injector_binary" 2>/dev/null | grep -E "GLOBAL[[:space:]]+UND" || true)
if [ -n "$global_undefined_symbols" ]; then
echo "The injector binary contains global undefined dynamic symbols, which is not allowed."
echo "Global undefined symbols found:"
echo "$global_undefined_symbols"
exit 1
else
echo "test no global undefined dynamic symbols successful"
exit 0
fi
}
check_dynsym_golden_signature() {
# Expected output: only the mandatory null symbol entry
# Note: readelf outputs a leading newline before the symbol table header
expected_output="
Symbol table '.dynsym' contains 1 entry:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND "
actual_output=$(readelf --dyn-syms "$injector_binary" 2>/dev/null)
if [ "$actual_output" = "$expected_output" ]; then
echo "test dynsym golden signature successful"
exit 0
else
echo "The injector binary dynamic symbol table does not match the expected signature."
echo "Expected (only the compulsory null symbol):"
echo "$expected_output"
echo ""
echo "Actual:"
echo "$actual_output"
exit 1
fi
}
case "$command" in
check_no_weak_dynamic_symbols)
check_no_weak_dynamic_symbols
;;
check_no_global_undefined_symbols)
check_no_global_undefined_symbols
;;
check_dynsym_golden_signature)
check_dynsym_golden_signature
;;
*)
echo "Error: unknown command '$command'"
echo "Valid commands: check_no_weak_dynamic_symbols, check_no_global_undefined_symbols, check_dynsym_golden_signature"
exit 1
;;
esac
open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/copy-reloc/ 0000775 0000000 0000000 00000000000 15240576456 0032274 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/copy-reloc/Dockerfile 0000664 0000000 0000000 00000003053 15240576456 0034267 0 ustar 00root root 0000000 0000000 # Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
# node:16-bullseye-slim ships glibc 2.31 and a node binary that contains a COPY
# relocation on environ (verified via `readelf -r /usr/local/bin/node`). This
# exercises the glibc < 2.34 fallback path where the injector resolves getenv
# directly from the ELF symbol table rather than via dlsym.
ARG base_image_run="node:16-bullseye-slim@sha256:503446c15c6236291222f8192513c2eb56a02a8949cbadf4fe78cce19815c734"
FROM ${base_image_run}
ARG injector_binary
RUN if [ -z "$injector_binary" ]; then \
echo "Error: build argument injector_binary is required but not set."; \
exit 1; \
fi
ARG create_sdk_dummy_files_script
RUN if [ -z "$create_sdk_dummy_files_script" ]; then \
echo "Error: build argument create_sdk_dummy_files_script is required but not set."; \
exit 1; \
fi
RUN mkdir -p /etc/opentelemetry/injector/conf.d && chmod -R 777 /etc/opentelemetry
WORKDIR /usr/src/otel/injector/
COPY injector-integration-tests/apps/copy-reloc/no-op-agent no-op-agent
COPY injector-integration-tests/apps/copy-reloc app
COPY injector-integration-tests/scripts/*.sh scripts/
COPY injector-integration-tests/tests/*.tests tests/
COPY injector-integration-tests/common/ common/
COPY injector-integration-tests/common/injector.custom-location.conf /custom/config/path/injector.conf
RUN scripts/create-config-file-directory.sh
RUN ${create_sdk_dummy_files_script}
COPY dist/${injector_binary} /injector/libotelinject.so
USER node
CMD ["scripts/run-tests-within-container.sh"]
open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/copy-reloc/index.js 0000664 0000000 0000000 00000001065 15240576456 0033743 0 ustar 00root root 0000000 0000000 // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
const process = require('node:process');
function echoEnvVar(envVarName) {
const envVarValue = process.env[envVarName];
if (!envVarValue) {
process.stdout.write(`${envVarName}: -`);
} else {
process.stdout.write(`${envVarName}: ${envVarValue}`);
}
}
function main() {
const envVarName = process.argv[2];
if (!envVarName) {
console.error('error: an environment variable name argument is required');
process.exit(1);
}
echoEnvVar(envVarName);
}
main();
no-op-agent/ 0000775 0000000 0000000 00000000000 15240576456 0034341 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/copy-reloc index.js 0000664 0000000 0000000 00000000217 15240576456 0036006 0 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/copy-reloc/no-op-agent // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
global.otel_injector_nodejs_no_op_agent_has_been_loaded = true;
open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/dotnet/ 0000775 0000000 0000000 00000000000 15240576456 0031515 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/dotnet/.gitignore 0000664 0000000 0000000 00000000011 15240576456 0033475 0 ustar 00root root 0000000 0000000 obj/
bin/ open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/dotnet/Dockerfile 0000664 0000000 0000000 00000003311 15240576456 0033505 0 ustar 00root root 0000000 0000000 # Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
ARG base_image_build=mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim
ARG base_image_run=mcr.microsoft.com/dotnet/runtime:9.0-bookworm-slim
FROM ${base_image_build} AS build
ARG TARGETARCH
WORKDIR /no-op-startup-hook-source
COPY injector-integration-tests/apps/dotnet/no-op-startup-hook .
RUN dotnet restore
RUN dotnet publish --no-restore -o /no-op-startup-hook
WORKDIR /source
# copy csproj and restore as distinct layers
COPY injector-integration-tests/apps/dotnet/app/*.csproj .
RUN dotnet restore
# copy and publish app and libraries
COPY injector-integration-tests/apps/dotnet/app/* .
RUN dotnet publish --no-restore -o /app
# final stage/image
FROM ${base_image_run}
RUN mkdir -p /etc/opentelemetry/injector/conf.d && chmod -R 777 /etc/opentelemetry
WORKDIR /usr/src/otel/injector/
COPY --from=build /no-op-startup-hook no-op-startup-hook
COPY --from=build /app app
ARG injector_binary
RUN if [ -z "$injector_binary" ]; then \
echo "Error: build argument injector_binary is required but not set."; \
exit 1; \
fi
ARG create_sdk_dummy_files_script
RUN if [ -z "$create_sdk_dummy_files_script" ]; then \
echo "Error: build argument create_sdk_dummy_files_script is required but not set."; \
exit 1; \
fi
COPY injector-integration-tests/scripts/*.sh scripts/
COPY injector-integration-tests/tests/*.tests tests/
COPY injector-integration-tests/common/ common/
COPY injector-integration-tests/common/injector.custom-location.conf /custom/config/path/injector.conf
RUN scripts/create-config-file-directory.sh
RUN ${create_sdk_dummy_files_script}
COPY dist/${injector_binary} /injector/libotelinject.so
CMD ["scripts/run-tests-within-container.sh"]
open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/dotnet/app/ 0000775 0000000 0000000 00000000000 15240576456 0032275 5 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/dotnet/app/App.cs 0000664 0000000 0000000 00000003074 15240576456 0033350 0 ustar 00root root 0000000 0000000 // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
namespace OpenTelemetry;
using System;
class App
{
static int Main(string[] args)
{
if (args.Length == 0) {
Console.WriteLine("error: not enough arguments, the command for the app under test needs to be specifed");
return 1;
}
string command = args[0];
if (command == null || command == "") {
Console.WriteLine("error: not enough arguments, the command for the app under test needs to be specifed");
return 1;
}
switch (command) {
case "coreclr-profiler-path":
EchoEnvVar("CORECLR_PROFILER_PATH");
break;
case "verify-startup-hook-has-been-injected":
EchoEnvVar("otel_injector_dotnet_no_op_startup_hook_has_been_loaded");
break;
case "otel-resource-attributes":
EchoEnvVar("OTEL_RESOURCE_ATTRIBUTES");
break;
case "custom-env-var":
EchoEnvVar(args[1]);
break;
default:
Console.WriteLine("error: unknown test app command: " + command);
return 1;
}
return 0;
}
private static void EchoEnvVar(String envVarName)
{
string value = Environment.GetEnvironmentVariable(envVarName);
if (value != null) {
Console.WriteLine("{0}: {1}", envVarName, value);
} else {
Console.WriteLine("{0}: -", envVarName);
}
}
}
dotnetapp.csproj 0000664 0000000 0000000 00000000354 15240576456 0035440 0 ustar 00root root 0000000 0000000 open-telemetry-opentelemetry-injector-ea9dca1/injector-integration-tests/apps/dotnet/app
Exe
net9.0
enable
enable