main db954acd415a cached
114 files
344.3 KB
96.1k tokens
358 symbols
1 requests
Download .txt
Showing preview only (377K chars total). Download the full file or copy to clipboard to get everything.
Repository: davidB/tracing-opentelemetry-instrumentation-sdk
Branch: main
Commit: db954acd415a
Files: 114
Total size: 344.3 KB

Directory structure:
gitextract_m0cxzsml/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── ci.yml
│       ├── mega-linter.yml
│       └── release-plz.yml
├── .gitignore
├── .mega-linter.yml
├── .mise.toml
├── .vscode/
│   └── settings.json
├── .yamllint.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Cargo.toml
├── LICENSE
├── README.md
├── axum-tracing-opentelemetry/
│   ├── CHANGELOG.md
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── lib.rs
│       └── middleware/
│           ├── mod.rs
│           ├── response_injector.rs
│           └── trace_extractor.rs
├── cliff.toml
├── deny.toml
├── examples/
│   ├── axum-otlp/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── main.rs
│   ├── bug_234_tls/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── main.rs
│   ├── grpc/
│   │   ├── Cargo.toml
│   │   ├── build.rs
│   │   ├── proto/
│   │   │   └── helloworld.proto
│   │   └── src/
│   │       ├── client.rs
│   │       ├── generated/
│   │       │   └── helloworld.rs
│   │       └── server.rs
│   ├── init-tracing-with/
│   │   ├── .cargo/
│   │   │   └── config.toml
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── main.rs
│   ├── load/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── main.rs
│   └── logging/
│       ├── Cargo.toml
│       └── src/
│           └── main.rs
├── fake-opentelemetry-collector/
│   ├── CHANGELOG.md
│   ├── Cargo.toml
│   ├── README.md
│   ├── src/
│   │   ├── common.rs
│   │   ├── lib.rs
│   │   ├── logs.rs
│   │   ├── metrics.rs
│   │   └── trace.rs
│   └── tests/
│       ├── demo_log.rs
│       ├── demo_metrics.rs
│       ├── demo_trace.rs
│       └── snapshots/
│           ├── demo_log__demo_fake_logger_and_collector.snap
│           ├── demo_metrics__demo_fake_meter_and_collector.snap
│           └── demo_trace__demo_fake_tracer_and_collector.snap
├── init-tracing-opentelemetry/
│   ├── CHANGELOG.md
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── config.rs
│       ├── error.rs
│       ├── formats.rs
│       ├── lib.rs
│       ├── otlp/
│       │   ├── logs.rs
│       │   ├── metrics.rs
│       │   ├── mod.rs
│       │   └── traces.rs
│       ├── resource.rs
│       ├── stdio.rs
│       └── tracing_subscriber_ext.rs
├── release-plz.toml
├── renovate.json5
├── rust-toolchain.toml
├── testing-tracing-opentelemetry/
│   ├── Cargo.toml
│   └── src/
│       ├── lib.rs
│       └── snapshots/
│           ├── testing_tracing_opentelemetry__call_with_w3c_trace.snap
│           ├── testing_tracing_opentelemetry__call_with_w3c_trace_otel_spans.snap
│           ├── testing_tracing_opentelemetry__empty_http_route_for_nonexisting_route.snap
│           ├── testing_tracing_opentelemetry__empty_http_route_for_nonexisting_route_otel_spans.snap
│           ├── testing_tracing_opentelemetry__extract_route_from_nested.snap
│           ├── testing_tracing_opentelemetry__extract_route_from_nested_otel_spans.snap
│           ├── testing_tracing_opentelemetry__filled_http_headers.snap
│           ├── testing_tracing_opentelemetry__filled_http_headers_otel_spans.snap
│           ├── testing_tracing_opentelemetry__filled_http_route_for_existing_route.snap
│           ├── testing_tracing_opentelemetry__filled_http_route_for_existing_route_otel_spans.snap
│           ├── testing_tracing_opentelemetry__status_code_on_close_for_error.snap
│           ├── testing_tracing_opentelemetry__status_code_on_close_for_error_otel_spans.snap
│           ├── testing_tracing_opentelemetry__status_code_on_close_for_ok.snap
│           ├── testing_tracing_opentelemetry__status_code_on_close_for_ok_otel_spans.snap
│           ├── testing_tracing_opentelemetry__trace_id_in_child_span.snap
│           ├── testing_tracing_opentelemetry__trace_id_in_child_span_for_remote.snap
│           ├── testing_tracing_opentelemetry__trace_id_in_child_span_for_remote_otel_spans.snap
│           └── testing_tracing_opentelemetry__trace_id_in_child_span_otel_spans.snap
├── tonic-tracing-opentelemetry/
│   ├── CHANGELOG.md
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── lib.rs
│       └── middleware/
│           ├── client.rs
│           ├── filters.rs
│           ├── mod.rs
│           └── server.rs
└── tracing-opentelemetry-instrumentation-sdk/
    ├── CHANGELOG.md
    ├── Cargo.toml
    ├── README.md
    └── src/
        ├── http/
        │   ├── grpc.rs
        │   ├── grpc_client.rs
        │   ├── grpc_server.rs
        │   ├── http_server.rs
        │   ├── mod.rs
        │   ├── opentelemetry_http.rs
        │   └── tools.rs
        ├── lib.rs
        └── span_type.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# https://editorconfig.org/

root = true

[*]
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
charset = utf-8

[*.conf]
indent_size = 2

[*.md]
#inside code block, indentation could be anything
indent_size = unset

[*.py]
indent_size = 4
# 88 is the default for black formatter
# 79 is PEP8's recommendation
# 119 is django's recommendation
max_line_length = 88

[*.rs]
# https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/guide.md
indent_size = 4
# officially the limit is 100, but we have long url (unsplittable) in comment
max_line_length = 200

[{*.bazel,*.bzl,BUILD,WORKSPACE}]
indent_size = 4

[*.java]
# try to align with https://github.com/diffplug/spotless (https://github.com/google/google-java-format)
indent_size = 4
max_line_length = 100

# The JSON files contain newlines inconsistently
[*.json]
insert_final_newline = unset

[**/vendor/**]
indent_style = unset
indent_size = unset
insert_final_newline = unset

# Minified JavaScript files shouldn't be changed
[**.min.js]
indent_style = unset
indent_size = unset
insert_final_newline = unset

# Makefiles always use tabs for indentation
[Makefile]
indent_style = tab
indent_size = 4

[justfile]
indent_style = space
indent_size = 4

# Batch files use tabs for indentation
[*.bat]
indent_style = tab
indent_size = 4


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: [davidB]
# patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
# otechie: # Replace with a single Otechie username
# lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .github/workflows/ci.yml
================================================
---
name: ci

on:
  pull_request:
    branches-ignore:
      - "release-plz-*"
  push:
    branches:
      - main
      - master
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  tests:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-latest
          # - macos-latest
    env:
      CARGO_TERM_COLOR: always
      RUST_BACKTRACE: full
      SCCACHE_GHA_ENABLED: "true"
      RUSTC_WRAPPER: "sccache"
    steps:
      - uses: actions/checkout@v6
      - uses: mozilla-actions/sccache-action@v0.0.9
      - uses: jdx/mise-action@v4
        with:
          # version 2025.5.11, a symlink is created for rust setup
          # without cache, missing components are installed
          # with cache, nothing is installed, but as rust tool is symlinked, it is not cached => missing components failure
          cache: false
          cache_save: false
          experimental: true
      - run: mise run --jobs 1 ci
      #- run: mise run test-each-feature


================================================
FILE: .github/workflows/mega-linter.yml
================================================
# MegaLinter GitHub Action configuration file
# More info at https://megalinter.io
---
name: MegaLinter

# Trigger mega-linter at every push. Action will also be visible from Pull
# Requests to main
on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

# Comment env block if you do not want to apply fixes
env:
  # Apply linter fixes configuration
  #
  # When active, APPLY_FIXES must also be defined as environment variable
  # (in github/workflows/mega-linter.yml or other CI tool)
  APPLY_FIXES: all

  # Decide which event triggers application of fixes in a commit or a PR
  # (pull_request, push, all)
  APPLY_FIXES_EVENT: pull_request

  # If APPLY_FIXES is used, defines if the fixes are directly committed (commit)
  # or posted in a PR (pull_request)
  APPLY_FIXES_MODE: commit

concurrency:
  group: ${{ github.ref }}-${{ github.workflow }}
  cancel-in-progress: true

# Give the default GITHUB_TOKEN write permission to commit and push, comment
# issues & post new PR; remove the ones you do not need
permissions:
  contents: write
  issues: write
  pull-requests: write

jobs:
  megalinter:
    name: MegaLinter
    runs-on: ubuntu-latest

    steps:
      # Git Checkout
      - name: Checkout Code
        uses: actions/checkout@v6
        with:
          token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}

          # If you use VALIDATE_ALL_CODEBASE = true, you can remove this line to
          # improve performance
          fetch-depth: 0

      # MegaLinter
      - name: MegaLinter

        # You can override MegaLinter flavor used to have faster performances
        # More info at https://megalinter.io/flavors/
        uses: oxsecurity/megalinter/flavors/documentation@v9

        id: ml

        # All available variables are described in documentation
        # https://megalinter.io/configuration/
        env:
          # Validates all source when push on main, else just the git diff with
          # main. Override with true if you always want to lint all sources
          #
          # To validate the entire codebase, set to:
          # VALIDATE_ALL_CODEBASE: true
          #
          # To validate only diff with main, set to:
          # VALIDATE_ALL_CODEBASE: >-
          #   ${{
          #     github.event_name == 'push' &&
          #     contains(fromJSON('["refs/heads/main", "refs/heads/master"]'), github.ref)
          #   }}
          VALIDATE_ALL_CODEBASE: >-
            ${{
              github.event_name == 'push' &&
              contains(fromJSON('["refs/heads/main", "refs/heads/master"]'), github.ref)
            }}

          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

          # ADD YOUR CUSTOM ENV VARIABLES HERE OR DEFINE THEM IN A FILE
          # .mega-linter.yml AT THE ROOT OF YOUR REPOSITORY

          # Uncomment to disable copy-paste and spell checks
          # DISABLE: COPYPASTE,SPELL

      # Upload MegaLinter artifacts
      - name: Archive production artifacts
        uses: actions/upload-artifact@v7
        if: success() || failure()
        with:
          name: MegaLinter reports
          path: |
            megalinter-reports
            mega-linter.log

      # Set APPLY_FIXES_IF var for use in future steps
      - name: Set APPLY_FIXES_IF var
        run: |
          printf 'APPLY_FIXES_IF=%s\n' "${{
            steps.ml.outputs.has_updated_sources == 1 &&
            (
              env.APPLY_FIXES_EVENT == 'all' ||
              env.APPLY_FIXES_EVENT == github.event_name
            ) &&
            (
              github.event_name == 'push' ||
              github.event.pull_request.head.repo.full_name == github.repository
            )
          }}" >> "${GITHUB_ENV}"

      # Set APPLY_FIXES_IF_* vars for use in future steps
      - name: Set APPLY_FIXES_IF_* vars
        run: |
          printf 'APPLY_FIXES_IF_PR=%s\n' "${{
            env.APPLY_FIXES_IF == 'true' &&
            env.APPLY_FIXES_MODE == 'pull_request'
          }}" >> "${GITHUB_ENV}"
          printf 'APPLY_FIXES_IF_COMMIT=%s\n' "${{
            env.APPLY_FIXES_IF == 'true' &&
            env.APPLY_FIXES_MODE == 'commit' &&
            (!contains(fromJSON('["refs/heads/main", "refs/heads/master"]'), github.ref))
          }}" >> "${GITHUB_ENV}"

      # Create pull request if applicable
      # (for now works only on PR from same repository, not from forks)
      - name: Create Pull Request with applied fixes
        uses: peter-evans/create-pull-request@v8
        id: cpr
        if: env.APPLY_FIXES_IF_PR == 'true'
        with:
          token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}
          commit-message: "[MegaLinter] Apply linters automatic fixes"
          title: "[MegaLinter] Apply linters automatic fixes"
          labels: bot

      - name: Create PR output
        if: env.APPLY_FIXES_IF_PR == 'true'
        run: |
          echo "PR Number - ${{ steps.cpr.outputs.pull-request-number }}"
          echo "PR URL - ${{ steps.cpr.outputs.pull-request-url }}"

      # Push new commit if applicable
      # (for now works only on PR from same repository, not from forks)
      - name: Prepare commit
        if: env.APPLY_FIXES_IF_COMMIT == 'true'
        run: sudo chown -Rc $UID .git/

      - name: Commit and push applied linter fixes
        uses: stefanzweifel/git-auto-commit-action@v7
        if: env.APPLY_FIXES_IF_COMMIT == 'true'
        with:
          branch: >-
            ${{
              github.event.pull_request.head.ref ||
              github.head_ref ||
              github.ref
            }}
          commit_message: "[MegaLinter] Apply linters fixes"
          commit_user_name: megalinter-bot
          commit_user_email: nicolas.vuillamy@ox.security


================================================
FILE: .github/workflows/release-plz.yml
================================================
name: release-plz

permissions:
  pull-requests: write
  contents: write

on:
  workflow_dispatch:
  push:
    branches:
      - main

concurrency:
  group: ${{ github.ref }}-${{ github.workflow }}
  cancel-in-progress: true

jobs:
  release-plz:
    name: Release-plz
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
      - name: Run release-plz
        uses: MarcoIeni/release-plz-action@v0.5
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}


================================================
FILE: .gitignore
================================================
# Created by https://www.toptal.com/developers/gitignore/api/git,bazel,vim,emacs,visualstudiocode,jetbrains+all,helm,rust
# Edit at https://www.toptal.com/developers/gitignore?templates=git,bazel,vim,emacs,visualstudiocode,jetbrains+all,helm,rust

### Bazel ###
# gitignore template for Bazel build system
# website: https://bazel.build/

# Ignore all bazel-* symlinks. There is no full list since this can change
# based on the name of the directory bazel is cloned into.
/bazel-*

# Directories for the Bazel IntelliJ plugin containing the generated
# IntelliJ project files and plugin configuration. Seperate directories are
# for the IntelliJ, Android Studio and CLion versions of the plugin.
/.ijwb/
/.aswb/
/.clwb/

### Emacs ###
# -*- mode: gitignore; -*-
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*

# Org-mode
.org-id-locations
*_archive

# flymake-mode
*_flymake.*

# eshell files
/eshell/history
/eshell/lastdir

# elpa packages
/elpa/

# reftex files
*.rel

# AUCTeX auto folder
/auto/

# cask packages
.cask/
dist/

# Flycheck
flycheck_*.el

# server auth directory
/server/

# projectiles files
.projectile

# directory configuration
.dir-locals.el

# network security
/network-security.data

### Git ###
# Created by git for backups. To disable backups in Git:
# $ git config --global mergetool.keepBackup false
*.orig

# Created by git when using merge tools for conflicts
*.BACKUP.*
*.BASE.*
*.LOCAL.*
*.REMOTE.*
*_BACKUP_*.txt
*_BASE_*.txt
*_LOCAL_*.txt
*_REMOTE_*.txt

### Helm ###
# Chart dependencies
**/charts/*.tgz

### JetBrains+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# AWS User-specific
.idea/**/aws.xml

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn.  Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# SonarLint plugin
.idea/sonarlint/

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

### JetBrains+all Patch ###
# Ignore everything but code style settings and run configurations
# that are supposed to be shared within teams.

.idea/*

!.idea/codeStyles
!.idea/runConfigurations

### Rust ###
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

### Vim ###
# Swap
[._]*.s[a-v][a-z]
!*.svg # comment out if you don't need vector files
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]

# Session
Session.vim
Sessionx.vim

# Temporary
.netrwhist
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~

### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets

# Local History for Visual Studio Code
.history/

# Built Visual Studio Code Extensions
*.vsix

### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide

# Support for Project snippet scope

# End of https://www.toptal.com/developers/gitignore/api/git,bazel,vim,emacs,visualstudiocode,jetbrains+all,helm,rust

.envrc

# ignore downloaded charts
*.tgz
*.off

# ignore report from MegaLinter
report/
megalinter-reports/

tempo-data


================================================
FILE: .mega-linter.yml
================================================
# Configuration file for MegaLinter
# See all available variables at https://megalinter.github.io/configuration/ and in linters documentation

APPLY_FIXES: all # all, none, or list of linter keys
# ENABLE: # If you use ENABLE variable, all other languages/formats/tooling-formats will be disabled by default
# ENABLE_LINTERS: # If you use ENABLE_LINTERS variable, all other linters will be disabled by default
DISABLE:
  - COPYPASTE # Comment to enable checks of excessive copy-pastes
  - SPELL # Comment to enable checks of spelling mistakes
DISABLE_LINTERS:
  - MARKDOWN_MARKDOWN_LINK_CHECK
  - DOCKERFILE_DOCKERFILELINT
  - RUST_CLIPPY
  - REPOSITORY_DEVSKIM
  - REPOSITORY_KICS
  - REPOSITORY_TRIVY
SHOW_ELAPSED_TIME: true
FILEIO_REPORTER: false
# DISABLE_ERRORS: true # Uncomment if you want MegaLinter to detect errors but not block CI to pass
FILTER_REGEX_EXCLUDE: "(\\.lock)|(\\.ndjson)|(\\.pdf)|(\\.csv)|(\\.zip)|(\\.tar)|(\\.ipynb)|(license.*)|(LICENSE.*)|(.*CHANGELOG.*)"
SPELL_FILTER_REGEX_INCLUDE: '\\.md$'
RUST_CLIPPY_ARGUMENTS: --workspace --all-features --all-targets -- --deny warnings --allow deprecated --allow unknown-lints


================================================
FILE: .mise.toml
================================================
[env]
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = "http://127.0.0.1:4317"
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = "grpc"
OTEL_TRACES_SAMPLER = "always_on"
# RUST_LOG = "warn,otel::setup=debug"

# [settings]
# auto_install_disable_tools = [
#   "cargo:cargo-deny",
#   "cargo:cargo-hack",
#   "cargo:cargo-insta",
#   "cargo:cargo-nextest",
#   "cargo:cargo-release",
#   "git-cliff",
# ]

[tools]
rust = { version = "1.91.0", profile = "minimal", components = "rustfmt,clippy" }  # the rust tool stack (with cargo, fmt, clippy) to build source
grpcurl = "1.9"
protoc = "34.1"
# grpc-health-probe = "*"
# sccache = "0.5"
# cargo-binstall allow to download (insteal of build) "cargo:*"
# - do not use cargo-binstall" (it's a special name used by mise)
# - "aqua:cargo-bins/cargo-binstall" allow to download the binary
"aqua:cargo-bins/cargo-binstall" = "1"
"cargo:cargo-deny" = "latest"
"cargo:cargo-nextest" = "latest"
"cargo:cargo-insta" = "latest"
"cargo:cargo-release" = "latest"
"cargo:cargo-hack" = "latest"
"git-cliff" = "latest"

[tasks.autofix]
description = "Automatically fix some linting issues & format code"
depends_post = ["format"]
run = "cargo clippy --all-features --fix --allow-dirty"

[tasks.format]
alias = "fmt"
description = "Format the code and sort dependencies"
run = [
  "cargo fmt",
  # "cargo sort --workspace --grouped"
]

[tasks.deny]
description = "Run cargo deny checks"
run = "cargo deny check"

[tasks.check]
description = "Check code with all feature combinations"
run = "cargo hack check --each-feature --no-dev-deps"
wait_for = ["test", "lint"]

[tasks.lint]
description = "Lint the rust code"
run = [
  "cargo fmt --all -- --check",
  "cargo clippy --workspace --all-features --all-targets -- --deny warnings --allow deprecated --allow unknown-lints",
]
wait_for = ["deny"]

[tasks.megalinter]
description = "Run megalinter in container"
run = 'docker run --pull always --rm -it -v "$PWD:/tmp/lint:rw" "oxsecurity/megalinter-documentation:v8"'

[tasks.test]
description = "Launch tests"
run = [
  "cargo nextest run",
  "cargo test --doc",
]
wait_for = ["lint"]

[tasks."test:review"]
description = "Launch snapshot test and review result (accept or reject)"
run = [
  "cargo insta review",
]
wait_for = ["lint"]

[tasks.test-each-feature]
description = "Test each feature separately"
run = "cargo hack test --each-feature -- --test-threads=1"

[tasks.set-version]
description = "Set version across all workspace crates (Usage: mise run set-version <version>)"
run = '''
#!/usr/bin/env bash
version="{{arg(name="version")}}"
sed -i "s/^version = .*/version = \"$version\"/" Cargo.toml
release-plz set-version axum-tracing-opentelemetry@"$version"
release-plz set-version fake-opentelemetry-collector@"$version"
release-plz set-version init-tracing-opentelemetry@"$version"
# release-plz set-version testing-tracing-opentelemetry@"$version"
release-plz set-version tonic-tracing-opentelemetry@"$version"
release-plz set-version tracing-opentelemetry-instrumentation-sdk@"$version"
'''

[tasks.run-otel-desktop-viewer]
description = "Run otel-desktop-viewer as receiver and viewer of otel trace"
run = [
  "# Viewer: open http://localhost:8000",
  "docker run -p 8000:8000 -p 4317:4317 -p 4318:4318 ghcr.io/ctrlspice/otel-desktop-viewer:latest-amd64",
]

[tasks.run-jaeger]
description = "Run Jaeger all-in-one container"
run = [
  "# Viewer: open http://localhost:16686",
  '''
  docker run --rm --name jaeger \
    -p 16686:16686 \
    -p 4317:4317 \
    -p 4318:4318 \
    -p 5778:5778 \
    -p 9411:9411 \
    cr.jaegertracing.io/jaegertracing/jaeger:latest
  '''
]

[tasks.run-example-grpc-server]
description = "Run gRPC server example"
run = "cd examples/grpc && OTEL_SERVICE_NAME=grpc-server cargo run --bin server"

[tasks.run-example-grpc-client]
description = "Run gRPC client example"
run = '''
grpcurl -plaintext 127.0.0.1:50051 list
cd examples/grpc && OTEL_SERVICE_NAME=grpc-client cargo run --bin client
'''

[tasks.run-example-axum-otlp-server]
description = "Run axum-otlp server example"
run = "cd examples/axum-otlp && OTEL_SERVICE_NAME=axum-otlp-4317 cargo run"

[tasks.run-example-axum-otlp-server-http]
description = "Run axum-otlp server example over HTTP"
run = 'cd examples/axum-otlp && OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://localhost:4318/v1/traces" OTEL_SERVICE_NAME=axum-otlp-4318 cargo run --features otlp-over-http'

[tasks.run-example-http-server]
description = "Run HTTP server example (alias for axum-otlp)"
depends = ["run-example-axum-otlp-server"]

[tasks.run-example-http-client]
description = "Run HTTP client example"
run = '''
# curl -i http://127.0.0.1:3003/health
curl -i http://127.0.0.1:3003/
'''

[tasks.run-example-load]
description = "Run load test example"
run = "cd examples/load && cargo run --release 2>/dev/null"

[tasks.ci]
depends = ["check", "lint", "test", "deny"]


================================================
FILE: .vscode/settings.json
================================================
{
  "cSpell.words": [
    "insta",
    "opentelemetry",
    "OTEL",
    "OTLP",
    "sdktrace",
    "semcov"
  ],
  "rust-analyzer.linkedProjects": [
    "./Cargo.toml",
    "./axum-tracing-opentelemetry/Cargo.toml",
    "./axum-tracing-opentelemetry/Cargo.toml"
  ]
}


================================================
FILE: .yamllint.yml
================================================
###########################################
# These are the rules used for            #
# linting all the yaml files in the stack #
# NOTE:                                   #
# You can disable line with:              #
# # yamllint disable-line                 #
###########################################
extends: default
rules:
  document-start: disable
  new-lines:
    level: warning
    type: unix
  line-length:
    max: 800
  comments:
    min-spaces-from-content: 1 # Used to follow prettier standard: https://github.com/prettier/prettier/pull/10926
  indentation:
    indent-sequences: consistent


================================================
FILE: CHANGELOG.md
================================================
<!-- markdownlint-disable MD024-->
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


### Added

### Changed

- ⬆️ upgrade to opentelemetry 0.24 (and related dependencies)


### Fixed


## [0.17.0] - 2024-02-11

### Added

- ✨ add support for logfmt into `tracing_subscriber_ext::init_subscribers()` ([580d709](580d709161554b5888697604a6ec125a69503b09))

### Changed

- 📝 update CHANGELOG ([d3609ac](d3609ac2cc699d3a24fbf89754053cc8e938e3bf))
- 📝 update link to homepage ([3e081fb](3e081fbd3a410fb9abfbdc0cc7a5a2953fee823a))
- 💄 fix display of OTEL_TRACES_SAMPLER ([62d9c2a](62d9c2a7af020015949e1eaf308d365124aad43b))

### Fixed

- 🐛 on grpc when no status code into header, fallback to OK (previously Unkown) ([f1a23c4](f1a23c4cdeba8abcea598a2d4305dbe6e1a10edf))

## [0.16.0] - 2023-12-30

### Added

- ✨ add support for OTLP headers from environment (#110) ([ccd123b](ccd123b6d7de9c1f10d3d861cb8494db9ed201ee))

### Changed

- 📝 update CHANGELOG ([319b1eb](319b1eb17cc8876d3b7f999a4e1d5b4f534d2816))
- 📝 Update link to changelog, remove homepage, ... ([7f38094](7f380949f73c76a315779db727b75be32211804d))
- ➖ remove dependency to opentelemetry-http ([e049fb0](e049fb0e0c67140b3252bf465aa3c74e6838400d))
- ⬆️ upgrade dependencies for axum-0.7 ([d4ad2d3](d4ad2d31bf8787b8c99332f6b8a7e44e34088886))
- 📝 update example in doc ([b74c686](b74c68604ab359b19d4e43da1a3b0514e1ec2e68))

### Fixed

- 🐛 fix compilation & linter ([24d1eca](24d1eca18a2f85bd2fda98389583684a89d42e7c))

## [0.15.0] - 2023-11-25

### Added

- ✨ add attribute `rpc.grpc.status_code` ([d885954](d8859542f80cf0df365ee18c3fcce654e2e1a843))

### Changed

- ⬆️ upgrade to openteletry 0.21 (and related dependencies) ([21ceb34](21ceb3450973b288743c9fc026cc45072364bb5e))

### Fixed

- 🐛 attribute `http.response.status_code` should of type `int` ([6ff9209](6ff9209175101ed767fd5eee0f5a33f663755dce))

## [0.14.0] - 2023-09-04

### Added

- ✨ enable simple basic grpc tls endpoint (#85) ([ecf4f9d](ecf4f9decce5e14766e6e7c24138bcc3519cd540))

### Changed

- ✏️ fix typo in homepage of init-tracing-opentelemetry ([9cfbaff](9cfbaff8f344e3ba918c7b0fa2587d0d18945172))
- ⬆️ bump tracing-opentelemetry from 0.20 to 0.21 ([6763c41](6763c41ba06e34fe1382e1f797c539e57cbe9cf5))
- ⬆️ bump tonic from 0.9 to 0.10 in tonic-tracing-opentelemetrty ([f33bfe6](f33bfe6f77fd1013497d79f147ce2732d3f4e3ea))

## [0.13.0] - 2023-08-06

### Added

- Feat: add span.type=web on spans ([d76017f](d76017f797b5b9cf2a649824aaea07c81cf84dcf))
- Feat: add span_type enum and documentation ([4871359](487135955342241b2633968c2162415159b9cdab))

### Changed

- ⬆️ upgrade to opentelemetry 0.20 (and related dependencies) ([8b8281e](8b8281ee5e938143379db7d5ef645a830ba87c51))

## [0.12.0] - 2023-07-02

### Changed

- 📝 update README ([400adeb](400adeb7b1105f0c197a29b6a27ec35fe4b1f722))

## [0.12.0-alpha.2] - 2023-06-28

### Added

- 💥 use `otel::tracing` as target for trace instead on the name of the crate ([1fda7c3](1fda7c3d566d4a622710116616d9d28680b7b475))
- ✨  introduce new crate `tracing-opentelemetry-instrumentation-sdk` ([51c45ae](51c45ae5f892e0efbea0ce957d3f3a7524bfe927))
- ✨ grpc server layer can use a filter function to not create trace for some endpoint ([2f3ca50](2f3ca5045ab43fcd5c2f3985f9117c9940d5f3ae))
- 💥 rewrite axum-tracing-opentelemetry ([661b891](661b8917d61b52e8d682863e75bece9ad76e9f9b))

### Changed

- ⚡️ tag as `inline` some helpers function ([753b1a7](753b1a72ece620a46461f7860360ebc347f518bb))

### Fixed

- 🐛 grpc client set the span context during async children processing ([cec0ce5](cec0ce531fbca3caf371ee290593e9cf5e226bf7))
- 🐛 grpc server set the span context during async children processing ([83d88e4](83d88e466049c4613cdd10e2d6668cd3a3d0428e))

## [0.12.0-alpha.1] - 2023-06-14

### Added

- ✨ add basic filtering for axum-tracing-opentelemetry ([bb510a3](bb510a32148182090264d5be9d1c9abe21895083))

### Changed

- 📝 add notes about how to release the workspace ([d1abae1](d1abae15855cfb6fb3d058fbb134f31da82018e3))

## [0.12.0-alpha.0] - 2023-06-14

### Added

- ✨ extract `fake-opentelemetry-collector` ([25becbb](25becbb6633336c189cb2ab02ff94f7530e8ac57))
- ✨ start the tonic-tracing-opentelemetry ([43c179f](43c179f28aa295a81428d2b08ebae83397329943))
- ✨ start the testing-tracing-opentelemetry ([d7ecb0d](d7ecb0dd416fd4d7d78e51abaa8d10a4c0fbb63a))

### Changed

- ➖ remove more unused dependencies ([46793cf](46793cf708952e21ee316dcedaf1873acf175600))

## [0.11.0] - 2023-06-11

### Added

- ✨ add a mock_collector server to to collect trace ([b36f5b1](b36f5b1557963d5678f8a337e0bf45606fb03dcf))

### Changed

- ⬆️ upgrade opentelemetry to 0.19 (and related dependencies) ([36b52a0](36b52a0bad4babfc8ace5fcaab79e897907890d3))
- ⬆️ upgrade opentelemetry to 0.19 (and related dependencies)  (2) ([b7a2a0e](b7a2a0ed9990c35424335e6cf71fa7e28ba1e60b))
- ⬆️ upgrade opentelemetry to 0.19 (and related dependencies)  (3) ([b8719a2](b8719a2912edac8e6556774530fbf99afb82a955))

### Fixed

- 🐛 fix features dependencies ([bdc949d](bdc949d2d0f1eafe0e44ecdbf4607f040150641d))
- Fix: fallback to req uri path for nested route (we can not get matched router in nested router handler) ([36a4302](36a43025ba54721dbb41306086a9135b80350f6c))
- 🐛 generate root opentelemetry span with valid spanId ([c5738a6](c5738a6a4586f9cabd66330335c8353b528498ed))

## [0.10.0] - 2023-02-26

### Added

- 💥 default configuration for otlp Sampler is now longer hardcoded to `always_on`, but read environment variables `OTEL_TRACES_SAMPLER`, `OTEL_TRACES_SAMPLER_ARG` ([c20e7c7](c20e7c77bb2da30737f78a48e4a513d6f3117f24))
- ✨ add a axum layer for gRPC (#36) ([bf7daee](bf7daeeebe1ffd07834388c81349ab7a972abdbe))
- ✨ log under target `otel::setup` detected configuration by otel setup tools ([6c2f5c1](6c2f5c119bea731cb3de770dabcfe726c8edc227))
- ✨ provide opinionated `tracing_subscriber_ext` ([53963eb](53963eb1ee543f3b1c0a0a90a9c00a319694f71b))

### Changed

- 📝 add sample to overwrite `otel.name` ([1dae1aa](1dae1aab7edb2b1cc793ab1e609ea6153e73f2d3))
- 📝 update changelog ([2945358](29453580794da60dacf449676820a8731fd036e9))

## [0.9.0] - 2023-02-05

### Added

- ✨ add `DetectResource` builder to help detection for [Resource Semantic Conventions | OpenTelemetry](https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/#semantic-attributes-with-sdk-provided-default-value) ([db7552e](db7552efdc5ea842bc17e19604a46ebe77283d0c))

### Changed

- 📝 add instruction to launch jaeger for local dev ([95411e9](95411e9640fc7a1e4eaf7bc5a6d9d07362cfe752))
- 📝 improve sample ([1b91fbf](1b91fbf9172578a81598292666fa9bd854a7f4c5))

### Fixed

- 🐛 fix mega-linter.yml ([6494dd6](6494dd6dab76f09e3364b1fe508ee6edae39356b))

## [0.8.2] - 2023-01-30

### Fixed

- 🐛 restore missing line in changelog ([f46c342](f46c3427fa6f31e8aa4e550315160ce2bcbafb1b))
- 🐛 use correct env variable (OTEL_PROPAGATORS) when setting up propagators ([c2d34eb](c2d34eb54a7672b62aefd3429cc264235c5f952d))

## [0.8.1] - 2023-01-29

### Added

- ✨ add `init_propagator` based on OTEL_PROPAGATORS ([b45b2f3](b45b2f3a39afaf86a589b5cef01e147f11416c3d))

### Changed

- 📝 update documentation & samples about configuration ([75a040d](75a040d08ebd41901a803562b1b8788f9a38e031))

## [0.7.1] - 2023-01-01

### Changed

- 📝 use more OTEL env variable into sample ([048f57c](048f57c668a352739172ffd3af965f263452a4a2))

## [0.7.0] - 2022-12-28

### Added

- ✨ add a layer`response_with_trace_layer` to have `traceparent` injected into response ([368c59d](368c59d0b0a928459b24e21ff26eac337c79a283))

### Changed

- 📝 add compatibility matrix ([9312737](93127375a8393a4b8df9dddbd108f875c1ab9cee))
- 📝 update changelog ([820ae63](820ae63eedcfaa76d5182c9c628c233a007ce8e0))

## [0.5.2] - 2022-11-06

### Fixed

- Fix: do not populate http.route when not supported by the HTTP server framework ([93cedaa](93cedaa7a94904cff127a966db94b70dd697cc6a))

## [0.5.1] - 2022-11-01

### Added

- :green_heart: add protoc into the CI require by `opentelemetry-proto` ([a1777c6](a1777c631c603074f9928787d156a5d4806bc708))

### Removed

- :rotating_light: remove useless code (after validation that experiment is ok) ([b17d9f0](b17d9f0a54a76ea3b185acbcdb97bfd0efffca98))

## [0.3.0] - 2022-08-04

### Added

- :pencil: add a sample about how to retrieve trace_id ([6dd26ff](6dd26ff288f95b719a42c4c1939596532a3f9e4c))

### Removed

- :heavy_minus_sign: remove unused tansitive dependencies ([bca0c14](bca0c1485ac47ee2756f5dc7963863b2f6d39057))

## [0.2.1] - 2022-06-11

### Added

- :sparkles: add code for opentelemetry_tracing_layer ([9403583](94035838f97aa61ad304791f0f3174e042a566f3))
- :sparkles: add tools to init tracer and find trace_id ([acb52a3](acb52a3ed98aeed7733ce3dba7aba894122a8949))
- :pencil: add examples code ([0482b59](0482b59f19af6d0e74082b43c19783e1d08e4c95))
- :pencil: add missing info for release ([a2f7c09](a2f7c0961366bcfd160ee89360d30c8874cfb6fd))

<!-- generated by git-cliff -->


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to tracing-opentelemetry-instrumentation-sdk

Thank you for your interest in contributing! This document provides guidelines and instructions for setting up your development environment and contributing to the project.

## Development Environment Setup

### Prerequisites

1. **Install mise** (if not already installed):

   ```bash
   # Using the install script
   curl https://mise.run | sh

   # Or using a package manager
   # macOS: brew install mise
   # Arch: pacman -S mise
   # Ubuntu/Debian: see https://mise.jdx.dev/installing-mise.html
   ```

2. **Clone the repository**:

   ```bash
   git clone https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk.git
   cd tracing-opentelemetry-instrumentation-sdk
   ```

3. **Install tools and dependencies**:

   ```bash
   # Install all tools defined in .mise.toml (Rust, protoc, grpcurl, etc.)
   mise install

   # Activate the environment (or use 'mise use' for shell integration)
   mise activate
   ```

### Available Development Tasks

We use `mise` tasks for all development workflows. Here are the main tasks:

#### Code Quality & Formatting

```bash
# Format code
mise run format

# Lint code (clippy + format check)
mise run lint

# Check code with all feature combinations
mise run check

# Run cargo deny security checks
mise run deny
```

#### Testing

```bash
# Run tests (using nextest + doctests)
mise run test

# Test each feature separately (slower but thorough)
mise run test-each-feature
```

#### Tool Installation

These tasks automatically install required tools if not present:

```bash
# Individual tool installation (usually handled automatically by other tasks)
mise run install:cargo-hack
mise run install:cargo-nextest
mise run install:cargo-insta
mise run install:cargo-deny
```

#### Container & Examples

```bash
# Start Jaeger all-in-one for local development
mise run run-jaeger

# Run example applications
mise run run-example-grpc-server     # gRPC server example
mise run run-example-grpc-client     # gRPC client example
mise run run-example-axum-otlp-server # Axum HTTP server
mise run run-example-http-client     # HTTP client test
mise run run-example-load            # Load testing example
```

#### Version Management

```bash
# Set version across all workspace crates
mise run set-version 0.1.0
```

### Development Workflow

1. **Setup environment** (first time only):

   ```bash
   mise install
   ```

2. **Before making changes**:

   ```bash
   # Format and check code
   mise run format
   mise run lint
   mise run check
   ```

3. **While developing**:

   ```bash
   # Run tests frequently
   mise run test

   # Test with examples if relevant
   mise run run-jaeger &  # Start Jaeger in background
   mise run run-example-axum-otlp-server
   ```

4. **Before submitting PR**:
   ```bash
   # Full validation
   mise run format
   mise run lint
   mise run check
   mise run test
   mise run deny
   ```

### Testing with OpenTelemetry

#### Local Jaeger Setup

```bash
# Start Jaeger (runs on various ports including 16686 for UI, 4317/4318 for OTLP)
mise run run-jaeger

# Open Jaeger UI
open http://localhost:16686
```

#### Running Examples

```bash
# Terminal 1: Start Jaeger
mise run run-jaeger

# Terminal 2: Start example server
mise run run-example-axum-otlp-server

# Terminal 3: Send requests and check traces
mise run run-example-http-client
# Then check traces in Jaeger UI at http://localhost:16686
```

### Project Structure

This workspace contains several crates:

- **`init-tracing-opentelemetry/`**: Helpers to initialize tracing + opentelemetry
- **`axum-tracing-opentelemetry/`**: Axum middlewares for tracing integration
- **`tonic-tracing-opentelemetry/`**: Tonic (gRPC) middlewares for tracing
- **`tracing-opentelemetry-instrumentation-sdk/`**: Core instrumentation SDK
- **`fake-opentelemetry-collector/`**: Testing utilities and fake collector
- **`testing-tracing-opentelemetry/`**: Test utilities
- **`examples/`**: Working examples demonstrating usage

### Code Style & Guidelines

- **Formatting**: We use `rustfmt` with default settings
- **Linting**: All clippy warnings must be addressed
- **Testing**: Add tests for new functionality
- **Documentation**: Update documentation for public APIs
- **Examples**: Update examples if adding new features

### Continuous Integration

Our CI pipeline runs:

- `mise run check` - Feature compatibility checks
- `mise run lint` - Code formatting and clippy
- `mise run test` - Full test suite
- `mise run deny` - Security and license checks

Make sure all these pass locally before submitting a PR.

### Common Issues & Solutions

#### Tool Installation Issues

If tools fail to install automatically:

```bash
# Install cargo-binstall manually
curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash

# Then retry the task
mise run <task-name>
```

#### Container Runtime

The project supports multiple container runtimes (podman, nerdctl, docker). If you have issues:

```bash
# Make sure one of these is installed and available
which podman || which nerdctl || which docker
```

#### Environment Variables

Key environment variables (already set in `.mise.toml`):

- `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://127.0.0.1:4317"`
- `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL="grpc"`
- `OTEL_TRACES_SAMPLER="always_on"`

### Getting Help

- Check existing [issues](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/issues)
- Review the [examples/](examples/) directory for usage patterns
- Look at test files for API usage examples
- Open a new issue for bugs or feature requests

### Submitting Changes

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/my-new-feature`
3. Make your changes following the guidelines above
4. Run the full test suite: `mise run lint && mise run test && mise run deny`
5. Commit with descriptive messages
6. Push to your fork and submit a pull request

Thank you for contributing!


================================================
FILE: Cargo.toml
================================================
[workspace]
resolver = "2"
members = [
  "axum-tracing-opentelemetry",
  "examples/*",
  "fake-opentelemetry-collector",
  "init-tracing-opentelemetry",
  "testing-tracing-opentelemetry",
  "tonic-tracing-opentelemetry",
  "tracing-opentelemetry-instrumentation-sdk",
]
exclude = ["target"]

[workspace.package]
version = "0.32.0"
edition = "2024"
rust-version = "1.91.0"
homepage = "https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk"
repository = "https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk"
license = "CC0-1.0"

[workspace.dependencies]
assert2 = "0.4"
axum = { version = "0.8", default-features = false }
http = "^1"
hyper = "1"
insta = { version = "^1", features = ["redactions", "yaml"] }
opentelemetry = { version = "0.31", default-features = false, features = [
  "trace",
] }
opentelemetry-aws = { version = "0.19", default-features = false }
opentelemetry-jaeger-propagator = { version = "0.31", default-features = false }
opentelemetry-otlp = { version = "0.31", default-features = false }
opentelemetry-proto = { version = "0.31", default-features = false }
opentelemetry-resource-detectors = { version = "0.10", default-features = false }
opentelemetry_sdk = { version = "0.31", default-features = false, features = [
  "rt-tokio",
] }
opentelemetry-semantic-conventions = { version = "0.31", default-features = false }
opentelemetry-stdout = { version = "0.31" }
opentelemetry-zipkin = { version = "0.31", default-features = false }
rstest = "0.26"
tokio = { version = "1", default-features = false }
tokio-stream = { version = "0.1", default-features = false }
tonic = { version = "0.14", default-features = false } # should be sync with opentelemetry-proto
tower = { version = "0.5", default-features = false }
tracing = "0.1"
tracing-opentelemetry = "0.32"

[workspace.metadata.release]
pre-release-commit-message = "🚀 (cargo-release) version {{version}}"
tag-prefix = ""
tag-name = "{{prefix}}{{version}}"
tag-message = "🔖 {{version}}"

[profile.dev.package.insta]
opt-level = 3

[profile.dev.package.similar]
opt-level = 3


================================================
FILE: LICENSE
================================================
Creative Commons Legal Code

CC0 1.0 Universal

    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
    HEREUNDER.

Statement of Purpose

The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").

Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.

For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.

1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:

  i. the right to reproduce, adapt, distribute, perform, display,
     communicate, and translate a Work;
 ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
     likeness depicted in a Work;
 iv. rights protecting against unfair competition in regards to a Work,
     subject to the limitations in paragraph 4(a), below;
  v. rights protecting the extraction, dissemination, use and reuse of data
     in a Work;
 vi. database rights (such as those arising under Directive 96/9/EC of the
     European Parliament and of the Council of 11 March 1996 on the legal
     protection of databases, and under any national implementation
     thereof, including any amended or successor version of such
     directive); and
vii. other similar, equivalent or corresponding rights throughout the
     world based on applicable law or treaty, and any national
     implementations thereof.

2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.

3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.

4. Limitations and Disclaimers.

 a. No trademark or patent rights held by Affirmer are waived, abandoned,
    surrendered, licensed or otherwise affected by this document.
 b. Affirmer offers the Work as-is and makes no representations or
    warranties of any kind concerning the Work, express, implied,
    statutory or otherwise, including without limitation warranties of
    title, merchantability, fitness for a particular purpose, non
    infringement, or the absence of latent or other defects, accuracy, or
    the present or absence of errors, whether or not discoverable, all to
    the greatest extent permissible under applicable law.
 c. Affirmer disclaims responsibility for clearing rights of other persons
    that may apply to the Work or any use thereof, including without
    limitation any person's Copyright and Related Rights in the Work.
    Further, Affirmer disclaims responsibility for obtaining any necessary
    consents, permissions or other rights required for any use of the
    Work.
 d. Affirmer understands and acknowledges that Creative Commons is not a
    party to this document and has no duty or obligation with respect to
    this CC0 or use of the Work.


================================================
FILE: README.md
================================================
# tracing-opentelemetry-instrumentation-sdk

A set of rust crates to help working with tracing + opentelemetry

- `init-tracing-opentelemetry`: A set of helpers to initialize (and more) tracing + opentelemetry (compose your own or use opinionated preset)
- `axum-tracing-opentelemetry`: Middlewares and tools to integrate axum + tracing + opentelemetry.
- `fake-opentelemetry-collector`: A Fake (basic) opentelemetry collector, useful to test what is collected opentelemetry

## For local dev / demo

To collect and visualize trace on local, some ofthe simplest solutions:

![screenshot](examples/axum-otlp/Screenshot-20251103_1308.jpg)

### Otel Desktop Viewer

[CtrlSpice/otel-desktop-viewer: desktop-collector](https://github.com/CtrlSpice/otel-desktop-viewer)

```sh
# also available via `brew install --cask ctrlspice/tap/otel-desktop-viewer`
# For AMD64 (most common)
# docker/nerdctl/podman or any container runner
docker run -p 8000:8000 -p 4317:4317 -p 4318:4318 ghcr.io/ctrlspice/otel-desktop-viewer:latest-amd64

open http://localhost:8000
```

### Jaeger all-in-one

```sh
# launch Jaeger with OpenTelemetry, Jaeger, Zipking,... mode.
# see https://www.jaegertracing.io/docs/1.49/getting-started/#all-in-one

# docker/nerdctl/podman or any container runner
docker run --rm --name jaeger \
  -p 16686:16686 \
  -p 4317:4317 \
  -p 4318:4318 \
  -p 5778:5778 \
  -p 9411:9411 \
  cr.jaegertracing.io/jaegertracing/jaeger:latest

open http://localhost:16686
```

Then :

- setup env variable (or not), (eg see [.envrc](.envrc))
- launch your server
- send the request
- copy trace_id from log (or response header)
- paste into Jaeger web UI

## To release

Use the github workflow `release-plz`.


================================================
FILE: axum-tracing-opentelemetry/CHANGELOG.md
================================================
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.30.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.29.0...axum-tracing-opentelemetry-v0.30.0) - 2025-08-25

### <!-- 2 -->Added

- *(axum)* optional extraction of `client.address` (former `client_ip`) from http headers or socket's info
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.33.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/releases/tag/axum-tracing-opentelemetry-v0.33.0) - 2026-01-19

### <!-- 2 -->Added

- *(deps)* update to rust 1.87 & edition 2024 ([#317](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/317))

## [0.33.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.32.3...axum-tracing-opentelemetry-v0.33.0) - 2026-01-19

### <!-- 2 -->Added

- *(deps)* update to rust 1.87 & edition 2024 ([#317](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/317))

## [0.32.2](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.32.1...axum-tracing-opentelemetry-v0.32.2) - 2025-11-03

### <!-- 4 -->Changed

- update sample

## [0.32.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.32.0...axum-tracing-opentelemetry-v0.32.1) - 2025-10-14

### Wip

- use `opentelemetry-semantic-conventions` instead of `static &str`

## [0.30.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.30.0...axum-tracing-opentelemetry-v0.30.1) - 2025-09-27

## [0.28.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.28.0...axum-tracing-opentelemetry-v0.28.1) - 2025-06-03

### <!-- 3 -->Removed

- remove deprecated sample from README

## [0.26.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.26.0...axum-tracing-opentelemetry-v0.26.1) - 2025-02-26

### <!-- 3 -->Removed

- *(deps)* remove minor constraint when major > 1

## [0.25.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.24.2...axum-tracing-opentelemetry-v0.25.0) - 2025-01-02

### <!-- 2 -->Added

- *(deps)* update rust crate axum to 0.8 (#197)

## [0.24.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.24.0...axum-tracing-opentelemetry-v0.24.1) - 2024-11-24

### <!-- 1 -->Fixed

- Use guard pattern to allow consumers to ensure final trace is sent ([#185](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/185))

## [0.21.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.19.0...axum-tracing-opentelemetry-v0.21.0) - 2024-08-31

### <!-- 1 -->Fixed
- 🐛 workaround for a delay, batch,... behavior in otlp exporter and test with fake-opentelemetry-collector (closed too early)
- 🐛 fix build of contributions (upgrade of opentelemetry, fake collector for logs,...)
- 🐛  Re-export tracing_level_info feature from axum to sdk ([#147](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/147))

### <!-- 4 -->Changed
- 💄 update deprecated syntax "default_features" in Cargo.toml
- ⬆️ upgrade to rstest 0.22

## [0.17.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/axum-tracing-opentelemetry-v0.17.0...axum-tracing-opentelemetry-v0.17.1) - 2024-02-24

### Other
- 👷 tune release-plz
- ✏️ Fix broken /examples URLs ([#129](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/129))


================================================
FILE: axum-tracing-opentelemetry/Cargo.toml
================================================
[package]
name = "axum-tracing-opentelemetry"
description = "Middlewares and tools to integrate axum + tracing + opentelemetry"
readme = "README.md"
keywords = ["axum", "tracing", "opentelemetry"]
categories = [
  "development-tools::debugging",
  "development-tools::profiling",
  "web-programming",
]
homepage = "https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/tree/main/axum-tracing-opentelemetry"
rust-version.workspace = true
edition.workspace = true
version = "0.33.1"
repository.workspace = true
license.workspace = true

[dependencies]
axum = { workspace = true, features = ["matched-path", "tokio"] }
futures-core = "0.3"
futures-util = { version = "0.3", default-features = false, features = [] }
http = { workspace = true }
opentelemetry = { workspace = true, features = [
  "trace",
], default-features = false }
opentelemetry-semantic-conventions = { workspace = true }
pin-project-lite = "0.2"
tower = { workspace = true }
tracing = { workspace = true }
tracing-opentelemetry = { workspace = true }
tracing-opentelemetry-instrumentation-sdk = { path = "../tracing-opentelemetry-instrumentation-sdk", features = [
  "http",
], version = "0.32" }

[dev-dependencies]
fake-opentelemetry-collector = { path = "../fake-opentelemetry-collector" }
testing-tracing-opentelemetry = { path = "../testing-tracing-opentelemetry" }
assert2 = { workspace = true }
hyper = { workspace = true }
insta = { workspace = true }
opentelemetry-otlp = { workspace = true, features = [
  "http-proto",
  "reqwest-client",
  "reqwest-rustls",
] }
opentelemetry-proto = { workspace = true, features = ["gen-tonic"] }
rstest = { workspace = true }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { workspace = true, features = ["full"] }
tokio-stream = { workspace = true, features = ["net"] }
tracing-subscriber = { version = "0.3", default-features = false, features = [
  "env-filter",
  "fmt",
  "json",
] }
# need tokio runtime to run smoke tests.
opentelemetry_sdk = { workspace = true, features = [
  "trace",
  "rt-tokio",
  "testing",
] }

[features]
# to use level `info` instead of `trace` to create otel span
tracing_level_info = [
  "tracing-opentelemetry-instrumentation-sdk/tracing_level_info",
]


================================================
FILE: axum-tracing-opentelemetry/README.md
================================================
# axum-tracing-opentelemetry

[![crates license](https://img.shields.io/crates/l/axum-tracing-opentelemetry.svg)](http://creativecommons.org/publicdomain/zero/1.0/)
[![crate version](https://img.shields.io/crates/v/axum-tracing-opentelemetry.svg)](https://crates.io/crates/axum-tracing-opentelemetry)

[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)

Middlewares to integrate axum + tracing + opentelemetry.

- Read OpenTelemetry header from incoming request
- Start a new trace if no trace found in the incoming request
- Trace is attached into tracing'span
- OpenTelemetry Span is created on close of the tracing's span (behavior from [tracing-opentelemetry])

For examples, you can look at the [examples](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/tree/main/examples/) folder.

```txt
//...
use axum_tracing_opentelemetry::middleware::{OtelAxumLayer, OtelInResponseLayer};

#[tokio::main]
async fn main() -> Result<(), axum::BoxError> {
    // very opinionated init of tracing, look as is source to make your own
    let _guard = init_tracing_opentelemetry::TracingConfig::production().init_subscriber()?;

    let app = app();
    // run it
    let addr = &"0.0.0.0:3000".parse::<SocketAddr>()?;
    tracing::warn!("listening on {}", addr);
    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, app.into_make_service()).await?;
    Ok(())
}

fn app() -> Router {
    Router::new()
        .route("/", get(index)) // request processed inside span
        // include trace context as header into the response
        .layer(OtelInResponseLayer::default())
        //start OpenTelemetry trace on incoming request
        .layer(OtelAxumLayer::default())
        .route("/health", get(health)) // request processed without span / trace
}
```

For more info about how to initialize, you can look at crate [`init-tracing-opentelemetry`] or [`tracing-opentelemetry`].

![screenshot](../examples/axum-otlp/Screenshot-20251103_1308.jpg)

## Changelog - History

[CHANGELOG.md](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/blob/main/CHANGELOG.md)

[`tracing-opentelemetry`]: https://crates.io/crates/tracing-opentelemetry
[`init-tracing-opentelemetry`]: https://crates.io/crates/init-tracing-opentelemetry


================================================
FILE: axum-tracing-opentelemetry/src/lib.rs
================================================
//#![warn(missing_docs)]
#![forbid(unsafe_code)]
#![warn(clippy::perf)]
#![warn(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
#![doc = include_str!("../README.md")]

#[allow(deprecated)]
pub mod middleware;

/// for basic backward compatibility and transition
#[allow(deprecated)]
pub use self::middleware::opentelemetry_tracing_layer;
/// for basic backward compatibility and transition
#[allow(deprecated)]
pub use self::middleware::response_with_trace_layer;

// reexport tracing_opentelemetry_instrumentation_sdk crate
pub use tracing_opentelemetry_instrumentation_sdk;


================================================
FILE: axum-tracing-opentelemetry/src/middleware/mod.rs
================================================
mod response_injector;
mod trace_extractor;

pub use response_injector::*;
pub use trace_extractor::*;


================================================
FILE: axum-tracing-opentelemetry/src/middleware/response_injector.rs
================================================
use futures_core::future::BoxFuture;
use http::{Request, Response};
use std::task::{Context, Poll};
use tower::{Layer, Service};
use tracing_opentelemetry_instrumentation_sdk as otel;
use tracing_opentelemetry_instrumentation_sdk::http as otel_http;

#[deprecated(
    since = "0.12.0",
    note = "keep for transition, replaced by OtelInResponseLayer"
)]
#[must_use]
pub fn response_with_trace_layer() -> OtelInResponseLayer {
    OtelInResponseLayer {}
}

#[derive(Default, Debug, Clone)]
pub struct OtelInResponseLayer;

impl<S> Layer<S> for OtelInResponseLayer {
    type Service = OtelInResponseService<S>;

    fn layer(&self, inner: S) -> Self::Service {
        OtelInResponseService { inner }
    }
}

#[derive(Default, Debug, Clone)]
pub struct OtelInResponseService<S> {
    inner: S,
}

impl<S, B, B2> Service<Request<B>> for OtelInResponseService<S>
where
    S: Service<Request<B>, Response = Response<B2>> + Send + 'static,
    S::Future: Send + 'static,
{
    type Response = S::Response;
    type Error = S::Error;
    // `BoxFuture` is a type alias for `Pin<Box<dyn Future + Send + 'a>>`
    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.inner.poll_ready(cx)
    }

    #[allow(unused_mut)]
    fn call(&mut self, mut request: Request<B>) -> Self::Future {
        let future = self.inner.call(request);

        Box::pin(async move {
            let mut response = future.await?;
            // inject the trace context into the response (optional but useful for debugging and client)
            otel_http::inject_context(&otel::find_current_context(), response.headers_mut());
            Ok(response)
        })
    }
}


================================================
FILE: axum-tracing-opentelemetry/src/middleware/trace_extractor.rs
================================================
//
//! `OpenTelemetry` tracing middleware.
//!
//! This returns a [`OtelAxumLayer`] configured to use [`OpenTelemetry`'s conventional span field
//! names][otel].
//!
//! # Span fields
//!
//! Try to provide some of the field define at
//! [semantic-conventions/.../http-spans.md](https://github.com/open-telemetry/semantic-conventions/blob/v1.25.0/docs/http/http-spans.md)
//! (Please report or provide fix for missing one)
//!
//! # Example
//!
//! ```
//! use axum::{Router, routing::get, http::Request};
//! use axum_tracing_opentelemetry::middleware::OtelAxumLayer;
//! use std::net::SocketAddr;
//! use tower::ServiceBuilder;
//!
//! let app = Router::new()
//!     .route("/", get(|| async {}))
//!     .layer(OtelAxumLayer::default());
//!
//! # async {
//! let addr = &"0.0.0.0:3000".parse::<SocketAddr>().unwrap();
//! let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
//! axum::serve(listener, app.into_make_service())
//!     .await
//!     .expect("server failed");
//! # };
//! ```
//!

use axum::extract::{ConnectInfo, MatchedPath};
use http::{Request, Response};
use opentelemetry_semantic_conventions::attribute::{CLIENT_ADDRESS, HTTP_ROUTE};
use pin_project_lite::pin_project;
use std::{
    error::Error,
    future::Future,
    net::SocketAddr,
    pin::Pin,
    task::{Context, Poll},
};
use tower::{Layer, Service};
use tracing::Span;
use tracing_opentelemetry_instrumentation_sdk::http::{
    self as otel_http, extract_client_ip_from_headers,
};

#[deprecated(
    since = "0.12.0",
    note = "keep for transition, replaced by OtelAxumLayer"
)]
#[must_use]
pub fn opentelemetry_tracing_layer() -> OtelAxumLayer {
    OtelAxumLayer::default()
}

pub type Filter = fn(&str) -> bool;

/// layer/middleware for axum:
///
/// - propagate `OpenTelemetry` context (`trace_id`,...) to server
/// - create a Span for `OpenTelemetry` (and tracing) on call
///
/// `OpenTelemetry` context are extracted from tracing's span.
#[derive(Default, Debug, Clone)]
pub struct OtelAxumLayer {
    filter: Option<Filter>,
    try_extract_client_ip: bool,
}

// add a builder like api
impl OtelAxumLayer {
    #[must_use]
    pub fn filter(self, filter: Filter) -> Self {
        let mut me = self;
        me.filter = Some(filter);
        me
    }

    /// Enable or disable (default) the extraction of client's ip.
    /// Extraction from (in order):
    ///
    /// 1. http header 'Forwarded'
    /// 2. http header `X-Forwarded-For`
    /// 3. socket connection ip, use the `axum::extract::ConnectionInfo` (see [`Router::into_make_service_with_connect_info`] for more details)
    /// 4. empty (failed to extract the information)
    ///
    /// The extracted value could an ip v4, ip v6, a string (as `Forwarded` can use label or hide the client).
    /// The extracted value is stored it as `client.address` in the span/trace
    ///
    /// [`Router::into_make_service_with_connect_info`]: axum::routing::Router::into_make_service_with_connect_info
    #[must_use]
    pub fn try_extract_client_ip(self, enable: bool) -> Self {
        let mut me = self;
        me.try_extract_client_ip = enable;
        me
    }
}

impl<S> Layer<S> for OtelAxumLayer {
    /// The wrapped service
    type Service = OtelAxumService<S>;
    fn layer(&self, inner: S) -> Self::Service {
        OtelAxumService {
            inner,
            filter: self.filter,
            try_extract_client_ip: self.try_extract_client_ip,
        }
    }
}

#[derive(Debug, Clone)]
pub struct OtelAxumService<S> {
    inner: S,
    filter: Option<Filter>,
    try_extract_client_ip: bool,
}

impl<S, B, B2> Service<Request<B>> for OtelAxumService<S>
where
    S: Service<Request<B>, Response = Response<B2>> + Clone + Send + 'static,
    S::Error: Error + 'static, //fmt::Display + 'static,
    S::Future: Send + 'static,
    B: Send + 'static,
{
    type Response = S::Response;
    type Error = S::Error;
    // #[allow(clippy::type_complexity)]
    // type Future = futures_core::future::BoxFuture<'static, Result<Self::Response, Self::Error>>;
    type Future = ResponseFuture<S::Future>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.inner.poll_ready(cx).map_err(Into::into)
    }

    fn call(&mut self, req: Request<B>) -> Self::Future {
        use tracing_opentelemetry::OpenTelemetrySpanExt;
        let req = req;
        let span = if self.filter.is_none_or(|f| f(req.uri().path())) {
            let route = http_route(&req);
            let method = req.method();
            let client_ip = if self.try_extract_client_ip {
                extract_client_ip_from_headers(req.headers())
                    .map(ToString::to_string)
                    .or_else(|| {
                        req.extensions()
                            .get::<ConnectInfo<SocketAddr>>()
                            .map(|ConnectInfo(client_ip)| client_ip.to_string())
                    })
            } else {
                None
            };

            let span = otel_http::http_server::make_span_from_request(&req);
            span.record(HTTP_ROUTE, route);
            span.record("otel.name", format!("{method} {route}").trim());
            if let Some(client_ip) = client_ip {
                span.record(CLIENT_ADDRESS, client_ip);
            }
            if let Err(error) = span.set_parent(otel_http::extract_context(req.headers())) {
                tracing::warn!(?error, "can not set parent trace_id to span");
            }
            span
        } else {
            tracing::Span::none()
        };
        let future = {
            let _enter = span.enter();
            self.inner.call(req)
        };
        ResponseFuture {
            inner: future,
            span,
        }
    }
}

pin_project! {
    /// Response future for [`Trace`].
    ///
    /// [`Trace`]: super::Trace
    pub struct ResponseFuture<F> {
        #[pin]
        pub(crate) inner: F,
        pub(crate) span: Span,
        // pub(crate) start: Instant,
    }
}

impl<Fut, ResBody, E> Future for ResponseFuture<Fut>
where
    Fut: Future<Output = Result<Response<ResBody>, E>>,
    E: std::error::Error + 'static,
{
    type Output = Result<Response<ResBody>, E>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let this = self.project();
        let _guard = this.span.enter();
        let result = futures_util::ready!(this.inner.poll(cx));
        otel_http::http_server::update_span_from_response_or_error(this.span, &result);
        Poll::Ready(result)
    }
}

#[inline]
fn http_route<B>(req: &Request<B>) -> &str {
    req.extensions()
        .get::<MatchedPath>()
        .map_or_else(|| "", |mp| mp.as_str())
}

#[cfg(test)]
mod tests {
    use super::*;
    use axum::{Router, body::Body, routing::get};
    use http::{Request, StatusCode};
    use rstest::rstest;
    use testing_tracing_opentelemetry::{FakeEnvironment, assert_trace};
    use tower::Service;

    #[rstest]
    #[case("filled_http_route_for_existing_route", "http://example.com/users/123", &[], false)]
    #[case("empty_http_route_for_nonexisting_route", "/idontexist/123", &[], false)]
    #[case("status_code_on_close_for_ok", "/users/123", &[], false)]
    #[case("status_code_on_close_for_error", "/status/500", &[], false)]
    #[case("filled_http_headers", "/users/123", &[("user-agent", "tests"), ("x-forwarded-for", "127.0.0.1")], false)]
    #[case("call_with_w3c_trace", "/users/123", &[("traceparent", "00-b2611246a58fd7ea623d2264c5a1e226-b2c9b811f2f424af-01")], true)]
    #[case("trace_id_in_child_span", "/with_child_span", &[], false)]
    #[case("trace_id_in_child_span_for_remote", "/with_child_span", &[("traceparent", "00-b2611246a58fd7ea623d2264c5a1e226-b2c9b811f2f424af-01")], true)]
    // failed to extract "http.route" before axum-0.6.15
    // - https://github.com/davidB/axum-tracing-opentelemetry/pull/54 (reverted)
    // - https://github.com/tokio-rs/axum/issues/1441#issuecomment-1272158039
    #[case("extract_route_from_nested", "/nest/123", &[], false)]
    #[tokio::test(flavor = "multi_thread")]
    async fn check_span_event(
        #[case] name: &str,
        #[case] uri: &str,
        #[case] headers: &[(&str, &str)],
        #[case] is_trace_id_constant: bool,
    ) {
        let mut fake_env = FakeEnvironment::setup().await;
        {
            let mut svc = Router::new()
                .route("/users/{id}", get(|| async { StatusCode::OK }))
                .route(
                    "/status/500",
                    get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
                )
                .route(
                    "/with_child_span",
                    get(|| async {
                        let span = tracing::span!(tracing::Level::INFO, "my child span");
                        span.in_scope(|| {
                            // Any trace events in this closure or code called by it will occur within
                            // the span.
                        });
                        StatusCode::OK
                    }),
                )
                .nest(
                    "/nest",
                    Router::new()
                        .route("/{nest_id}", get(|| async {}))
                        .fallback(|| async { (StatusCode::NOT_FOUND, "inner fallback") }),
                )
                .fallback(|| async { (StatusCode::NOT_FOUND, "outer fallback") })
                .layer(opentelemetry_tracing_layer());
            let mut builder = Request::builder();
            for (key, value) in headers {
                builder = builder.header(*key, *value);
            }
            let req = builder.uri(uri).body(Body::empty()).unwrap();
            let _res = svc.call(req).await.unwrap();

            // while res.data().await.is_some() {}
            // res.trailers().await.unwrap();
            // drop(res);
        }
        let (tracing_events, otel_spans) = fake_env.collect_traces().await;
        assert_trace(name, tracing_events, otel_spans, is_trace_id_constant);
    }
}


================================================
FILE: cliff.toml
================================================
# git-cliff ~ default configuration file
# https://git-cliff.org/docs/configuration
#
# Lines starting with "#" are comments.
# Configuration options are organized into tables and keys.
# See documentation for more information on available options.
# see https://github.com/orhun/git-cliff/blob/main/examples/keepachangelog.toml

[changelog]
# changelog header
header = """
<!-- markdownlint-disable MD024-->
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

"""
# template for the changelog body
# https://keats.github.io/tera/docs/#introduction
body = """
{% if version %}\
    ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
    ## [Unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
    ### {{ group | upper_first }}
    {% for commit in commits %}
        - {{ commit.message | split(pat="\\n") | first | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ commit.id }}))\
    {% endfor %}
{% endfor %}\n
"""
# remove the leading and trailing whitespace from the template
trim = true
# changelog footer
footer = """
<!-- generated by git-cliff -->
"""
# postprocessors
postprocessors = [
  # { pattern = '<REPO>', replace = "https://github.com/orhun/git-cliff" }, # replace repository URL
]
[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = false
# filter out the commits that are not conventional
filter_unconventional = false
# process each line of a commit as an individual commit
split_commits = false
# regex for preprocessing the commit messages
commit_preprocessors = [
  # { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"}, # replace issue numbers
]
# regex for parsing and grouping commits
# try to follow [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
commit_parsers = [
  { message = "^(feat|✨|💥)", group = "Added" },
  { message = "^(fix|🐛|🚑️|👽️)", group = "Fixed" },
  { message = "^(doc|✏️|📝)", group = "Changed" },
  { message = "^(perf|⚡️)", group = "Changed" },
  { message = "^(refactor|🎨|🔥|♻️)", group = "Refactor", skip = true },
  { message = "^(style|💄)", group = "Changed" },
  { message = "^(test|✅)", group = "Fixed", skip = true },
  { message = "^(chore\\(release\\): prepare for|🔖|🚀)", skip = true },
  { message = "^(chore\\(deps\\)|⬇️|⬆️|➕|➖)", group = "Changed" },
  { message = "^chore\\(pr\\)", skip = true },
  { message = "^chore\\(pull\\)", skip = true },
  { message = "^(chore|ci|💚|👷|🚧)", group = "Changed", skip = true },
  { message = "^(🔒️|🔐)", group = "Security" },
  { body = ".*security", group = "Security" },
  { message = "^revert", group = "Changed" },
  { message = "^.*: add", group = "Added" },
  { message = "^.*: support", group = "Added" },
  { message = "^.*: remove", group = "Removed" },
  { message = "^.*: delete", group = "Removed" },
]
# protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
# filter out the commits that are not matched by commit parsers
filter_commits = true
# regex for matching git tags
tag_pattern = "[0-9]+\\.[0-9]+\\.[0-9]+.*"

# regex for skipping tags
skip_tags = ""
# regex for ignoring tags
ignore_tags = ""
# sort the tags topologically
topo_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "oldest"
# limit the number of commits included in the changelog.
# limit_commits = 42


================================================
FILE: deny.toml
================================================
# This template contains all of the possible sections and their default values

# Note that all fields that take a lint level have these possible values:
# * deny - An error will be produced and the check will fail
# * warn - A warning will be produced, but the check will not fail
# * allow - No warning or error will be produced, though in some cases a note
# will be

# The values provided in this template are the default values that will be used
# when any section or field is not specified in your own configuration

# Root options

# The graph table configures how the dependency graph is constructed and thus
# which crates the checks are performed against
[graph]
# If 1 or more target triples (and optionally, target_features) are specified,
# only the specified targets will be checked when running `cargo deny check`.
# This means, if a particular package is only ever used as a target specific
# dependency, such as, for example, the `nix` crate only being used via the
# `target_family = "unix"` configuration, that only having windows targets in
# this list would mean the nix crate, as well as any of its exclusive
# dependencies not shared by any other crates, would be ignored, as the target
# list here is effectively saying which targets you are building for.
targets = [
  # The triple can be any string, but only the target triples built in to
  # rustc (as of 1.40) can be checked against actual config expressions
  # "x86_64-unknown-linux-musl",
  # You can also specify which target_features you promise are enabled for a
  # particular target. target_features are currently not validated against
  # the actual valid features supported by the target architecture.
  # { triple = "wasm32-unknown-unknown", features = ["atomics"] },
]
# When creating the dependency graph used as the source of truth when checks are
# executed, this field can be used to prune crates from the graph, removing them
# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate
# is pruned from the graph, all of its dependencies will also be pruned unless
# they are connected to another crate in the graph that hasn't been pruned,
# so it should be used with care. The identifiers are [Package ID Specifications]
# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html)
# exclude = []
# If true, metadata will be collected with `--all-features`. Note that this can't
# be toggled off if true, if you want to conditionally enable `--all-features` it
# is recommended to pass `--all-features` on the cmd line instead
all-features = false
# If true, metadata will be collected with `--no-default-features`. The same
# caveat with `all-features` applies
no-default-features = false
# If set, these feature will be enabled when collecting metadata. If `--features`
# is specified on the cmd line they will take precedence over this option.
# features = []

# The output table provides options for how/if diagnostics are outputted
[output]
# When outputting inclusion graphs in diagnostics that include features, this
# option can be used to specify the depth at which feature edges will be added.
# This option is included since the graphs can be quite large and the addition
# of features from the crate(s) to all of the graph roots can be far too verbose.
# This option can be overridden via `--feature-depth` on the cmd line
feature-depth = 1

# This section is considered when running `cargo deny check advisories`
# More documentation for the advisories section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
[advisories]
# The path where the advisory databases are cloned/fetched into
# db-path = "$CARGO_HOME/advisory-dbs"
# The url(s) of the advisory databases to use
# db-urls = ["https://github.com/rustsec/advisory-db"]
# A list of advisory IDs to ignore. Note that ignored advisories will still
# output a note when they are encountered.
ignore = [
  # "RUSTSEC-0000-0000",
  # { id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
  # "a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
  # { crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
]
# If this is true, then cargo deny will use the git executable to fetch advisory database.
# If this is false, then it uses a built-in git library.
# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.
# See Git Authentication for more information about setting up git authentication.
# git-fetch-with-cli = true

# This section is considered when running `cargo deny check licenses`
# More documentation for the licenses section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
[licenses]
# List of explicitly allowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
allow = [
  "Apache-2.0",
  "Apache-2.0 WITH LLVM-exception",
  "BSD-2-Clause",
  "BSD-3-Clause",
  "CC0-1.0",
  "ISC",
  "MIT",
  # "OpenSSL",
  "Unicode-3.0",
  # "Unicode-DFS-2016",
  "Unlicense",
  "Zlib"
]
# The confidence threshold for detecting a license from license text.
# The higher the value, the more closely the license text must be to the
# canonical license text of a valid SPDX license file.
# [possible values: any between 0.0 and 1.0].
confidence-threshold = 0.8
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
# aren't accepted for every possible crate as with the normal allow list
exceptions = [
  # Each entry is the crate and version constraint, and its specific allow
  # list
  # { allow = ["Zlib"], crate = "adler32" },
]

# Some crates don't have (easily) machine readable licensing information,
# adding a clarification entry for it allows you to manually specify the
# licensing information
[[licenses.clarify]]
# The package spec the clarification applies to
crate = "ring"
# The SPDX expression for the license requirements of the crate
expression = "MIT AND ISC AND OpenSSL"
license-files = [
  # Each entry is a crate relative path, and the (opaque) hash of its contents
  { path = "LICENSE", hash = 0xbd0eed23 },
]

[licenses.private]
# One or more files in the crate's source used as the "source of truth" for
# the license expression. If the contents match, the clarification will be used
# when running the license check, otherwise the clarification will be ignored
# and the crate will be checked normally, which may produce warnings or errors
# depending on the rest of your configuration
# If true, ignores workspace crates that aren't published, or are only
# published to private registries.
# To see how to mark a crate as unpublished (to the official registry),
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
ignore = false
# One or more private registries that you might publish crates to, if a crate
# is only published to private registries, and ignore is true, the crate will
# not have its license(s) checked
registries = [
  # "https://sekretz.com/registry
]

# This section is considered when running `cargo deny check bans`.
# More documentation about the 'bans' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
[bans]
# Lint level for when multiple versions of the same crate are detected
multiple-versions = "deny"
# Lint level for when a crate version requirement is `*`
wildcards = "allow"
# The graph highlighting used when creating dotgraphs for crates
# with multiple versions
# * lowest-version - The path to the lowest versioned duplicate is highlighted
# * simplest-path - The path to the version with the fewest edges is highlighted
# * all - Both lowest-version and simplest-path are used
highlight = "all"
# The default lint level for `default` features for crates that are members of
# the workspace that is being checked. This can be overridden by allowing/denying
# `default` on a crate-by-crate basis if desired.
workspace-default-features = "allow"
# The default lint level for `default` features for external crates that are not
# members of the workspace. This can be overridden by allowing/denying `default`
# on a crate-by-crate basis if desired.
external-default-features = "allow"
# List of crates that are allowed. Use with care!
allow = [
  # "ansi_term@0.11.0",
  # { crate = "ansi_term@0.11.0", reason = "you can specify a reason it is allowed" },
]
# List of crates to deny
deny = [
  # "ansi_term@0.11.0",
  # { crate = "ansi_term@0.11.0", reason = "you can specify a reason it is banned" },
  # Wrapper crates can optionally be specified to allow the crate when it
  # is a direct dependency of the otherwise banned crate
  # { crate = "ansi_term@0.11.0", wrappers = ["this-crate-directly-depends-on-ansi_term"] },
]

# List of features to allow/deny
# Each entry the name of a crate and a version range. If version is
# not specified, all versions will be matched.
# [[bans.features]]
# crate = "reqwest"
# Features to not allow
# deny = ["json"]
# Features to allow
# allow = [
#    "rustls",
#    "__rustls",
#    "__tls",
#    "hyper-rustls",
#    "rustls",
#    "rustls-pemfile",
#    "rustls-tls-webpki-roots",
#    "tokio-rustls",
#    "webpki-roots",
# ]
# If true, the allowed features must exactly match the enabled feature set. If
# this is set there is no point setting `deny`
# exact = true

# Certain crates/versions that will be skipped when doing duplicate detection.
skip = [
  # "ansi_term@0.11.0",
  # { crate = "ansi_term@0.11.0", reason = "you can specify a reason why it can't be updated/removed" },
  # "axum@0.7",      # tonic depend on axum 0.7
  # "axum-core@0.4", # tonic depend on axum 0.7
  # "matchit@0.7",   # tonic depend on axum 0.7
  # "tower@0.4",     # axum 0.7 use tower 0.5, but hyper still use 0.4
  # "sync_wrapper",   # axum direct and transive dependency use multiple version
  # "regex-syntax",
  # "regex-automata",
  # "indexmap",
  # "hermit-abi",
  # "rustls-native-certs",
  "hashbrown",
  "getrandom",
  # "rand", # until tonic & tower upgrade
  # "rand_chacha", # until tonic & tower upgrade
  # "rand_core", # until tonic & tower upgrade
  "r-efi",
  # "socket2",
  # "wasi",
  "wit-bindgen",
]
# Similarly to `skip` allows you to skip certain crates during duplicate
# detection. Unlike skip, it also includes the entire tree of transitive
# dependencies starting at the specified crate, up to a certain depth, which is
# by default infinite.
skip-tree = [
  # "ansi_term@0.11.0", # will be skipped along with _all_ of its direct and transitive dependencies
  # { crate = "ansi_term@0.11.0", depth = 20 },
  "windows-targets",
  "windows-sys",
  # "async-std",
]

# This section is considered when running `cargo deny check sources`.
# More documentation about the 'sources' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
[sources]
# Lint level for what to happen when a crate from a crate registry that is not
# in the allow list is encountered
unknown-registry = "warn"
# Lint level for what to happen when a crate from a git repository that is not
# in the allow list is encountered
unknown-git = "warn"
# List of URLs for allowed crate registries. Defaults to the crates.io index
# if not specified. If it is specified but empty, no registries are allowed.
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
# List of URLs for allowed Git repositories
allow-git = []

[sources.allow-org]
# github.com organizations to allow git sources for
github = []
# gitlab.com organizations to allow git sources for
gitlab = []
# bitbucket.org organizations to allow git sources for
bitbucket = []


================================================
FILE: examples/axum-otlp/Cargo.toml
================================================
[package]
name = "examples-axum-otlp"
publish = false
edition.workspace = true
version.workspace = true
repository.workspace = true
license.workspace = true

[dependencies]
axum = { workspace = true, default-features = true }
axum-tracing-opentelemetry = { path = "../../axum-tracing-opentelemetry" }
init-tracing-opentelemetry = { path = "../../init-tracing-opentelemetry", features = [
  "otlp",
  "tracing_subscriber_ext",
  "metrics"
] }
opentelemetry = { workspace = true }
opentelemetry-otlp = { workspace = true, default-features = false, features = [
  "reqwest-rustls",
  "http-proto",
  "tls",
] }
serde_json = "1"
tokio = { workspace = true, features = ["full"] }
tracing = { workspace = true }
tracing-opentelemetry-instrumentation-sdk = { path = "../../tracing-opentelemetry-instrumentation-sdk" }


================================================
FILE: examples/axum-otlp/README.md
================================================
# `examples-axum-otlp`

In a terminal, run

Configure the [environment variables](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/) for the OTLP exporter:

```sh
# For GRPC:
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://localhost:4317"
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL="grpc"
export OTEL_TRACES_SAMPLER="always_on"

# For HTTP:
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://127.0.0.1:4318/v1/traces"
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL="http/protobuf"
export OTEL_TRACES_SAMPLER="always_on"
```

```sh
❯ cd examples/axum-otlp
❯ cargo run
   Compiling examples-axum-otlp v0.1.0 (/home/david/src/github.com/davidB/axum-tracing-opentelemetry/examples/axum-otlp)
    Finished dev [unoptimized + debuginfo] target(s) in 3.60s
     Running `/home/david/src/github.com/davidB/axum-tracing-opentelemetry/target/debug/examples-axum-otlp`
     0.000041809s  INFO init_tracing_opentelemetry::tracing_subscriber_ext: init logging & tracing
    at init-tracing-opentelemetry/src/tracing_subscriber_ext.rs:82 on main

     0.000221695s DEBUG otel::setup::resource: key: service.name, value: unknown_service
    at init-tracing-opentelemetry/src/resource.rs:63 on main

     0.000242183s DEBUG otel::setup::resource: key: os.type, value: linux
    at init-tracing-opentelemetry/src/resource.rs:63 on main

     0.000280946s DEBUG otel::setup: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "http://localhost:4317"
    at init-tracing-opentelemetry/src/otlp.rs:22 on main

     0.000293128s DEBUG otel::setup: OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: "grpc"
    at init-tracing-opentelemetry/src/otlp.rs:23 on main

     0.000377897s DEBUG otel::setup: OTEL_TRACES_SAMPLER: "always_on"
    at init-tracing-opentelemetry/src/otlp.rs:80 on main

     0.000561931s DEBUG otel::setup: OTEL_PROPAGATORS: "tracecontext,baggage"
    at init-tracing-opentelemetry/src/lib.rs:97 on main

     0.000134291s  WARN examples_axum_otlp: listening on 0.0.0.0:3003
    at examples/axum-otlp/src/main.rs:15 on main

     0.000150401s  INFO examples_axum_otlp: try to call `curl -i http://127.0.0.1:3003/` (with trace)
    at examples/axum-otlp/src/main.rs:16 on main

     0.000159659s  INFO examples_axum_otlp: try to call `curl -i http://127.0.0.1:3003/health` (with NO trace)
    at examples/axum-otlp/src/main.rs:17 on main
...
```

Into an other terminal, call the `/` (endpoint with `OtelAxumLayer` and `OtelInResponseLayer`)

```sh
❯ curl -i http://127.0.0.1:3003/
HTTP/1.1 200 OK
content-type: application/json
content-length: 50
traceparent: 00-b2611246a58fd7ea623d2264c5a1e226-b2c9b811f2f424af-01
tracestate:
date: Wed, 28 Dec 2022 17:04:59 GMT

{"my_trace_id":"b2611246a58fd7ea623d2264c5a1e226"}
```

call the `/health` (endpoint with NO layer)

```sh
❯ curl -i http://127.0.0.1:3003/health
HTTP/1.1 200 OK
content-type: application/json
content-length: 15
date: Wed, 28 Dec 2022 17:14:07 GMT

{"status":"UP"}
```


================================================
FILE: examples/axum-otlp/src/main.rs
================================================
#![allow(clippy::let_with_type_underscore)]
#![allow(clippy::default_constructed_unit_structs)] // warning since 1.71

use axum::extract::Path;
use axum::{BoxError, Router, response::IntoResponse, routing::get};
use axum_tracing_opentelemetry::middleware::{OtelAxumLayer, OtelInResponseLayer};
use serde_json::json;
use std::net::SocketAddr;
use tracing_opentelemetry_instrumentation_sdk::find_current_trace_id;

#[tokio::main]
async fn main() -> Result<(), BoxError> {
    // very opinionated init of tracing, look as is source to make your own
    let _guard = init_tracing_opentelemetry::TracingConfig::production().init_subscriber()?;

    let app = app();
    // run it
    let addr = &"0.0.0.0:3003".parse::<SocketAddr>()?;
    tracing::warn!("listening on {}", addr);
    tracing::info!("try to call `curl -i http://127.0.0.1:3003/` (with trace)"); //Devskim: ignore DS137138
    tracing::info!("try to call `curl -i http://127.0.0.1:3003/health` (with NO trace)"); //Devskim: ignore DS137138
    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, app.into_make_service()).await?;
    Ok(())
}

fn app() -> Router {
    // build our application with a route
    Router::new()
        .route(
            "/proxy/{service}/{*path}",
            get(proxy_handler).post(proxy_handler),
        )
        .route("/", get(index)) // request processed inside span
        // include trace context as header into the response
        .layer(OtelInResponseLayer::default())
        //start OpenTelemetry trace on incoming request
        .layer(OtelAxumLayer::default())
        .route("/health", get(health)) // request processed without span / trace
}

async fn health() -> impl IntoResponse {
    axum::Json(json!({ "status" : "UP" }))
}

#[tracing::instrument]
async fn index() -> impl IntoResponse {
    tracing::info!(monotonic_counter.index = 1);
    sleep_10ms().await;
    sleep_10ms().await;
    sleep_10ms().await;
    let trace_id = find_current_trace_id();
    dbg!(&trace_id);
    //std::thread::sleep(std::time::Duration::from_secs(1));
    axum::Json(json!({ "my_trace_id": trace_id }))
}

#[tracing::instrument]
async fn sleep_10ms() {
    tokio::time::sleep(std::time::Duration::from_millis(10)).await;
}

async fn proxy_handler(Path((service, path)): Path<(String, String)>) -> impl IntoResponse {
    // Overwrite the otel.name of the span
    tracing::Span::current().record("otel.name", format!("proxy {service}"));
    let trace_id = find_current_trace_id();
    axum::Json(
        json!({ "my_trace_id": trace_id, "fake_proxy": { "service": service, "path": path } }),
    )
}


================================================
FILE: examples/bug_234_tls/Cargo.toml
================================================
[package]
name = "bug_234_tls"
publish = false
edition.workspace = true
version.workspace = true
repository.workspace = true
license.workspace = true

[dependencies]
axum = { workspace = true, default-features = true }
axum-tracing-opentelemetry = { path = "../../axum-tracing-opentelemetry" }
tokio = { version = "1", features = ["full"] }
tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = { version = "0.3.19", features = ["env-filter", "std"] }
init-tracing-opentelemetry = { path = "../../init-tracing-opentelemetry", features = [
    "otlp",
    "tracing_subscriber_ext",
    "tls",
] }
tracing-opentelemetry-instrumentation-sdk = { path = "../../tracing-opentelemetry-instrumentation-sdk", features = [
    "http",
] }
# opentelemetry = { version = "0.29.1", features = ["metrics"] }


================================================
FILE: examples/bug_234_tls/src/main.rs
================================================
use axum::{Router, response::Html, routing::get};

#[tokio::main]
async fn main() {
    // build our application with a route
    let app = Router::new().route("/", get(handler));

    // run it
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    println!("listening on {}", listener.local_addr().unwrap());
    axum::serve(listener, app).await.unwrap();
}

async fn handler() -> Html<&'static str> {
    Html("<h1>Hello, World!</h1>")
}


================================================
FILE: examples/grpc/Cargo.toml
================================================
[package]
name = "examples-grpc"
publish = false
edition.workspace = true
version.workspace = true
repository.workspace = true
license.workspace = true

[dependencies]
init-tracing-opentelemetry = { path = "../../init-tracing-opentelemetry", features = [
  "otlp",
  "tracing_subscriber_ext",
  "logfmt",
] }
opentelemetry = { workspace = true }
prost = "0.14"
tokio = { workspace = true, features = ["full"] }
tonic = { workspace = true, features = ["transport", "router"] }
tonic-health = "0.14"
tonic-prost = "0.14"
tonic-reflection = "0.14"
tonic-tracing-opentelemetry = { path = "../../tonic-tracing-opentelemetry" }
tower = { workspace = true }
tracing = { workspace = true }
tracing-opentelemetry-instrumentation-sdk = { path = "../../tracing-opentelemetry-instrumentation-sdk" }

[build-dependencies]
tonic-prost-build = "0.14"

[[bin]]
name = "server"
path = "src/server.rs"

[[bin]]
name = "client"
path = "src/client.rs"


================================================
FILE: examples/grpc/build.rs
================================================
use std::path::PathBuf;

fn main() {
    // trigger rebuild if "proto" folder change or empty
    print!("cargo:rerun-if-changed=./proto");
    print!("cargo:rerun-if-changed=./src/generated");

    //let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let out_dir = PathBuf::from(std::env!("CARGO_MANIFEST_DIR"))
        .join("src")
        .join("generated");
    std::fs::create_dir_all(&out_dir).unwrap();

    tonic_prost_build::configure()
        .build_client(true)
        .build_server(true)
        .file_descriptor_set_path(out_dir.join("helloworld_descriptor.bin"))
        .out_dir(out_dir)
        .compile_protos(&["helloworld.proto"], &["proto"])
        .unwrap();
}


================================================
FILE: examples/grpc/proto/helloworld.proto
================================================
syntax = "proto3";

import "google/protobuf/empty.proto";
package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  rpc SayStatus (StatusRequest) returns (google.protobuf.Empty) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

message StatusRequest {
  // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md#status-codes-and-their-use-in-grpc
  int32 code = 1;
  string message = 2;
}


================================================
FILE: examples/grpc/src/client.rs
================================================
use generated::greeter_client::GreeterClient;
use generated::{HelloRequest, StatusRequest};
use tonic::Code;
use tonic::transport::Channel;
use tonic_tracing_opentelemetry::middleware::client::OtelGrpcLayer;
use tower::ServiceBuilder;

pub mod generated {
    //tonic::include_proto!("helloworld");
    include!("generated/helloworld.rs");
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // very opinionated init of tracing, look as is source to make your own
    let _guard = init_tracing_opentelemetry::TracingConfig::production()
        .init_subscriber()
        .expect("init subscribers");

    // let channel = Channel::from_static("http://[::1]:50051").connect().await?;
    let channel = Channel::from_static("http://127.0.0.1:50051")
        .connect()
        .await?; //Devskim: ignore DS137138
    let channel = ServiceBuilder::new().layer(OtelGrpcLayer).service(channel);

    let mut client = GreeterClient::new(channel);
    {
        let request = tonic::Request::new(HelloRequest {
            name: "Tonic".into(),
        });

        let response = client.say_hello(request).await?;

        println!("RESPONSE={response:?}");
    }
    {
        let request = tonic::Request::new(StatusRequest {
            code: Code::NotFound.into(),
            message: "not found...".into(),
        });

        let response = client.say_status(request).await;

        println!("RESPONSE={response:?}");
    }
    {
        let request = tonic::Request::new(StatusRequest {
            code: Code::DeadlineExceeded.into(),
            message: "deadline...".into(),
        });

        let response = client.say_status(request).await;

        println!("RESPONSE={response:?}");
    }

    Ok(())
}


================================================
FILE: examples/grpc/src/generated/helloworld.rs
================================================
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct HelloRequest {
    #[prost(string, tag = "1")]
    pub name: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct HelloReply {
    #[prost(string, tag = "1")]
    pub message: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct StatusRequest {
    /// <https://github.com/grpc/grpc/blob/master/doc/statuscodes.md#status-codes-and-their-use-in-grpc>
    #[prost(int32, tag = "1")]
    pub code: i32,
    #[prost(string, tag = "2")]
    pub message: ::prost::alloc::string::String,
}
/// Generated client implementations.
pub mod greeter_client {
    #![allow(
        unused_variables,
        dead_code,
        missing_docs,
        clippy::wildcard_imports,
        clippy::let_unit_value,
    )]
    use tonic::codegen::*;
    use tonic::codegen::http::Uri;
    #[derive(Debug, Clone)]
    pub struct GreeterClient<T> {
        inner: tonic::client::Grpc<T>,
    }
    impl GreeterClient<tonic::transport::Channel> {
        /// Attempt to create a new client by connecting to a given endpoint.
        pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
        where
            D: TryInto<tonic::transport::Endpoint>,
            D::Error: Into<StdError>,
        {
            let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
            Ok(Self::new(conn))
        }
    }
    impl<T> GreeterClient<T>
    where
        T: tonic::client::GrpcService<tonic::body::Body>,
        T::Error: Into<StdError>,
        T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,
        <T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,
    {
        pub fn new(inner: T) -> Self {
            let inner = tonic::client::Grpc::new(inner);
            Self { inner }
        }
        pub fn with_origin(inner: T, origin: Uri) -> Self {
            let inner = tonic::client::Grpc::with_origin(inner, origin);
            Self { inner }
        }
        pub fn with_interceptor<F>(
            inner: T,
            interceptor: F,
        ) -> GreeterClient<InterceptedService<T, F>>
        where
            F: tonic::service::Interceptor,
            T::ResponseBody: Default,
            T: tonic::codegen::Service<
                http::Request<tonic::body::Body>,
                Response = http::Response<
                    <T as tonic::client::GrpcService<tonic::body::Body>>::ResponseBody,
                >,
            >,
            <T as tonic::codegen::Service<
                http::Request<tonic::body::Body>,
            >>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
        {
            GreeterClient::new(InterceptedService::new(inner, interceptor))
        }
        /// Compress requests with the given encoding.
        ///
        /// This requires the server to support it otherwise it might respond with an
        /// error.
        #[must_use]
        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
            self.inner = self.inner.send_compressed(encoding);
            self
        }
        /// Enable decompressing responses.
        #[must_use]
        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
            self.inner = self.inner.accept_compressed(encoding);
            self
        }
        /// Limits the maximum size of a decoded message.
        ///
        /// Default: `4MB`
        #[must_use]
        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
            self.inner = self.inner.max_decoding_message_size(limit);
            self
        }
        /// Limits the maximum size of an encoded message.
        ///
        /// Default: `usize::MAX`
        #[must_use]
        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
            self.inner = self.inner.max_encoding_message_size(limit);
            self
        }
        pub async fn say_hello(
            &mut self,
            request: impl tonic::IntoRequest<super::HelloRequest>,
        ) -> std::result::Result<tonic::Response<super::HelloReply>, tonic::Status> {
            self.inner
                .ready()
                .await
                .map_err(|e| {
                    tonic::Status::unknown(
                        format!("Service was not ready: {}", e.into()),
                    )
                })?;
            let codec = tonic_prost::ProstCodec::default();
            let path = http::uri::PathAndQuery::from_static(
                "/helloworld.Greeter/SayHello",
            );
            let mut req = request.into_request();
            req.extensions_mut()
                .insert(GrpcMethod::new("helloworld.Greeter", "SayHello"));
            self.inner.unary(req, path, codec).await
        }
        pub async fn say_status(
            &mut self,
            request: impl tonic::IntoRequest<super::StatusRequest>,
        ) -> std::result::Result<tonic::Response<()>, tonic::Status> {
            self.inner
                .ready()
                .await
                .map_err(|e| {
                    tonic::Status::unknown(
                        format!("Service was not ready: {}", e.into()),
                    )
                })?;
            let codec = tonic_prost::ProstCodec::default();
            let path = http::uri::PathAndQuery::from_static(
                "/helloworld.Greeter/SayStatus",
            );
            let mut req = request.into_request();
            req.extensions_mut()
                .insert(GrpcMethod::new("helloworld.Greeter", "SayStatus"));
            self.inner.unary(req, path, codec).await
        }
    }
}
/// Generated server implementations.
pub mod greeter_server {
    #![allow(
        unused_variables,
        dead_code,
        missing_docs,
        clippy::wildcard_imports,
        clippy::let_unit_value,
    )]
    use tonic::codegen::*;
    /// Generated trait containing gRPC methods that should be implemented for use with GreeterServer.
    #[async_trait]
    pub trait Greeter: std::marker::Send + std::marker::Sync + 'static {
        async fn say_hello(
            &self,
            request: tonic::Request<super::HelloRequest>,
        ) -> std::result::Result<tonic::Response<super::HelloReply>, tonic::Status>;
        async fn say_status(
            &self,
            request: tonic::Request<super::StatusRequest>,
        ) -> std::result::Result<tonic::Response<()>, tonic::Status>;
    }
    #[derive(Debug)]
    pub struct GreeterServer<T> {
        inner: Arc<T>,
        accept_compression_encodings: EnabledCompressionEncodings,
        send_compression_encodings: EnabledCompressionEncodings,
        max_decoding_message_size: Option<usize>,
        max_encoding_message_size: Option<usize>,
    }
    impl<T> GreeterServer<T> {
        pub fn new(inner: T) -> Self {
            Self::from_arc(Arc::new(inner))
        }
        pub fn from_arc(inner: Arc<T>) -> Self {
            Self {
                inner,
                accept_compression_encodings: Default::default(),
                send_compression_encodings: Default::default(),
                max_decoding_message_size: None,
                max_encoding_message_size: None,
            }
        }
        pub fn with_interceptor<F>(
            inner: T,
            interceptor: F,
        ) -> InterceptedService<Self, F>
        where
            F: tonic::service::Interceptor,
        {
            InterceptedService::new(Self::new(inner), interceptor)
        }
        /// Enable decompressing requests with the given encoding.
        #[must_use]
        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
            self.accept_compression_encodings.enable(encoding);
            self
        }
        /// Compress responses with the given encoding, if the client supports it.
        #[must_use]
        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
            self.send_compression_encodings.enable(encoding);
            self
        }
        /// Limits the maximum size of a decoded message.
        ///
        /// Default: `4MB`
        #[must_use]
        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
            self.max_decoding_message_size = Some(limit);
            self
        }
        /// Limits the maximum size of an encoded message.
        ///
        /// Default: `usize::MAX`
        #[must_use]
        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
            self.max_encoding_message_size = Some(limit);
            self
        }
    }
    impl<T, B> tonic::codegen::Service<http::Request<B>> for GreeterServer<T>
    where
        T: Greeter,
        B: Body + std::marker::Send + 'static,
        B::Error: Into<StdError> + std::marker::Send + 'static,
    {
        type Response = http::Response<tonic::body::Body>;
        type Error = std::convert::Infallible;
        type Future = BoxFuture<Self::Response, Self::Error>;
        fn poll_ready(
            &mut self,
            _cx: &mut Context<'_>,
        ) -> Poll<std::result::Result<(), Self::Error>> {
            Poll::Ready(Ok(()))
        }
        fn call(&mut self, req: http::Request<B>) -> Self::Future {
            match req.uri().path() {
                "/helloworld.Greeter/SayHello" => {
                    #[allow(non_camel_case_types)]
                    struct SayHelloSvc<T: Greeter>(pub Arc<T>);
                    impl<T: Greeter> tonic::server::UnaryService<super::HelloRequest>
                    for SayHelloSvc<T> {
                        type Response = super::HelloReply;
                        type Future = BoxFuture<
                            tonic::Response<Self::Response>,
                            tonic::Status,
                        >;
                        fn call(
                            &mut self,
                            request: tonic::Request<super::HelloRequest>,
                        ) -> Self::Future {
                            let inner = Arc::clone(&self.0);
                            let fut = async move {
                                <T as Greeter>::say_hello(&inner, request).await
                            };
                            Box::pin(fut)
                        }
                    }
                    let accept_compression_encodings = self.accept_compression_encodings;
                    let send_compression_encodings = self.send_compression_encodings;
                    let max_decoding_message_size = self.max_decoding_message_size;
                    let max_encoding_message_size = self.max_encoding_message_size;
                    let inner = self.inner.clone();
                    let fut = async move {
                        let method = SayHelloSvc(inner);
                        let codec = tonic_prost::ProstCodec::default();
                        let mut grpc = tonic::server::Grpc::new(codec)
                            .apply_compression_config(
                                accept_compression_encodings,
                                send_compression_encodings,
                            )
                            .apply_max_message_size_config(
                                max_decoding_message_size,
                                max_encoding_message_size,
                            );
                        let res = grpc.unary(method, req).await;
                        Ok(res)
                    };
                    Box::pin(fut)
                }
                "/helloworld.Greeter/SayStatus" => {
                    #[allow(non_camel_case_types)]
                    struct SayStatusSvc<T: Greeter>(pub Arc<T>);
                    impl<T: Greeter> tonic::server::UnaryService<super::StatusRequest>
                    for SayStatusSvc<T> {
                        type Response = ();
                        type Future = BoxFuture<
                            tonic::Response<Self::Response>,
                            tonic::Status,
                        >;
                        fn call(
                            &mut self,
                            request: tonic::Request<super::StatusRequest>,
                        ) -> Self::Future {
                            let inner = Arc::clone(&self.0);
                            let fut = async move {
                                <T as Greeter>::say_status(&inner, request).await
                            };
                            Box::pin(fut)
                        }
                    }
                    let accept_compression_encodings = self.accept_compression_encodings;
                    let send_compression_encodings = self.send_compression_encodings;
                    let max_decoding_message_size = self.max_decoding_message_size;
                    let max_encoding_message_size = self.max_encoding_message_size;
                    let inner = self.inner.clone();
                    let fut = async move {
                        let method = SayStatusSvc(inner);
                        let codec = tonic_prost::ProstCodec::default();
                        let mut grpc = tonic::server::Grpc::new(codec)
                            .apply_compression_config(
                                accept_compression_encodings,
                                send_compression_encodings,
                            )
                            .apply_max_message_size_config(
                                max_decoding_message_size,
                                max_encoding_message_size,
                            );
                        let res = grpc.unary(method, req).await;
                        Ok(res)
                    };
                    Box::pin(fut)
                }
                _ => {
                    Box::pin(async move {
                        let mut response = http::Response::new(
                            tonic::body::Body::default(),
                        );
                        let headers = response.headers_mut();
                        headers
                            .insert(
                                tonic::Status::GRPC_STATUS,
                                (tonic::Code::Unimplemented as i32).into(),
                            );
                        headers
                            .insert(
                                http::header::CONTENT_TYPE,
                                tonic::metadata::GRPC_CONTENT_TYPE,
                            );
                        Ok(response)
                    })
                }
            }
        }
    }
    impl<T> Clone for GreeterServer<T> {
        fn clone(&self) -> Self {
            let inner = self.inner.clone();
            Self {
                inner,
                accept_compression_encodings: self.accept_compression_encodings,
                send_compression_encodings: self.send_compression_encodings,
                max_decoding_message_size: self.max_decoding_message_size,
                max_encoding_message_size: self.max_encoding_message_size,
            }
        }
    }
    /// Generated gRPC service name
    pub const SERVICE_NAME: &str = "helloworld.Greeter";
    impl<T> tonic::server::NamedService for GreeterServer<T> {
        const NAME: &'static str = SERVICE_NAME;
    }
}


================================================
FILE: examples/grpc/src/server.rs
================================================
use generated::greeter_server::{Greeter, GreeterServer};
use generated::{HelloReply, HelloRequest, StatusRequest};
use tonic::Code;
use tonic::{Request, Response, Status, transport::Server};
use tonic_tracing_opentelemetry::middleware::{filters, server};

pub mod generated {
    //tonic::include_proto!("helloworld");
    include!("generated/helloworld.rs");

    pub(crate) const FILE_DESCRIPTOR_SET: &[u8] =
        //tonic::include_file_descriptor_set!("helloworld_descriptor");
        include_bytes!("generated/helloworld_descriptor.bin");
}

#[derive(Default)]
pub struct MyGreeter {}

#[tonic::async_trait]
impl Greeter for MyGreeter {
    #[tracing::instrument(skip(self, request))]
    async fn say_hello(
        &self,
        request: Request<HelloRequest>,
    ) -> Result<Response<HelloReply>, Status> {
        let trace_id = tracing_opentelemetry_instrumentation_sdk::find_current_trace_id();
        tracing::info!(
            "Got a request from {:?} ({:?})",
            request.remote_addr(),
            trace_id
        );

        let reply = generated::HelloReply {
            message: format!("Hello {}! ({:?})", request.into_inner().name, trace_id),
        };
        Ok(Response::new(reply))
    }

    #[tracing::instrument(skip(self, request))]
    async fn say_status(&self, request: Request<StatusRequest>) -> Result<Response<()>, Status> {
        let trace_id = tracing_opentelemetry_instrumentation_sdk::find_current_trace_id();
        let request = request.into_inner();
        tracing::info!("ask to return status : {} ({:?})", request.code, trace_id);
        Err(Status::new(Code::from(request.code), request.message))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // very opinionated init of tracing, look as is source to make your own
    let _guard = init_tracing_opentelemetry::TracingConfig::production()
        .init_subscriber()
        .expect("init subscribers");

    let addr = "0.0.0.0:50051".parse()?;
    let greeter = MyGreeter::default();

    let (_, health_service) = tonic_health::server::health_reporter();
    let reflection_service = tonic_reflection::server::Builder::configure()
        .register_encoded_file_descriptor_set(generated::FILE_DESCRIPTOR_SET)
        .build_v1()?;

    println!("GreeterServer listening on {addr}");

    Server::builder()
        .timeout(std::time::Duration::from_secs(10))
        // create trace for every request including health_service
        .layer(server::OtelGrpcLayer::default().filter(filters::reject_healthcheck))
        .add_service(health_service)
        .add_service(reflection_service)
        //.add_service(GreeterServer::new(greeter))
        .add_service(GreeterServer::new(greeter))
        .serve(addr)
        .await?;

    Ok(())
}


================================================
FILE: examples/init-tracing-with/.cargo/config.toml
================================================
[build]
rustflags = ["--cfg", "tokio_unstable"]


================================================
FILE: examples/init-tracing-with/Cargo.toml
================================================
[package]
name = "init-tracing-with"
publish = false
edition.workspace = true
version.workspace = true
repository.workspace = true
license.workspace = true

[dependencies]
init-tracing-opentelemetry = { path = "../../init-tracing-opentelemetry", features = [
  "tracing_subscriber_ext",
] }
tokio = { version = "1.48.0", features = [
  "macros",
  "rt-multi-thread",
  "tracing",
] }
tokio-blocked = "0.1.0"
tracing = { workspace = true }
tracing-subscriber = "0.3"


================================================
FILE: examples/init-tracing-with/src/main.rs
================================================
use init_tracing_opentelemetry::TracingConfig;
use tokio_blocked::TokioBlockedLayer;
use tracing::info;
use tracing_subscriber::layer::SubscriberExt;

#[tokio::main]
async fn main() {
    let blocked = TokioBlockedLayer::new()
        .with_warn_busy_single_poll(Some(std::time::Duration::from_micros(150)));

    let _guard = TracingConfig::default()
        .with_log_directives("info,tokio::task=trace,tokio::task::waker=warn")
        .with_span_events(tracing_subscriber::fmt::format::FmtSpan::NONE)
        .init_subscriber_ext(|subscriber| subscriber.with(blocked))
        .unwrap();

    info!("will block in 1 secs");
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;

    tokio::task::spawn(async {
        // BAD!
        // This produces a warning log message.
        info!("blocking!");
        std::thread::sleep(std::time::Duration::from_secs(1));
    })
    .await
    .unwrap();

    // sleep().await;

    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
}

// #[tracing::instrument]
// async fn sleep() {
//     tokio::time::sleep(tokio::time::Duration::from_secs(30)).await;
// }


================================================
FILE: examples/load/Cargo.toml
================================================
[package]
name = "examples-load"
publish = false
edition.workspace = true
version.workspace = true
repository.workspace = true
license.workspace = true

[dependencies]
init-tracing-opentelemetry = { path = "../../init-tracing-opentelemetry", features = [
  "otlp",
  "tracing_subscriber_ext",
] }
memory-stats = "1"
opentelemetry = { workspace = true }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
tracing = { workspace = true }
tracing-opentelemetry-instrumentation-sdk = { path = "../../tracing-opentelemetry-instrumentation-sdk" }


================================================
FILE: examples/load/README.md
================================================
# examples use to

Not an example, but a "load application" used to measure memory usage (+/-)

```sh
> bash -c "cargo run --release 2>/dev/null"
...
13s Current memory usage: Some(MemoryStats { physical_mem: 22814720, virtual_mem: 1123610624 })
13s Current memory usage: Some(MemoryStats { physical_mem: 22835200, virtual_mem: 1123610624 })
13s Current memory usage: Some(MemoryStats { physical_mem: 22859776, virtual_mem: 1123610624 })
13s Current memory usage: Some(MemoryStats { physical_mem: 22863872, virtual_mem: 1123610624 })
14s Current memory usage: Some(MemoryStats { physical_mem: 22867968, virtual_mem: 1123610624 })
14s Current memory usage: Some(MemoryStats { physical_mem: 22876160, virtual_mem: 1123610624 })
14s Current memory usage: Some(MemoryStats { physical_mem: 22888448, virtual_mem: 1123610624 })
15s Current memory usage: Some(MemoryStats { physical_mem: 22892544, virtual_mem: 1123610624 })
15s Current memory usage: Some(MemoryStats { physical_mem: 22896640, virtual_mem: 1123610624 })
15s Current memory usage: Some(MemoryStats { physical_mem: 22904832, virtual_mem: 1123610624 })
16s Current memory usage: Some(MemoryStats { physical_mem: 22921216, virtual_mem: 1123610624 })
16s Current memory usage: Some(MemoryStats { physical_mem: 22933504, virtual_mem: 1123610624 })
16s Current memory usage: Some(MemoryStats { physical_mem: 22937600, virtual_mem: 1123610624 })
16s Current memory usage: Some(MemoryStats { physical_mem: 22941696, virtual_mem: 1123610624 })
22s Current memory usage: Some(MemoryStats { physical_mem: 22945792, virtual_mem: 1123610624 })
22s Current memory usage: Some(MemoryStats { physical_mem: 22949888, virtual_mem: 1123610624 })
28s Current memory usage: Some(MemoryStats { physical_mem: 22970368, virtual_mem: 1123610624 })
36s Current memory usage: Some(MemoryStats { physical_mem: 22999040, virtual_mem: 1123815424 })
36s Current memory usage: Some(MemoryStats { physical_mem: 23003136, virtual_mem: 1123815424 })
36s Current memory usage: Some(MemoryStats { physical_mem: 23007232, virtual_mem: 1123815424 })
36s Current memory usage: Some(MemoryStats { physical_mem: 23011328, virtual_mem: 1123815424 })
37s Current memory usage: Some(MemoryStats { physical_mem: 23015424, virtual_mem: 1123815424 })
38s Current memory usage: Some(MemoryStats { physical_mem: 23207936, virtual_mem: 1123815424 })
38s Current memory usage: Some(MemoryStats { physical_mem: 22712320, virtual_mem: 1123299328 })
38s Current memory usage: Some(MemoryStats { physical_mem: 22786048, virtual_mem: 1123459072 })
38s Current memory usage: Some(MemoryStats { physical_mem: 22872064, virtual_mem: 1123688448 })
38s Current memory usage: Some(MemoryStats { physical_mem: 22876160, virtual_mem: 1123688448 })
39s Current memory usage: Some(MemoryStats { physical_mem: 22880256, virtual_mem: 1123688448 })
40s Current memory usage: Some(MemoryStats { physical_mem: 22888448, virtual_mem: 1123688448 })
40s Current memory usage: Some(MemoryStats { physical_mem: 22904832, virtual_mem: 1123688448 })
40s Current memory usage: Some(MemoryStats { physical_mem: 22921216, virtual_mem: 1123688448 })
...

```


================================================
FILE: examples/load/src/main.rs
================================================
use std::time::Instant;

use memory_stats::memory_stats;
use tracing::field::Empty;
use tracing_opentelemetry_instrumentation_sdk::otel_trace_span;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // very opinionated init of tracing, look as is source to make your own
    let _guard = init_tracing_opentelemetry::TracingConfig::production().init_subscriber()?;
    let mut stats = memory_stats();
    if stats.is_none() {
        eprintln!("Couldn't get the current memory usage :(");
        return Ok(());
    }
    let start = Instant::now();
    loop {
        let prev_stats = stats;
        stats = memory_stats();
        if stats != prev_stats {
            println!(
                "{}s Current memory usage: {:?}",
                start.elapsed().as_secs(),
                stats
            );
        }
        for _i in 1..10000 {
            let _span = otel_trace_span!(
                "Load",
                http.request.method = "GET",
                http.route = Empty,
                network.protocol.version = "1.1",
                http.client.address = Empty,
                http.response.status_code = Empty,
                otel.kind = "Sever",
                otel.status_code = Empty,
                trace_id = Empty,
                request_id = Empty,
                exception.message = Empty,
                //"span.type" = SpanType::Web.to_string(),
            )
            .entered();
            //eprintln!("trace_id: {:?}", tracing_opentelemetry_instrumentation_sdk::find_current_trace_id());
        }
    }
}


================================================
FILE: examples/logging/Cargo.toml
================================================
[package]
name = "examples-logging"
publish = false
edition.workspace = true
version.workspace = true
repository.workspace = true
license.workspace = true

[dependencies]
init-tracing-opentelemetry = { path = "../../init-tracing-opentelemetry", features = [
  "otlp",
  "tracing_subscriber_ext",
  "logs"
] }
memory-stats = "1"
opentelemetry = { workspace = true }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
tracing = { workspace = true }
tracing-opentelemetry-instrumentation-sdk = { path = "../../tracing-opentelemetry-instrumentation-sdk" }


================================================
FILE: examples/logging/src/main.rs
================================================
#[tracing::instrument]
async fn log() {
    tracing::error!("This is ground control to Major Tom");
    tracing::warn!("Houston, we have a problem");
    tracing::info!("We have contact");
    tracing::debug!("Roger, copy that");
    tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
}

#[tracing::instrument]
async fn calc(a: i32, b: i32) {
    let result = a + b;
    tracing::info!(result, "calculated result");
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // setting up tracing
    let _guard = init_tracing_opentelemetry::TracingConfig::production().init_subscriber()?;

    log().await;
    calc(1, 2).await;

    Ok(())
}


================================================
FILE: fake-opentelemetry-collector/CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.34.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/fake-opentelemetry-collector-v0.34.0...fake-opentelemetry-collector-v0.34.1) - 2026-03-15

### <!-- 1 -->Fixed

- MSRV (bump to 1.88) & api changes in dependencies, reformat ([#325](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/325))

## [0.34.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/fake-opentelemetry-collector-v0.33.1...fake-opentelemetry-collector-v0.34.0) - 2026-01-19

### <!-- 2 -->Added

- *(deps)* update to rust 1.87 & edition 2024 ([#317](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/317))

## [0.33.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/fake-opentelemetry-collector-v0.32.0...fake-opentelemetry-collector-v0.33.0) - 2025-11-22

### <!-- 2 -->Added

- *(metrics)* add support for metrics to the `fake-opentelemetry-collector` ([#302](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/302))

## [0.32.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/fake-opentelemetry-collector-v0.28.0...fake-opentelemetry-collector-v0.32.0) - 2025-06-03

### <!-- 2 -->Added

- *(deps)* update opentelemetry 0.30 & tonic 0.13 (#240)

## [0.28.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/fake-opentelemetry-collector-v0.26.1...fake-opentelemetry-collector-v0.28.0) - 2025-03-31

### <!-- 2 -->Added

- *(deps)* update opentelemetry to 0.29 (#227)

## [0.26.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/fake-opentelemetry-collector-v0.26.0...fake-opentelemetry-collector-v0.26.1) - 2025-02-26

### <!-- 3 -->Removed

- *(deps)* remove minor constraint when major > 1

## [0.25.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/fake-opentelemetry-collector-v0.24.0...fake-opentelemetry-collector-v0.25.0) - 2024-11-24

### <!-- 1 -->Fixed

- [**breaking**] use `TraceProvider::flush_force()` during test

## [0.21.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/fake-opentelemetry-collector-v0.20.0...fake-opentelemetry-collector-v0.21.0) - 2024-09-22

### <!-- 2 -->Added

- *(deps)* upgrade to opentelemetry 0.25

## [0.17.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/fake-opentelemetry-collector-v0.17.0...fake-opentelemetry-collector-v0.17.1) - 2024-02-24

### Other
- 👷 tune release-plz


================================================
FILE: fake-opentelemetry-collector/Cargo.toml
================================================
[package]
name = "fake-opentelemetry-collector"
description = "A Fake (basic) opentelemetry collector, useful to test what is collected opentelemetry"
readme = "README.md"
keywords = ["tracing", "opentelemetry", "faker", "mock"]
categories = ["development-tools::testing"]
edition.workspace = true
version = "0.34.1"
repository.workspace = true
license.workspace = true

[dependencies]
futures = "0.3"
hex = "0.4"
opentelemetry = { workspace = true }
opentelemetry-otlp = { workspace = true, features = [
  "grpc-tonic",
  "logs",
  "trace",
  "metrics",
] }
opentelemetry-proto = { workspace = true, features = [
  "gen-tonic",
  "logs",
  "trace",
] }
# need tokio runtime to run smoke tests.
opentelemetry_sdk = { workspace = true, features = [
  "trace",
  "rt-tokio",
  "testing",
] }
serde = { version = "1", features = ["derive"] }
tokio = { workspace = true, features = ["full"] }
tokio-stream = { workspace = true, features = ["net"] }
tonic = { workspace = true, features = ["codegen", "transport", "router"]}
tracing = { workspace = true }

[dev-dependencies]
assert2 = { workspace = true }
insta = { workspace = true }


================================================
FILE: fake-opentelemetry-collector/README.md
================================================
# fake-opentelemetry-collector

A Fake (basic) opentelemetry collector, useful to test what is collected by opentelemetry

Usage example with [insta](https://crates.io/crates/insta) (snapshot testing)

```rust
use std::time::Duration;

use fake_opentelemetry_collector::{setup_tracer_provider, FakeCollectorServer};
use opentelemetry::trace::TracerProvider;
use opentelemetry::trace::{Span, SpanKind, Tracer};
use tracing::debug;

#[tokio::test(flavor = "multi_thread")]
async fn demo_fake_tracer_and_collector() {
    debug!("Start the fake collector");
    let mut fake_collector = FakeCollectorServer::start()
        .await
        .expect("fake collector setup and started");

    debug!("Init the 'application' & tracer provider");
    let tracer_provider = setup_tracer_provider(&fake_collector).await;
    let tracer = tracer_provider.tracer("test");

    debug!("Run the 'application' & sending span...");
    let mut span = tracer
        .span_builder("my-test-span")
        .with_kind(SpanKind::Server)
        .start(&tracer);
    span.add_event("my-test-event", vec![]);
    span.end();

    debug!("Shutdown the 'application' & tracer provider and force flush the spans");
    let _ = tracer_provider.force_flush();
    tracer_provider
        .shutdown()
        .expect("no error during shutdown");
    drop(tracer_provider);

    debug!("Collect & check the spans");
    let otel_spans = fake_collector
        .exported_spans(1, Duration::from_secs(20))
        .await;
    //insta::assert_debug_snapshot!(otel_spans);
    insta::assert_yaml_snapshot!(otel_spans, {
        "[].start_time_unix_nano" => "[timestamp]",
        "[].end_time_unix_nano" => "[timestamp]",
        "[].events[].time_unix_nano" => "[timestamp]",
        "[].trace_id" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(trace_id) = value.as_str());
            format!("[trace_id:lg{}]", trace_id.len())
        }),
        "[].span_id" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(span_id) = value.as_str());
            format!("[span_id:lg{}]", span_id.len())
        }),
        "[].links[].trace_id" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(trace_id) = value.as_str());
            format!("[trace_id:lg{}]", trace_id.len())
        }),
        "[].links[].span_id" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(span_id) = value.as_str());
            format!("[span_id:lg{}]", span_id.len())
        }),
    });
}
```

test example at <https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/tree/main/fake-opentelemetry-collector/tests>


================================================
FILE: fake-opentelemetry-collector/src/common.rs
================================================
use std::collections::BTreeMap;

pub(crate) fn cnv_attributes(
    attributes: &[opentelemetry_proto::tonic::common::v1::KeyValue],
) -> BTreeMap<String, String> {
    attributes
        .iter()
        .map(|kv| (kv.key.to_string(), format!("{:?}", kv.value)))
        .collect::<BTreeMap<String, String>>()
}


================================================
FILE: fake-opentelemetry-collector/src/lib.rs
================================================
mod common;
mod logs;
mod metrics;
mod trace;

use logs::*;
use metrics::*;
use trace::*;

pub use logs::ExportedLog;
pub use metrics::ExportedMetric;
pub use trace::ExportedSpan;

use futures::StreamExt;
use opentelemetry_otlp::{LogExporter, MetricExporter, SpanExporter, WithExportConfig};
use opentelemetry_proto::tonic::collector::logs::v1::logs_service_server::LogsServiceServer;
use opentelemetry_proto::tonic::collector::metrics::v1::metrics_service_server::MetricsServiceServer;
use opentelemetry_proto::tonic::collector::trace::v1::trace_service_server::TraceServiceServer;
use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider};
use std::net::SocketAddr;
use std::time::{Duration, Instant};
use tokio::sync::mpsc;
use tokio::sync::mpsc::Receiver;
use tokio_stream::wrappers::TcpListenerStream;
use tracing::debug;

pub struct FakeCollectorServer {
    address: SocketAddr,
    req_rx: mpsc::Receiver<ExportedSpan>,
    log_rx: mpsc::Receiver<ExportedLog>,
    metrics_rx: mpsc::Receiver<ExportedMetric>,
    handle: tokio::task::JoinHandle<()>,
}

impl FakeCollectorServer {
    pub async fn start() -> Result<Self, Box<dyn std::error::Error>> {
        let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
        let listener = tokio::net::TcpListener::bind(addr).await?;
        let addr = listener.local_addr()?;
        let stream = TcpListenerStream::new(listener).map(|s| {
            if let Ok(ref s) = s {
                debug!("Got new conn at {}", s.peer_addr()?);
            }
            s
        });

        let (req_tx, req_rx) = mpsc::channel::<ExportedSpan>(64);
        let (log_tx, log_rx) = mpsc::channel::<ExportedLog>(64);
        let (metrics_tx, metrics_rx) = mpsc::channel::<ExportedMetric>(64);
        let trace_service = TraceServiceServer::new(FakeTraceService::new(req_tx));
        let logs_service = LogsServiceServer::new(FakeLogsService::new(log_tx));
        let metrics_service = MetricsServiceServer::new(FakeMetricsService::new(metrics_tx));
        let handle = tokio::task::spawn(async move {
            debug!("start FakeCollectorServer http://{addr}"); //Devskim: ignore DS137138)
            tonic::transport::Server::builder()
                .add_service(trace_service)
                .add_service(logs_service)
                .add_service(metrics_service)
                .serve_with_incoming(stream)
                .await
                .expect("Server failed");
            debug!("stop FakeCollectorServer");
        });
        Ok(Self {
            address: addr,
            req_rx,
            log_rx,
            metrics_rx,
            handle,
        })
    }

    pub fn address(&self) -> SocketAddr {
        self.address
    }

    pub fn endpoint(&self) -> String {
        format!("http://{}", self.address()) //Devskim: ignore DS137138)
    }

    pub async fn exported_spans(
        &mut self,
        at_least: usize,
        timeout: Duration,
    ) -> Vec<ExportedSpan> {
        recv_many(&mut self.req_rx, at_least, timeout).await
    }

    pub async fn exported_logs(&mut self, at_least: usize, timeout: Duration) -> Vec<ExportedLog> {
        recv_many(&mut self.log_rx, at_least, timeout).await
    }

    pub async fn exported_metrics(
        &mut self,
        at_least: usize,
        timeout: Duration,
    ) -> Vec<ExportedMetric> {
        recv_many(&mut self.metrics_rx, at_least, timeout).await
    }

    pub fn abort(self) {
        self.handle.abort()
    }
}

async fn recv_many<T>(rx: &mut Receiver<T>, at_least: usize, timeout: Duration) -> Vec<T> {
    let deadline = Instant::now();
    let pause = (timeout / 10).min(Duration::from_millis(10));
    while rx.len() < at_least && deadline.elapsed() < timeout {
        tokio::time::sleep(pause).await;
    }
    std::iter::from_fn(|| rx.try_recv().ok()).collect::<Vec<_>>()
}

pub async fn setup_tracer_provider(
    fake_server: &FakeCollectorServer,
) -> opentelemetry_sdk::trace::SdkTracerProvider {
    // if the environment variable is set (in test or in caller), `with_endpoint` value is ignored
    // if std::env::var("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT").is_ok() {
    //     panic!(
    //         "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT is set, but it should not be, conflict with fake collector"
    //     );
    // }
    unsafe {
        std::env::remove_var("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"); // unsafe
    }

    opentelemetry_sdk::trace::SdkTracerProvider::builder()
        .with_batch_exporter(
            SpanExporter::builder()
                .with_tonic()
                .with_endpoint(fake_server.endpoint())
                .build()
                .expect("failed to install tracer"),
        )
        .build()
}

pub async fn setup_logger_provider(
    fake_server: &FakeCollectorServer,
) -> opentelemetry_sdk::logs::SdkLoggerProvider {
    opentelemetry_sdk::logs::SdkLoggerProvider::builder()
        //Install simple so we don't have to wait for batching in tests
        .with_simple_exporter(
            LogExporter::builder()
                .with_tonic()
                .with_endpoint(fake_server.endpoint())
                .build()
                .expect("failed to install logging"),
        )
        .build()
}

pub async fn setup_meter_provider(
    fake_server: &FakeCollectorServer,
) -> opentelemetry_sdk::metrics::SdkMeterProvider {
    let exporter = MetricExporter::builder()
        .with_tonic()
        .with_endpoint(fake_server.endpoint())
        .build()
        .expect("failed to install metrics");

    let reader = PeriodicReader::builder(exporter).build();

    SdkMeterProvider::builder().with_reader(reader).build()
}


================================================
FILE: fake-opentelemetry-collector/src/logs.rs
================================================
use crate::common::cnv_attributes;
use opentelemetry_proto::tonic::collector::logs::v1::{
    ExportLogsServiceRequest, ExportLogsServiceResponse, logs_service_server::LogsService,
};
use serde::Serialize;
use std::collections::BTreeMap;
use tokio::sync::mpsc;

/// This is created to flatten the log record to make it more compatible with insta for testing
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ExportedLog {
    pub trace_id: String,
    pub span_id: String,
    pub observed_time_unix_nano: u64,
    pub severity_number: i32,
    pub severity_text: String,
    pub body: Option<String>,
    pub attributes: BTreeMap<String, String>,
    pub dropped_attributes_count: u32,
    pub flags: u32,
}

impl From<opentelemetry_proto::tonic::logs::v1::LogRecord> for ExportedLog {
    fn from(value: opentelemetry_proto::tonic::logs::v1::LogRecord) -> Self {
        Self {
            trace_id: hex::encode(value.trace_id),
            span_id: hex::encode(value.span_id),
            observed_time_unix_nano: value.observed_time_unix_nano,
            severity_number: value.severity_number,
            severity_text: value.severity_text,
            body: value.body.map(|value| format!("{value:?}")),
            attributes: cnv_attributes(&value.attributes),
            dropped_attributes_count: value.dropped_attributes_count,
            flags: value.flags,
        }
    }
}

pub(crate) struct FakeLogsService {
    tx: mpsc::Sender<ExportedLog>,
}

impl FakeLogsService {
    pub fn new(tx: mpsc::Sender<ExportedLog>) -> Self {
        Self { tx }
    }
}

#[tonic::async_trait]
impl LogsService for FakeLogsService {
    async fn export(
        &self,
        request: tonic::Request<ExportLogsServiceRequest>,
    ) -> Result<tonic::Response<ExportLogsServiceResponse>, tonic::Status> {
        let sender = self.tx.clone();
        for el in request
            .into_inner()
            .resource_logs
            .into_iter()
            .flat_map(|rl| rl.scope_logs)
            .flat_map(|sl| sl.log_records)
            .map(ExportedLog::from)
        {
            sender
                .send(el)
                .await
                .inspect_err(|e| eprintln!("failed to send to channel: {e}"))
                .map_err(|err| tonic::Status::from_error(Box::new(err)))?;
        }

        Ok(tonic::Response::new(ExportLogsServiceResponse {
            partial_success: None,
        }))
    }
}


================================================
FILE: fake-opentelemetry-collector/src/metrics.rs
================================================
use crate::common::cnv_attributes;
use opentelemetry_proto::tonic::{
    collector::metrics::v1::{
        ExportMetricsServiceRequest, ExportMetricsServiceResponse,
        metrics_service_server::MetricsService,
    },
    metrics::v1 as otel_metrics,
};
use serde::Serialize;
use std::collections::BTreeMap;
use tokio::sync::mpsc;

pub(crate) struct FakeMetricsService {
    tx: mpsc::Sender<ExportedMetric>,
}

impl FakeMetricsService {
    pub fn new(tx: mpsc::Sender<ExportedMetric>) -> Self {
        Self { tx }
    }
}

#[tonic::async_trait]
impl MetricsService for FakeMetricsService {
    async fn export(
        &self,
        request: tonic::Request<ExportMetricsServiceRequest>,
    ) -> Result<tonic::Response<ExportMetricsServiceResponse>, tonic::Status> {
        let sender = self.tx.clone();
        for el in request
            .into_inner()
            .resource_metrics
            .iter()
            .flat_map(|e| e.scope_metrics.to_vec())
            .map(ExportedMetric::from)
        {
            sender
                .send(el)
                .await
                .inspect_err(|e| eprintln!("failed to send to channel: {e}"))
                .map_err(|err| tonic::Status::from_error(Box::new(err)))?;
        }

        Ok(tonic::Response::new(ExportMetricsServiceResponse {
            partial_success: None,
        }))
    }
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ExportedMetric {
    pub metrics: Vec<Metric>,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Metric {
    pub name: String,
    pub description: String,
    pub unit: String,
    pub data: Option<MetricsData>,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum MetricsData {
    Gauge(Gauge),
    Sum(Sum),
    Histogram(Histogram),
    ExponentialHistogram(ExponentialHistogram),
    Summary(Summary),
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Gauge {
    pub data_points: Vec<NumberDataPoint>,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Sum {
    pub data_points: Vec<NumberDataPoint>,
    pub aggregation_temporality: i32,
    pub is_monotonic: bool,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Histogram {
    pub data_points: Vec<HistogramDataPoint>,
    pub aggregation_temporality: i32,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ExponentialHistogram {
    pub data_points: Vec<ExponentialHistogramDataPoint>,
    pub aggregation_temporality: i32,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Summary {
    pub data_points: Vec<SummaryDataPoint>,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct NumberDataPoint {
    pub attributes: BTreeMap<String, String>,
    pub start_time_unix_nano: u64,
    pub time_unix_nano: u64,
    pub exemplars: Vec<Exemplar>,
    pub flags: u32,
    pub value: Option<Value>,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct HistogramDataPoint {
    pub attributes: BTreeMap<String, String>,
    pub start_time_unix_nano: u64,
    pub time_unix_nano: u64,
    pub count: u64,
    pub sum: Option<f64>,
    pub bucket_counts: Vec<u64>,
    pub explicit_bounds: Vec<f64>,
    pub flags: u32,
    pub min: Option<f64>,
    pub max: Option<f64>,
    pub exemplars: Vec<Exemplar>,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ExponentialHistogramDataPoint {
    pub attributes: BTreeMap<String, String>,
    pub start_time_unix_nano: u64,
    pub time_unix_nano: u64,
    pub count: u64,
    pub sum: Option<f64>,
    pub scale: i32,
    pub zero_count: u64,
    pub positive: Option<Buckets>,
    pub negative: Option<Buckets>,
    pub flags: u32,
    pub exemplars: Vec<Exemplar>,
    pub min: Option<f64>,
    pub max: Option<f64>,
    pub zero_threshold: f64,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Buckets {
    pub offset: i32,
    pub bucket_counts: Vec<u64>,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct SummaryDataPoint {
    pub attributes: BTreeMap<String, String>,
    pub start_time_unix_nano: u64,
    pub time_unix_nano: u64,
    pub count: u64,
    pub sum: f64,
    pub quantile_values: Vec<ValueAtQuantile>,
    pub flags: u32,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ValueAtQuantile {
    pub quantile: f64,
    pub value: f64,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Exemplar {
    pub filtered_attributes: BTreeMap<String, String>,
    pub time_unix_nano: u64,
    pub span_id: String,
    pub trace_id: String,
    pub value: Option<Value>,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum Value {
    AsDouble(f64),
    AsInt(i64),
}

impl From<otel_metrics::ScopeMetrics> for ExportedMetric {
    fn from(value: otel_metrics::ScopeMetrics) -> Self {
        ExportedMetric {
            metrics: value
                .metrics
                .iter()
                .map(|m| Metric {
                    name: m.name.clone(),
                    description: m.description.clone(),
                    unit: m.unit.clone(),
                    data: m.data.clone().map(Into::into),
                })
                .collect(),
        }
    }
}

impl From<otel_metrics::metric::Data> for MetricsData {
    fn from(value: otel_metrics::metric::Data) -> Self {
        match value {
            otel_metrics::metric::Data::Gauge(g) => MetricsData::Gauge(g.into()),
            otel_metrics::metric::Data::Sum(s) => MetricsData::Sum(s.into()),
            otel_metrics::metric::Data::Histogram(h) => MetricsData::Histogram(h.into()),
            otel_metrics::metric::Data::ExponentialHistogram(h) => {
                MetricsData::ExponentialHistogram(h.into())
            }
            otel_metrics::metric::Data::Summary(s) => MetricsData::Summary(s.into()),
        }
    }
}

impl From<otel_metrics::Summary> for Summary {
    fn from(value: otel_metrics::Summary) -> Self {
        Self {
            data_points: value.data_points.iter().map(Into::into).collect(),
        }
    }
}

impl From<otel_metrics::ExponentialHistogram> for ExponentialHistogram {
    fn from(value: otel_metrics::ExponentialHistogram) -> Self {
        Self {
            data_points: value.data_points.iter().map(Into::into).collect(),
            aggregation_temporality: value.aggregation_temporality,
        }
    }
}

impl From<otel_metrics::Histogram> for Histogram {
    fn from(value: otel_metrics::Histogram) -> Self {
        Self {
            data_points: value.data_points.iter().map(Into::into).collect(),
            aggregation_temporality: value.aggregation_temporality,
        }
    }
}

impl From<otel_metrics::Sum> for Sum {
    fn from(value: otel_metrics::Sum) -> Self {
        Self {
            data_points: value.data_points.iter().map(Into::into).collect(),
            aggregation_temporality: value.aggregation_temporality,
            is_monotonic: value.is_monotonic,
        }
    }
}

impl From<otel_metrics::Gauge> for Gauge {
    fn from(value: otel_metrics::Gauge) -> Self {
        Self {
            data_points: value.data_points.iter().map(Into::into).collect(),
        }
    }
}

impl From<&otel_metrics::NumberDataPoint> for NumberDataPoint {
    fn from(value: &otel_metrics::NumberDataPoint) -> Self {
        Self {
            attributes: cnv_attributes(&value.attributes),
            start_time_unix_nano: value.start_time_unix_nano,
            time_unix_nano: value.time_unix_nano,
            exemplars: value.exemplars.iter().map(Into::into).collect(),
            flags: value.flags,
            value: value.value.map(Into::into),
        }
    }
}

impl From<&otel_metrics::Exemplar> for Exemplar {
    fn from(value: &otel_metrics::Exemplar) -> Self {
        Self {
            filtered_attributes: cnv_attributes(&value.filtered_attributes),
            time_unix_nano: value.time_unix_nano,
            span_id: hex::encode(&value.span_id),
            trace_id: hex::encode(&value.trace_id),
            value: value.value.map(Into::into),
        }
    }
}

impl From<&otel_metrics::SummaryDataPoint> for SummaryDataPoint {
    fn from(value: &otel_metrics::SummaryDataPoint) -> Self {
        Self {
            attributes: cnv_attributes(&value.attributes),
            start_time_unix_nano: value.start_time_unix_nano,
            time_unix_nano: value.time_unix_nano,
            count: value.count,
            sum: value.sum,
            quantile_values: value.quantile_values.iter().map(Into::into).collect(),
            flags: value.flags,
        }
    }
}

impl From<&otel_metrics::summary_data_point::ValueAtQuantile> for ValueAtQuantile {
    fn from(value: &otel_metrics::summary_data_point::ValueAtQuantile) -> Self {
        Self {
            quantile: value.quantile,
            value: value.value,
        }
    }
}

impl From<&otel_metrics::HistogramDataPoint> for HistogramDataPoint {
    fn from(value: &otel_metrics::HistogramDataPoint) -> Self {
        Self {
            attributes: cnv_attributes(&value.attributes),
            start_time_unix_nano: value.start_time_unix_nano,
            time_unix_nano: value.time_unix_nano,
            count: value.count,
            sum: value.sum,
            bucket_counts: value.bucket_counts.to_vec(),
            flags: value.flags,
            explicit_bounds: value.explicit_bounds.to_vec(),
            max: value.max,
            min: value.min,
            exemplars: value.exemplars.iter().map(Into::into).collect(),
        }
    }
}

impl From<&otel_metrics::ExponentialHistogramDataPoint> for ExponentialHistogramDataPoint {
    fn from(value: &otel_metrics::ExponentialHistogramDataPoint) -> Self {
        Self {
            attributes: cnv_attributes(&value.attributes),
            start_time_unix_nano: value.start_time_unix_nano,
            time_unix_nano: value.time_unix_nano,
            count: value.count,
            sum: value.sum,
            scale: value.scale,
            zero_count: value.zero_count,
            positive: value.positive.as_ref().map(Into::into),
            negative: value.negative.as_ref().map(Into::into),
            flags: value.flags,
            exemplars: value.exemplars.iter().map(Into::into).collect(),
            max: value.max,
            min: value.min,
            zero_threshold: value.zero_threshold,
        }
    }
}

impl From<&otel_metrics::exponential_histogram_data_point::Buckets> for Buckets {
    fn from(value: &otel_metrics::exponential_histogram_data_point::Buckets) -> Self {
        Self {
            offset: value.offset,
            bucket_counts: value.bucket_counts.to_vec(),
        }
    }
}

impl From<otel_metrics::exemplar::Value> for Value {
    fn from(value: otel_metrics::exemplar::Value) -> Self {
        match value {
            otel_metrics::exemplar::Value::AsDouble(n) => Value::AsDouble(n),
            otel_metrics::exemplar::Value::AsInt(n) => Value::AsInt(n),
        }
    }
}

impl From<otel_metrics::number_data_point::Value> for Value {
    fn from(value: otel_metrics::number_data_point::Value) -> Self {
        match value {
            otel_metrics::number_data_point::Value::AsDouble(n) => Value::AsDouble(n),
            otel_metrics::number_data_point::Value::AsInt(n) => Value::AsInt(n),
        }
    }
}


================================================
FILE: fake-opentelemetry-collector/src/trace.rs
================================================
//! based on https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry-otlp/tests/smoke.rs
use crate::common::cnv_attributes;
use opentelemetry_proto::tonic::collector::trace::v1::{
    ExportTraceServiceRequest, ExportTraceServiceResponse, trace_service_server::TraceService,
};
use serde::Serialize;
use std::collections::BTreeMap;
use tokio::sync::mpsc;

use tracing::debug;

/// opentelemetry_proto::tonic::trace::v1::Span is no compatible with serde::Serialize
/// and to be able to test with insta,... it's needed (Debug is not enough to be able to filter unstable value,...)
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ExportedSpan {
    pub trace_id: String,
    pub span_id: String,
    pub trace_state: String,
    pub parent_span_id: String,
    pub name: String,
    pub kind: String, //SpanKind,
    pub start_time_unix_nano: u64,
    pub end_time_unix_nano: u64,
    pub attributes: BTreeMap<String, String>,
    pub dropped_attributes_count: u32,
    pub events: Vec<Event>,
    pub dropped_events_count: u32,
    pub links: Vec<Link>,
    pub dropped_links_count: u32,
    pub status: Option<Status>,
}

impl From<opentelemetry_proto::tonic::trace::v1::Span> for ExportedSpan {
    fn from(value: opentelemetry_proto::tonic::trace::v1::Span) -> Self {
        Self {
            trace_id: hex::encode(&value.trace_id),
            span_id: hex::encode(&value.span_id),
            trace_state: value.trace_state.clone(),
            parent_span_id: hex::encode(&value.parent_span_id),
            name: value.name.clone(),
            kind: value.kind().as_str_name().to_owned(),
            start_time_unix_nano: value.start_time_unix_nano,
            end_time_unix_nano: value.end_time_unix_nano,
            attributes: cnv_attributes(&value.attributes),
            dropped_attributes_count: value.dropped_attributes_count,
            events: value.events.iter().map(Event::from).collect(),
            dropped_events_count: value.dropped_events_count,
            links: value.links.iter().map(Link::from).collect(),
            dropped_links_count: value.dropped_links_count,
            status: value.status.map(Status::from),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Serialize)]
pub struct Status {
    pub message: String,
    pub code: String,
}

impl From<opentelemetry_proto::tonic::trace::v1::Status> for Status {
    fn from(value: opentelemetry_proto::tonic::trace::v1::Status) -> Self {
        Self {
            message: value.message.clone(),
            code: value.code().as_str_name().to_string(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Link {
    pub trace_id: String,
    pub span_id: String,
    pub trace_state: String,
    pub attributes: BTreeMap<String, String>,
    pub dropped_attributes_count: u32,
}

impl From<&opentelemetry_proto::tonic::trace::v1::span::Link> for Link {
    fn from(value: &opentelemetry_proto::tonic::trace::v1::span::Link) -> Self {
        Self {
            trace_id: hex::encode(&value.trace_id),
            span_id: hex::encode(&value.span_id),
            trace_state: value.trace_state.clone(),
            attributes: cnv_attributes(&value.attributes),
            dropped_attributes_count: value.dropped_attributes_count,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Event {
    pub time_unix_nano: u64,
    pub name: String,
    pub attributes: BTreeMap<String, String>,
    pub dropped_attributes_count: u32,
}

impl From<&opentelemetry_proto::tonic::trace::v1::span::Event> for Event {
    fn from(value: &opentelemetry_proto::tonic::trace::v1::span::Event) -> Self {
        Self {
            time_unix_nano: value.time_unix_nano,
            name: value.name.clone(),
            attributes: cnv_attributes(&value.attributes),
            dropped_attributes_count: value.dropped_attributes_count,
        }
    }
}

pub(crate) struct FakeTraceService {
    tx: mpsc::Sender<ExportedSpan>,
}

impl FakeTraceService {
    pub fn new(tx: mpsc::Sender<ExportedSpan>) -> Self {
        Self { tx }
    }
}

#[tonic::async_trait]
impl TraceService for FakeTraceService {
    async fn export(
        &self,
        request: tonic::Request<ExportTraceServiceRequest>,
    ) -> Result<tonic::Response<ExportTraceServiceResponse>, tonic::Status> {
        debug!("Sending request into channel...");
        let sender = self.tx.clone();
        for es in request
            .into_inner()
            .resource_spans
            .into_iter()
            .flat_map(|rs| rs.scope_spans)
            .flat_map(|ss| ss.spans)
            .map(ExportedSpan::from)
        {
            sender
                .send(es)
                .await
                .inspect_err(|e| eprintln!("failed to send to channel: {e}"))
                .map_err(|err| tonic::Status::from_error(Box::new(err)))?;
        }
        Ok(tonic::Response::new(ExportTraceServiceResponse {
            partial_success: None,
        }))
    }
}


================================================
FILE: fake-opentelemetry-collector/tests/demo_log.rs
================================================
use std::time::Duration;

use fake_opentelemetry_collector::{FakeCollectorServer, setup_logger_provider};
use opentelemetry::logs::{LogRecord, Logger, LoggerProvider, Severity};
use tracing::debug;

#[tokio::test(flavor = "multi_thread")]
async fn demo_fake_logger_and_collector() {
    debug!("Start the fake collector");
    let mut fake_collector = FakeCollectorServer::start()
        .await
        .expect("fake collector setup and started");

    debug!("Init the 'application' & logger provider");
    let logger_provider = setup_logger_provider(&fake_collector).await;
    let logger = logger_provider.logger("test");

    debug!("Run the 'application' & send log ...");
    let mut record = logger.create_log_record();
    record.set_body("This is information".into());
    record.set_severity_number(Severity::Info);
    record.set_severity_text("info");
    logger.emit(record);

    debug!("Shutdown the 'application' & logger provider");
    let _ = logger_provider.force_flush();
    logger_provider
        .shutdown()
        .expect("no error during shutdown");
    drop(logger_provider);

    debug!("Collect & check the logs");
    let otel_logs = fake_collector
        .exported_logs(1, Duration::from_millis(500))
        .await;

    insta::assert_yaml_snapshot!(otel_logs, {
        "[].trace_id" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(trace_id) = value.as_str());
            format!("[trace_id:lg{}]", trace_id.len())
        }),
        "[].span_id" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(span_id) = value.as_str());
            format!("[span_id:lg{}]", span_id.len())
        }),
        "[].observed_time_unix_nano" => "[timestamp]",
        "[].severity_number" => 9,
        "[].severity_text" => "info",
        "[].body" => "AnyValue { value: Some(StringValue(\"This is information\")) }",
    });
}


================================================
FILE: fake-opentelemetry-collector/tests/demo_metrics.rs
================================================
use fake_opentelemetry_collector::{FakeCollectorServer, setup_meter_provider};
use opentelemetry::{KeyValue, global};
use std::time::Duration;
use tracing::debug;

#[tokio::test(flavor = "multi_thread")]
async fn demo_fake_meter_and_collector() {
    debug!("Start the fake collector");
    let mut fake_collector = FakeCollectorServer::start()
        .await
        .expect("fake collector setup and started");

    debug!("Init the 'application' & meter provider");
    let meter_provider = setup_meter_provider(&fake_collector).await;
    global::set_meter_provider(meter_provider.clone());

    debug!("Run the 'application' & send metrics ...");
    let meter = global::meter("test");
    let attributes = &[KeyValue::new("foo", "bar")];

    let gauge = meter
        .f64_gauge("test_gauge")
        .with_description("A test gauge")
        .with_unit("km/s")
        .build();
    gauge.record(123.456, attributes);

    let up_down_counter = meter
        .i64_up_down_counter("test_updown_counter")
        .with_description("A test up-down-counter")
        .with_unit("m/s^2")
        .build();
    up_down_counter.add(-50, attributes);

    let counter = meter
        .u64_counter("test_counter")
        .with_description("A test counter")
        .with_unit("Jigawatts")
        .build();
    counter.add(25, attributes);

    let histogram = meter
        .u64_histogram("test_histogram")
        .with_description("A test histogram")
        .with_unit("ft/in^2")
        .build();
    histogram.record(10, attributes);
    histogram.record(13, attributes);

    debug!("Shutdown the 'application' & meter provider");
    meter_provider.shutdown().expect("no error during shutdown");
    drop(meter_provider);

    debug!("Collect & check the metrics");
    let otel_metrics = fake_collector
        .exported_metrics(1, Duration::from_millis(500))
        .await;

    insta::assert_yaml_snapshot!(otel_metrics, {
        // Validate gauge metric
        "[0].metrics[0].name" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(name) = value.as_str());
            assert_eq!(name, "test_gauge");
            name.to_string()
        }),
        "[0].metrics[0].description" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(desc) = value.as_str());
            assert_eq!(desc, "A test gauge");
            desc.to_string()
        }),
        "[0].metrics[0].unit" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(unit) = value.as_str());
            assert_eq!(unit, "km/s");
            unit.to_string()
        }),
        "[0].metrics[0].data.Gauge.data_points[0].value.AsDouble" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(val) = value.as_f64());
            assert!((val - 123.456).abs() < 0.001);
            format!("{val}")
        }),

        // Validate up-down counter
        "[0].metrics[1].name" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(name) = value.as_str());
            assert_eq!(name, "test_updown_counter");
            name.to_string()
        }),
        "[0].metrics[1].description" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(desc) = value.as_str());
            assert_eq!(desc, "A test up-down-counter");
            desc.to_string()
        }),
        "[0].metrics[1].unit" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(unit) = value.as_str());
            assert_eq!(unit, "m/s^2");
            unit.to_string()
        }),
        "[0].metrics[1].data.Sum.data_points[0].value.AsInt" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(val) = value.as_i64());
            assert_eq!(val, -50);
            format!("{val}")
        }),
        "[0].metrics[1].data.Sum.is_monotonic" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(monotonic) = value.as_bool());
            assert!(!monotonic);
            format!("{monotonic}")
        }),
        "[0].metrics[1].data.Sum.aggregation_temporality" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(temporality) = value.as_u64());
            assert_eq!(temporality, 2); // Cumulative
            format!("{temporality}")
        }),

        // Validate counter
        "[0].metrics[2].name" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(name) = value.as_str());
            assert_eq!(name, "test_counter");
            name.to_string()
        }),
        "[0].metrics[2].description" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(desc) = value.as_str());
            assert_eq!(desc, "A test counter");
            desc.to_string()
        }),
        "[0].metrics[2].unit" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(unit) = value.as_str());
            assert_eq!(unit, "Jigawatts");
            unit.to_string()
        }),
        "[0].metrics[2].data.Sum.data_points[0].value.AsInt" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(val) = value.as_i64());
            assert_eq!(val, 25);
            format!("{val}")
        }),
        "[0].metrics[2].data.Sum.is_monotonic" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(monotonic) = value.as_bool());
            assert!(monotonic);
            format!("{monotonic}")
        }),
        "[0].metrics[2].data.Sum.aggregation_temporality" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(temporality) = value.as_u64());
            assert_eq!(temporality, 2); // Cumulative
            format!("{temporality}")
        }),

        // Validate histogram
        "[0].metrics[3].name" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(name) = value.as_str());
            assert_eq!(name, "test_histogram");
            name.to_string()
        }),
        "[0].metrics[3].description" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(desc) = value.as_str());
            assert_eq!(desc, "A test histogram");
            desc.to_string()
        }),
        "[0].metrics[3].unit" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(unit) = value.as_str());
            assert_eq!(unit, "ft/in^2");
            unit.to_string()
        }),
        "[0].metrics[3].data.Histogram.data_points[0].count" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(count) = value.as_u64());
            assert_eq!(count, 2);
            format!("{count}")
        }),
        "[0].metrics[3].data.Histogram.data_points[0].sum" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(sum) = value.as_u64());
            assert_eq!(sum, 23); // 10 + 13
            format!("{sum}")
        }),
        "[0].metrics[3].data.Histogram.data_points[0].min" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(min) = value.as_u64());
            assert_eq!(min, 10);
            format!("{min}")
        }),
        "[0].metrics[3].data.Histogram.data_points[0].max" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(max) = value.as_u64());
            assert_eq!(max, 13);
            format!("{max}")
        }),
        "[0].metrics[3].data.Histogram.aggregation_temporality" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(temporality) = value.as_u64());
            assert_eq!(temporality, 2); // Cumulative
            format!("{temporality}")
        }),

        // Validate attributes for all metrics
        "[].metrics[].data.**.attributes.foo" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(attr_value) = value.as_str());
            assert!(attr_value.contains("bar"));
            "\"Some(AnyValue { value: Some(StringValue(\\\"bar\\\")) })\""
        }),

        // Redact timestamps
        "[].metrics[].data.**.start_time_unix_nano" => "[timestamp]",
        "[].metrics[].data.**.time_unix_nano" => "[timestamp]",
        "[].metrics[].data.**.exemplars[].time_unix_nano" => "[timestamp]",
    });
}


================================================
FILE: fake-opentelemetry-collector/tests/demo_trace.rs
================================================
use std::time::Duration;

use fake_opentelemetry_collector::{FakeCollectorServer, setup_tracer_provider};
use opentelemetry::trace::TracerProvider;
use opentelemetry::trace::{Span, SpanKind, Tracer};
use tracing::debug;

#[tokio::test(flavor = "multi_thread")]
async fn demo_fake_tracer_and_collector() {
    debug!("Start the fake collector");
    let mut fake_collector = FakeCollectorServer::start()
        .await
        .expect("fake collector setup and started");

    debug!("Init the 'application' & tracer provider");
    let tracer_provider = setup_tracer_provider(&fake_collector).await;
    let tracer = tracer_provider.tracer("test");

    debug!("Run the 'application' & sending span...");
    let mut span = tracer
        .span_builder("my-test-span")
        .with_kind(SpanKind::Server)
        .start(&tracer);
    span.add_event("my-test-event", vec![]);
    span.end();

    debug!("Shutdown the 'application' & tracer provider and force flush the spans");
    let _ = tracer_provider.force_flush();
    tracer_provider
        .shutdown()
        .expect("no error during shutdown");
    drop(tracer_provider);

    debug!("Collect & check the spans");
    let otel_spans = fake_collector
        .exported_spans(1, Duration::from_secs(20))
        .await;
    //insta::assert_debug_snapshot!(otel_spans);
    insta::assert_yaml_snapshot!(otel_spans, {
        "[].start_time_unix_nano" => "[timestamp]",
        "[].end_time_unix_nano" => "[timestamp]",
        "[].events[].time_unix_nano" => "[timestamp]",
        "[].trace_id" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(trace_id) = value.as_str());
            format!("[trace_id:lg{}]", trace_id.len())
        }),
        "[].span_id" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(span_id) = value.as_str());
            format!("[span_id:lg{}]", span_id.len())
        }),
        "[].links[].trace_id" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(trace_id) = value.as_str());
            format!("[trace_id:lg{}]", trace_id.len())
        }),
        "[].links[].span_id" => insta::dynamic_redaction(|value, _path| {
            assert2::assert!(let Some(span_id) = value.as_str());
            format!("[span_id:lg{}]", span_id.len())
        }),
    });
}


================================================
FILE: fake-opentelemetry-collector/tests/snapshots/demo_log__demo_fake_logger_and_collector.snap
================================================
---
source: fake-opentelemetry-collector/tests/demo_log.rs
expression: otel_logs
snapshot_kind: text
---
- trace_id: "[trace_id:lg0]"
  span_id: "[span_id:lg0]"
  observed_time_unix_nano: "[timestamp]"
  severity_number: 9
  severity_text: info
  body: "AnyValue { value: Some(StringValue(\"This is information\")) }"
  attributes: {}
  dropped_attributes_count: 0
  flags: 0


================================================
FILE: fake-opentelemetry-collector/tests/snapshots/demo_metrics__demo_fake_meter_and_collector.snap
================================================
---
source: fake-opentelemetry-collector/tests/demo_metrics.rs
expression: otel_metrics
---
- metrics:
    - name: test_gauge
      description: A test gauge
      unit: km/s
      data:
        Gauge:
          data_points:
            - attributes:
                foo: "\"Some(AnyValue { value: Some(StringValue(\\\"bar\\\")) })\""
              start_time_unix_nano: "[timestamp]"
              time_unix_nano: "[timestamp]"
              exemplars: []
              flags: 0
              value:
                AsDouble: 123.456
    - name: test_updown_counter
      description: A test up-down-counter
      unit: m/s^2
      data:
        Sum:
          data_points:
            - attributes:
                foo: "\"Some(AnyValue { value: Some(StringValue(\\\"bar\\\")) })\""
              start_time_unix_nano: "[timestamp]"
              time_unix_nano: "[timestamp]"
              exemplars: []
              flags: 0
              value:
                AsInt: -50
          aggregation_temporality: 2
          is_monotonic: false
    - name: test_counter
      description: A test counter
      unit: Jigawatts
      data:
        Sum:
          data_points:
            - attributes:
                foo: "\"Some(AnyValue { value: Some(StringValue(\\\"bar\\\")) })\""
              start_time_unix_nano: "[timestamp]"
              time_unix_nano: "[timestamp]"
              exemplars: []
              flags: 0
              value:
                AsInt: 25
          aggregation_temporality: 2
          is_monotonic: true
    - name: test_histogram
      description: A test histogram
      unit: ft/in^2
      data:
        Histogram:
          data_points:
            - attributes:
                foo: "\"Some(AnyValue { value: Some(StringValue(\\\"bar\\\")) })\""
              start_time_unix_nano: "[timestamp]"
              time_unix_nano: "[timestamp]"
              count: 2
              sum: 23
              bucket_counts:
                - 0
                - 0
                - 1
                - 1
                - 0
                - 0
                - 0
                - 0
                - 0
                - 0
                - 0
                - 0
                - 0
                - 0
                - 0
                - 0
              explicit_bounds:
                - 0
                - 5
                - 10
                - 25
                - 50
                - 75
                - 100
                - 250
                - 500
                - 750
                - 1000
                - 2500
                - 5000
                - 7500
                - 10000
              flags: 0
              min: 10
              max: 13
              exemplars: []
          aggregation_temporality: 2


================================================
FILE: fake-opentelemetry-collector/tests/snapshots/demo_trace__demo_fake_tracer_and_collector.snap
================================================
---
source: fake-opentelemetry-collector/tests/demo_trace.rs
expression: otel_spans
snapshot_kind: text
---
- trace_id: "[trace_id:lg32]"
  span_id: "[span_id:lg16]"
  trace_state: ""
  parent_span_id: ""
  name: my-test-span
  kind: SPAN_KIND_SERVER
  start_time_unix_nano: "[timestamp]"
  end_time_unix_nano: "[timestamp]"
  attributes: {}
  dropped_attributes_count: 0
  events:
    - time_unix_nano: "[timestamp]"
      name: my-test-event
      attributes: {}
      dropped_attributes_count: 0
  dropped_events_count: 0
  links: []
  dropped_links_count: 0
  status:
    message: ""
    code: STATUS_CODE_UNSET


================================================
FILE: init-tracing-opentelemetry/CHANGELOG.md
================================================
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.37.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.36.1...init-tracing-opentelemetry-v0.37.0) - 2026-04-27

### <!-- 1 -->Fixed

- *(init)* metrics enabled if feature flages & explicit enabling
- avoid to log sensitive OTEL value, and warn if issue on logfmt
- *(docs)* build of sample & add screenshot for log

### <!-- 2 -->Added

- accept owned string for service'name and version
- add OTLP log exporter ([#333](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/333))

## [0.37.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.36.1...init-tracing-opentelemetry-v0.37.0) - 2026-04-27

### <!-- 1 -->Fixed

- *(init)* metrics enabled if feature flages & explicit enabling
- avoid to log sensitive OTEL value, and warn if issue on logfmt
- *(docs)* build of sample & add screenshot for log

### <!-- 2 -->Added

- accept owned string for service'name and version
- add OTLP log exporter ([#333](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/333))

## [0.36.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.36.0...init-tracing-opentelemetry-v0.36.1) - 2026-03-15

### <!-- 1 -->Fixed

- MSRV (bump to 1.88) & api changes in dependencies, reformat ([#325](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/325))

## [0.36.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.36.0...init-tracing-opentelemetry-v0.36.1) - 2026-03-15

### <!-- 1 -->Fixed

- MSRV (bump to 1.88) & api changes in dependencies, reformat ([#325](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/325))

## [0.36.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/releases/tag/init-tracing-opentelemetry-v0.36.0) - 2026-01-19

### <!-- 2 -->Added

- *(deps)* update to rust 1.87 & edition 2024 ([#317](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/317))

## [0.36.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.35.0...init-tracing-opentelemetry-v0.36.0) - 2026-01-19

### <!-- 2 -->Added

- *(deps)* update to rust 1.87 & edition 2024 ([#317](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/317))

## [0.35.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.34.0...init-tracing-opentelemetry-v0.35.0) - 2026-01-12

### <!-- 2 -->Added

- allow to define otel tracer's name via `TracerConfig` ([#313](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/313))

## [0.34.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.33.0...init-tracing-opentelemetry-v0.34.0) - 2025-11-13

### <!-- 1 -->Fixed

- *(init-tracing-opentelemetry)* apply custom resource configuration to OpenTelemetry layers ([#297](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/297))
- Fix timers, booleans add support for `Layer::without_time` ([#295](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/295))

### <!-- 2 -->Added

- Add support for `Layer::with_thread_ids`
- Add support for `Layer::with_file`
- add support for `tracing_subscriber::fmt::format::Full` ([#291](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/291))
- add in features to docs.rs rendered content. ([#287](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/287))

## [0.33.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.32.1...init-tracing-opentelemetry-v0.33.0) - 2025-11-02

### <!-- 2 -->Added

- allow to customize the tracing configuration (registry) with additional layers ([#281](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/281))

## [0.31.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.30.1...init-tracing-opentelemetry-v0.31.0) - 2025-09-27

### <!-- 2 -->Added

- [**breaking**] Guard struct allow future evolution, init_subscriber can be used for non global (like test,...)
- a more configurable tracing configuration with `TracingConfig`

## [0.30.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.29.0...init-tracing-opentelemetry-v0.30.0) - 2025-07-18

### <!-- 2 -->Added

- add support for Opentelemetry Metrics (#249)

## [0.28.2](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.28.1...init-tracing-opentelemetry-v0.28.2) - 2025-06-03

### <!-- 1 -->Fixed

- *(deps)* missing `tonic` dependency on `tls`

### <!-- 3 -->Removed

- remove deprecated sample from README

## [0.28.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.27.1...init-tracing-opentelemetry-v0.28.0) - 2025-03-31

### <!-- 2 -->Added

- *(deps)* update opentelemetry to 0.29 (#227)

## [0.27.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.27.0...init-tracing-opentelemetry-v0.27.1) - 2025-02-26

### <!-- 1 -->Fixed

- reqwest must use blocking client since opentelemetry 0.28 (#220)

### <!-- 3 -->Removed

- *(deps)* remove minor constraint when major > 1

## [0.27.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.26.0...init-tracing-opentelemetry-v0.27.0) - 2025-02-24

### <!-- 1 -->Fixed

- drop on the TracingGuard also shutdown the wrapped TracerProvider

### <!-- 2 -->Added

- allow to provide log's "directives" via `init_subscribers_and_loglevel`

## [0.25.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.24.1...init-tracing-opentelemetry-v0.25.0) - 2024-12-10

### <!-- 1 -->Fixed

- inference of `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` for protocol `http/protobuf`

## [0.24.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.24.0...init-tracing-opentelemetry-v0.24.1) - 2024-11-24

### <!-- 1 -->Fixed

- Use guard pattern to allow consumers to ensure final trace is sent ([#185](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/185))

## [0.24.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.21.0...init-tracing-opentelemetry-v0.24.0) - 2024-09-23

### <!-- 2 -->Added

- [**breaking**] remove trace_id and span_id from logfmt (to avoid link with old version)

## [0.21.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.20.0...init-tracing-opentelemetry-v0.21.0) - 2024-09-22

### <!-- 2 -->Added

- *(deps)* upgrade to opentelemetry 0.25
- add a troubleshot section
- [**breaking**] disable resourcedetector (os,...) until update for new version of opentelemetry
- [**breaking**] disable support of xray (until update for new version of opentelemetry)

## [0.20.0](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.19.0...init-tracing-opentelemetry-v0.20.0) - 2024-08-31

### <!-- 1 -->Fixed
- 🐛 fix build of contributions (upgrade of opentelemetry, fake collector for logs,...)

### <!-- 4 -->Changed
- ⬆️ upgrade to rstest 0.22
- ⬆️ upgrade to opentelemetry 0.24 (and related dependencies) ([#151](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/pull/151))

## [0.17.1](https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/compare/init-tracing-opentelemetry-v0.17.0...init-tracing-opentelemetry-v0.17.1) - 2024-02-24

### Other
- 👷 tune release-plz


================================================
FILE: init-tracing-opentelemetry/Cargo.toml
================================================
[package]
name = "init-tracing-opentelemetry"
description = "A set of helpers to initialize (and more) tracing + opentelemetry (compose your own or use opinionated preset)"
readme = "README.md"
keywords = ["tracing", "opentelemetry"]
categories = ["development-tools::debugging", "development-tools::profiling"]
homepage = "https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk/tree/main/init-tracing-opentelemetry"
edition.workspace = true
version = "0.37.0"
repository.workspace = true
license.workspace = true

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docs_rs"]

[dependencies]
opentelemetry = { workspace = true }
opentelemetry-appender-tracing = { version = "0.31", default-features = false, optional = true }
opentelemetry-aws = { workspace = true, optional = true, features = ["trace"] }
opentelemetry-jaeger-propagator = { workspace = true, optional = true }
opentelemetry-otlp = { workspace = true, optional = true, features = [
  "grpc-tonic",
  "trace",
] }
# opentelemetry-resource-detectors = { workspace = true } //FIXME enable when available for opentelemetry >= 0.25
opentelemetry-stdout = { workspace = true, features = [
  "trace",
], optional = true }
opentelemetry-semantic-conventions = { workspace = true, optional = true }
opentelemetry-zipkin = { workspace = true, features = [], optional = true }
opentelemetry_sdk = { workspace = true, features = ["trace"] }
thiserror = "2"
tonic = { workspace = true, optional = true }
tracing = { workspace = true }
tracing-logfmt = { version = "0.3", optional = true }
tracing-opentelemetry = { workspace = true }
tracing-subscriber = { version = "0.3", default-features = false, features = [
  "ansi",
  "env-filter",
  "fmt",
  "json",
], optional = true }

[dev-dependencies]
assert2 = { workspace = true }
rstest = { workspace = true }
# need tokio runtime to run smoke tests and rust doc
tracing-opentelemetry-instrumentation-sdk = { path = "../tracing-opentelemetry-instrumentation-sdk" }
opentelemetry_sdk = { workspace = true, features = [
  "trace",
  "rt-tokio",
  "testing",
] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
tokio-blocked = "0.1"
tokio-stream = { version = "0.1" }
tracing-subscriber = { version = "0.3", default-features = false, features = [
  "env-filter",
  "fmt",
  "json",
] }

[features]
jaeger = ["dep:opentelemetry-jaeger-propagator"]
otlp = [
  "opentelemetry-otlp/http-proto",
  "opentelemetry-otlp/reqwest-blocking-client",
  "opentelemetry-otlp/reqwest-rustls",
  "tracer",
]
stdout = ["dep:opentelemetry-stdout", "tracer"]
tracer = ["dep:opentelemetry-semantic-conventions"]
xray = ["dep:opentelemetry-aws"]
zipkin = ["dep:opentelemetry-zipkin"]
tracing_subscriber_ext = ["dep:tracing-subscriber", "otlp"]
tls = ["opentelemetry-otlp/tls", "tonic"]
tls-roots = ["opentelemetry-otlp/tls-roots"]
tls-webpki-roots = ["opentelemetry-otlp/tls-webpki-roots"]
logfmt = ["dep:tracing-logfmt"]
logs = [
  "dep:opentelemetry-appender-tracing",
  "opentelemetry-otlp/logs",
  "opentelemetry_sdk/logs",
  "opentelemetry/logs",
]
metrics = [
  "opentelemetry-otlp/metrics",
  "tracing-opentelemetry/metrics",
  "opentelemetry-stdout/metrics",
]

[lints]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(docs_rs)'] }


================================================
FILE: init-tracing-opentelemetry/README.md
================================================
# init-tracing-opentelemetry

[![crates license](https://img.shields.io/crates/l/init-tracing-opentelemetry.svg)](http://creativecommons.org/publicdomain/zero/1.0/)
[![crate version](https://img.shields.io/crates/v/init-tracing-opentelemetry.svg)](https://crates.io/crates/init-tracing-opentelemetry)

A set of helpers to initialize (and more) tracing + opentelemetry (compose your own or use opinionated preset)

```rust
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Simple preset
    let _guard = init_tracing_opentelemetry::TracingConfig::production().init_subscriber()?;

    //...

    Ok(())
}
```

```rust
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // custom configuration
    let _guard = init_tracing_opentelemetry::TracingConfig::default()
        .with_json_format()
        .with_stderr()
        .with_log_directives("debug")
        .init_subscriber()?;

    //...

    Ok(())
}
```

The `init_subscriber()` function returns an `OtelGuard` instance. Following the guard pattern, this struct provides no functions but, when dropped, ensures that any pending traces/metrics are sent before it exits. The syntax `let _guard` is suggested to ensure that Rust does not drop the struct until the application exits.

## Configuration Options

### Presets

- `TracingConfig::development()` - Pretty format, stderr, with debug info
- `TracingConfig::production()` - JSON format, stdout, minimal metadata
- `TracingConfig::debug()` - Full verbosity with all span events
- `TracingConfig::minimal()` - Compact format, no OpenTelemetry
- `TracingConfig::testing()` - Minimal output for tests

### Custom Configuration

```rust,no_run
use init_tracing_opentelemetry::TracingConfig;

TracingConfig::default()
    .with_pretty_format()           // or .with_json_format(), .with_compact_format()
    .with_stderr()                  // or .with_stdout(), .with_file(path)
    .with_log_directives("debug")   // Custom log levels
    .with_line_numbers(true)        // Include line numbers
    .with_thread_names(true)        // Include thread names
    .with_otel(true)                // Enable OpenTelemetry
    .init_subscriber()
    .expect("valid tracing configuration");
```

### Add custom layer, modify subscriber

Use `init_subscriber_ext(|subscriber| {...} )` to transform the subscriber (registry), before application of the configuration.

```rust
use init_tracing_opentelemetry::TracingConfig;
use tokio_blocked::TokioBlockedLayer;
use tracing::info;
use tracing_subscriber::layer::SubscriberExt;

#[tokio::main]
async fn main() {
    let blocked = TokioBlockedLayer::new()
        .with_warn_busy_single_poll(Some(std::time::Duration::from_micros(150)));

    let _guard = TracingConfig::default()
        .with_log_directives("info,tokio::task=trace,tokio::task::waker=warn")
        .with_span_events(tracing_subscriber::fmt::format::FmtSpan::NONE)
        .init_subscriber_ext(|subscriber| subscriber.with(blocked))
        .unwrap();

    tokio::task::spawn(async {
        // BAD!
        // This produces a warning log message.
        info!("blocking!");
        std::thread::sleep(std::time::Duration::from_secs(1));
    })
    .await
    .unwrap();

    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
}
```

### Legacy API (deprecated)

For backward compatibility, the old API is still available:

```txt
pub fn build_loglevel_filter_layer() -> tracing_subscriber::filter::EnvFilter {
    // filter what is output on log (fmt)
    // std::env::set_var("RUST_LOG", "warn,axum_tracing_opentelemetry=info,otel=debug");
    std::env::set_var(
        "RUST_LOG",
        format!(
            // `otel::tracing` should be a level trace to emit opentelemetry trace & span
            // `otel::setup` set to debug to log detected resources, configuration read and infered
            "{},otel::tracing=trace,otel=debug",
            std::env::var("RUST_LOG")
                .or_else(|_| std::env::var("OTEL_LOG_LEVEL"))
                .unwrap_or_else(|_| "info".to_string())
        ),
    );
    EnvFilter::from_default_env()
}

pub fn build_otel_layer<S>() -> Result<OpenTelemetryLayer<S, Tracer>, BoxError>
where
    S: Subscriber + for<'a> LookupSpan<'a>,
{
    use crate::{
        init_propagator, //stdio,
        otlp,
        resource::DetectResource,
    };
    let otel_rsrc = DetectResource::default()
        //.with_fallback_service_name(env!("CARGO_PKG_NAME"))
        //.with_fallback_service_version(env!("CARGO_PKG_VERSION"))
        .build();
    let otel_tracer = otlp::init_tracer(otel_rsrc, otlp::identity)?;
    // to not send trace somewhere, but continue to create and propagate,...
    // then send them to `axum_tracing_opentelemetry::stdio::WriteNoWhere::default()`
    // or to `std::io::stdout()` to print
    //
    // let otel_tracer =
    //     stdio::init_tracer(otel_rsrc, stdio::identity, stdio::WriteNoWhere::default())?;
    init_propagator()?;
    Ok(tracing_opentelemetry::layer().with_tracer(otel_tracer))
}
```

To retrieve the current `trace_id` (eg to add it into error message (as header or attributes))

```rust
  # use tracing_opentelemetry_instrumentation_sdk;

  let trace_id = tracing_opentelemetry_instrumentation_sdk::find_current_trace_id();
  //json!({ "error" :  "xxxxxx", "trace_id": trace_id})
```

## Configuration based on the environment variables

To ease setup and compliance with [OpenTelemetry SDK configuration](https://opentelemetry.io/docs/concepts/sdk-configuration/general-sdk-configuration/), the configuration can be done with the following environment variables (see sample `init_tracing()` above):

- `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` fallback to `OTEL_EXPORTER_OTLP_ENDPOINT` for the url of the exporter / collector
- `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` fallback to `OTEL_EXPORTER_OTLP_PROTOCOL`, fallback to auto-detection based on ENDPOINT port
- `OTEL_SERVICE_NAME` for the name of the service
- `OTEL_PROPAGATORS` for the configuration of the propagators
- `OTEL_TRACES_SAMPLER` & `OTEL_TRACES_SAMPLER_ARG` for configuration of the sampler

Few other environment variables can also be used to configure OTLP exporter (eg to configure headers, authentication,, etc...):

- [`OTEL_EXPORTER_OTLP_HEADERS`](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/#otel_exporter_otlp_headers)
- [`OTEL_EXPORTER_OTLP_TRACES_HEADERS`](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/#otel_exporter_otlp_traces_headers)

```sh
# For GRPC:
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://localhost:4317"
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL="grpc"
export OTEL_TRACES_SAMPLER="always_on"

# For HTTP:
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://127.0.0.1:4318/v1/traces"
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL="http/protobuf"
export OTEL_TRACES_SAMPLER="always_on"
```

In the context of **kubernetes**, some of the above environment variables can be injected by the Opentelemetry operator (via `inject-sdk`):

```yaml
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    metadata:
      annotations:
        # to inject environment variables only by opentelemetry-operator
        instrumentation.opentelemetry.io/inject-sdk: "opentelemetry-operator/instrumentation"
        instrumentation.opentelemetry.io/container-names: "app"
      containers:
        - name: app
```

Or if you don't setup `inject-sdk`, you can manually set the environment variable eg

```yaml
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    metadata:
      containers:
        - name: app
          env:
            - name: OTEL_SERVICE_NAME
              value: "app"
            - name: OTEL_EXPORTER_OTLP_PROTOCOL
              value: "grpc"
            # for otel collector in `deployment` mode, use the name of the service
            # - name: OTEL_EXPORTER_OTLP_ENDPOINT
            #   value: "http://opentelemetry-collector.opentelemetry-collector:4317"
            # for otel collector in sidecar mode (imply to deploy a sidecar CR per namespace)
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: "http://localhost:4317"
            # for `daemonset` mode: need to use the local daemonset (value interpolated by k8s: `$(...)`)
            # - name: OTEL_EXPORTER_OTLP_ENDPOINT
            #   value: "http://$(HOST_IP):4317"
            # - name: HOST_IP
            #   valueFrom:
            #     fieldRef:
            #       fieldPath: status.hostIP
```

## Troubleshot why no trace?

- check you only have a single version of opentelemtry (could be part of your CI/build), use `cargo-deny` or `cargo tree`

  ```sh
  # Check only one version of opentelemetry should be used
  # else issue with setup of global (static variable)
  # check_single_version_opentelemtry:
  cargo tree -i opentelemetry
  ```

- check the code of your exporter and the integration with `tracing` (as subscriber's layer)
- check the environment variables of opentelemetry `OTEL_EXPORTER...` and `OTEL_TRACES_SAMPLER` (values are logged on target `otel::setup` )
- check that log target `otel::tracing` enable log level `trace` (or `info` if you use `tracing_level_info` feature) to generate span to send to opentelemetry collector.

## Metrics

To configure opentelemetry metrics, enable the `metrics` feature, this will initialize a `SdkMeterProvider`, set it globally and add a a [`MetricsLayer`](https://docs.rs/tracing-opentelemetry/latest/tracing_opentelemetry/struct.MetricsLayer.html) to allow using `tracing` events to produce metrics.

The `opentelemetry_sdk` can still be used to produce metrics as well, since we
Download .txt
gitextract_m0cxzsml/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── ci.yml
│       ├── mega-linter.yml
│       └── release-plz.yml
├── .gitignore
├── .mega-linter.yml
├── .mise.toml
├── .vscode/
│   └── settings.json
├── .yamllint.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Cargo.toml
├── LICENSE
├── README.md
├── axum-tracing-opentelemetry/
│   ├── CHANGELOG.md
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── lib.rs
│       └── middleware/
│           ├── mod.rs
│           ├── response_injector.rs
│           └── trace_extractor.rs
├── cliff.toml
├── deny.toml
├── examples/
│   ├── axum-otlp/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── main.rs
│   ├── bug_234_tls/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── main.rs
│   ├── grpc/
│   │   ├── Cargo.toml
│   │   ├── build.rs
│   │   ├── proto/
│   │   │   └── helloworld.proto
│   │   └── src/
│   │       ├── client.rs
│   │       ├── generated/
│   │       │   └── helloworld.rs
│   │       └── server.rs
│   ├── init-tracing-with/
│   │   ├── .cargo/
│   │   │   └── config.toml
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── main.rs
│   ├── load/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── main.rs
│   └── logging/
│       ├── Cargo.toml
│       └── src/
│           └── main.rs
├── fake-opentelemetry-collector/
│   ├── CHANGELOG.md
│   ├── Cargo.toml
│   ├── README.md
│   ├── src/
│   │   ├── common.rs
│   │   ├── lib.rs
│   │   ├── logs.rs
│   │   ├── metrics.rs
│   │   └── trace.rs
│   └── tests/
│       ├── demo_log.rs
│       ├── demo_metrics.rs
│       ├── demo_trace.rs
│       └── snapshots/
│           ├── demo_log__demo_fake_logger_and_collector.snap
│           ├── demo_metrics__demo_fake_meter_and_collector.snap
│           └── demo_trace__demo_fake_tracer_and_collector.snap
├── init-tracing-opentelemetry/
│   ├── CHANGELOG.md
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── config.rs
│       ├── error.rs
│       ├── formats.rs
│       ├── lib.rs
│       ├── otlp/
│       │   ├── logs.rs
│       │   ├── metrics.rs
│       │   ├── mod.rs
│       │   └── traces.rs
│       ├── resource.rs
│       ├── stdio.rs
│       └── tracing_subscriber_ext.rs
├── release-plz.toml
├── renovate.json5
├── rust-toolchain.toml
├── testing-tracing-opentelemetry/
│   ├── Cargo.toml
│   └── src/
│       ├── lib.rs
│       └── snapshots/
│           ├── testing_tracing_opentelemetry__call_with_w3c_trace.snap
│           ├── testing_tracing_opentelemetry__call_with_w3c_trace_otel_spans.snap
│           ├── testing_tracing_opentelemetry__empty_http_route_for_nonexisting_route.snap
│           ├── testing_tracing_opentelemetry__empty_http_route_for_nonexisting_route_otel_spans.snap
│           ├── testing_tracing_opentelemetry__extract_route_from_nested.snap
│           ├── testing_tracing_opentelemetry__extract_route_from_nested_otel_spans.snap
│           ├── testing_tracing_opentelemetry__filled_http_headers.snap
│           ├── testing_tracing_opentelemetry__filled_http_headers_otel_spans.snap
│           ├── testing_tracing_opentelemetry__filled_http_route_for_existing_route.snap
│           ├── testing_tracing_opentelemetry__filled_http_route_for_existing_route_otel_spans.snap
│           ├── testing_tracing_opentelemetry__status_code_on_close_for_error.snap
│           ├── testing_tracing_opentelemetry__status_code_on_close_for_error_otel_spans.snap
│           ├── testing_tracing_opentelemetry__status_code_on_close_for_ok.snap
│           ├── testing_tracing_opentelemetry__status_code_on_close_for_ok_otel_spans.snap
│           ├── testing_tracing_opentelemetry__trace_id_in_child_span.snap
│           ├── testing_tracing_opentelemetry__trace_id_in_child_span_for_remote.snap
│           ├── testing_tracing_opentelemetry__trace_id_in_child_span_for_remote_otel_spans.snap
│           └── testing_tracing_opentelemetry__trace_id_in_child_span_otel_spans.snap
├── tonic-tracing-opentelemetry/
│   ├── CHANGELOG.md
│   ├── Cargo.toml
│   ├── README.md
│   └── src/
│       ├── lib.rs
│       └── middleware/
│           ├── client.rs
│           ├── filters.rs
│           ├── mod.rs
│           └── server.rs
└── tracing-opentelemetry-instrumentation-sdk/
    ├── CHANGELOG.md
    ├── Cargo.toml
    ├── README.md
    └── src/
        ├── http/
        │   ├── grpc.rs
        │   ├── grpc_client.rs
        │   ├── grpc_server.rs
        │   ├── http_server.rs
        │   ├── mod.rs
        │   ├── opentelemetry_http.rs
        │   └── tools.rs
        ├── lib.rs
        └── span_type.rs
Download .txt
SYMBOL INDEX (358 symbols across 42 files)

FILE: axum-tracing-opentelemetry/src/middleware/response_injector.rs
  function response_with_trace_layer (line 13) | pub fn response_with_trace_layer() -> OtelInResponseLayer {
  type OtelInResponseLayer (line 18) | pub struct OtelInResponseLayer;
    type Service (line 21) | type Service = OtelInResponseService<S>;
    method layer (line 23) | fn layer(&self, inner: S) -> Self::Service {
  type OtelInResponseService (line 29) | pub struct OtelInResponseService<S> {
  type Response (line 38) | type Response = S::Response;
  type Error (line 39) | type Error = S::Error;
  type Future (line 41) | type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
  function poll_ready (line 43) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::...
  function call (line 48) | fn call(&mut self, mut request: Request<B>) -> Self::Future {

FILE: axum-tracing-opentelemetry/src/middleware/trace_extractor.rs
  function opentelemetry_tracing_layer (line 57) | pub fn opentelemetry_tracing_layer() -> OtelAxumLayer {
  type Filter (line 61) | pub type Filter = fn(&str) -> bool;
  type OtelAxumLayer (line 70) | pub struct OtelAxumLayer {
    method filter (line 78) | pub fn filter(self, filter: Filter) -> Self {
    method try_extract_client_ip (line 97) | pub fn try_extract_client_ip(self, enable: bool) -> Self {
    type Service (line 106) | type Service = OtelAxumService<S>;
    method layer (line 107) | fn layer(&self, inner: S) -> Self::Service {
  type OtelAxumService (line 117) | pub struct OtelAxumService<S> {
  type Response (line 130) | type Response = S::Response;
  type Error (line 131) | type Error = S::Error;
  type Future (line 134) | type Future = ResponseFuture<S::Future>;
    type Output (line 199) | type Output = Result<Response<ResBody>, E>;
    method poll (line 201) | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Outp...
  function poll_ready (line 136) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::...
  function call (line 140) | fn call(&mut self, req: Request<B>) -> Self::Future {
  function http_route (line 211) | fn http_route<B>(req: &Request<B>) -> &str {
  function check_span_event (line 240) | async fn check_span_event(

FILE: examples/axum-otlp/src/main.rs
  function main (line 12) | async fn main() -> Result<(), BoxError> {
  function app (line 27) | fn app() -> Router {
  function health (line 42) | async fn health() -> impl IntoResponse {
  function index (line 47) | async fn index() -> impl IntoResponse {
  function sleep_10ms (line 59) | async fn sleep_10ms() {
  function proxy_handler (line 63) | async fn proxy_handler(Path((service, path)): Path<(String, String)>) ->...

FILE: examples/bug_234_tls/src/main.rs
  function main (line 4) | async fn main() {
  function handler (line 16) | async fn handler() -> Html<&'static str> {

FILE: examples/grpc/build.rs
  function main (line 3) | fn main() {

FILE: examples/grpc/src/client.rs
  function main (line 14) | async fn main() -> Result<(), Box<dyn std::error::Error>> {

FILE: examples/grpc/src/generated/helloworld.rs
  type HelloRequest (line 3) | pub struct HelloRequest {
  type HelloReply (line 8) | pub struct HelloReply {
  type StatusRequest (line 13) | pub struct StatusRequest {
  type GreeterClient (line 32) | pub struct GreeterClient<T> {
  function connect (line 37) | pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
  function new (line 53) | pub fn new(inner: T) -> Self {
  function with_origin (line 57) | pub fn with_origin(inner: T, origin: Uri) -> Self {
  function with_interceptor (line 61) | pub fn with_interceptor<F>(
  function send_compressed (line 85) | pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
  function accept_compressed (line 91) | pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
  function max_decoding_message_size (line 99) | pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
  function max_encoding_message_size (line 107) | pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
  function say_hello (line 111) | pub async fn say_hello(
  function say_status (line 132) | pub async fn say_status(
  type Greeter (line 167) | pub trait Greeter: std::marker::Send + std::marker::Sync + 'static {
    method say_hello (line 168) | async fn say_hello(
    method say_status (line 172) | async fn say_status(
  type GreeterServer (line 178) | pub struct GreeterServer<T> {
  function new (line 186) | pub fn new(inner: T) -> Self {
  function from_arc (line 189) | pub fn from_arc(inner: Arc<T>) -> Self {
  function with_interceptor (line 198) | pub fn with_interceptor<F>(
  function accept_compressed (line 209) | pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
  function send_compressed (line 215) | pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
  function max_decoding_message_size (line 223) | pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
  function max_encoding_message_size (line 231) | pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
  type Response (line 242) | type Response = http::Response<tonic::body::Body>;
  type Error (line 243) | type Error = std::convert::Infallible;
  type Future (line 244) | type Future = BoxFuture<Self::Response, Self::Error>;
  function poll_ready (line 245) | fn poll_ready(
  function call (line 251) | fn call(&mut self, req: http::Request<B>) -> Self::Future {
  method clone (line 362) | fn clone(&self) -> Self {
  constant SERVICE_NAME (line 374) | pub const SERVICE_NAME: &str = "helloworld.Greeter";
  constant NAME (line 376) | const NAME: &'static str = SERVICE_NAME;

FILE: examples/grpc/src/server.rs
  constant FILE_DESCRIPTOR_SET (line 11) | pub(crate) const FILE_DESCRIPTOR_SET: &[u8] =
  type MyGreeter (line 17) | pub struct MyGreeter {}
  method say_hello (line 22) | async fn say_hello(
  method say_status (line 40) | async fn say_status(&self, request: Request<StatusRequest>) -> Result<Re...
  function main (line 49) | async fn main() -> Result<(), Box<dyn std::error::Error>> {

FILE: examples/init-tracing-with/src/main.rs
  function main (line 7) | async fn main() {

FILE: examples/load/src/main.rs
  function main (line 8) | async fn main() -> Result<(), Box<dyn std::error::Error>> {

FILE: examples/logging/src/main.rs
  function log (line 2) | async fn log() {
  function calc (line 11) | async fn calc(a: i32, b: i32) {
  function main (line 17) | async fn main() -> Result<(), Box<dyn std::error::Error>> {

FILE: fake-opentelemetry-collector/src/common.rs
  function cnv_attributes (line 3) | pub(crate) fn cnv_attributes(

FILE: fake-opentelemetry-collector/src/lib.rs
  type FakeCollectorServer (line 27) | pub struct FakeCollectorServer {
    method start (line 36) | pub async fn start() -> Result<Self, Box<dyn std::error::Error>> {
    method address (line 73) | pub fn address(&self) -> SocketAddr {
    method endpoint (line 77) | pub fn endpoint(&self) -> String {
    method exported_spans (line 81) | pub async fn exported_spans(
    method exported_logs (line 89) | pub async fn exported_logs(&mut self, at_least: usize, timeout: Durati...
    method exported_metrics (line 93) | pub async fn exported_metrics(
    method abort (line 101) | pub fn abort(self) {
  function recv_many (line 106) | async fn recv_many<T>(rx: &mut Receiver<T>, at_least: usize, timeout: Du...
  function setup_tracer_provider (line 115) | pub async fn setup_tracer_provider(
  function setup_logger_provider (line 139) | pub async fn setup_logger_provider(
  function setup_meter_provider (line 154) | pub async fn setup_meter_provider(

FILE: fake-opentelemetry-collector/src/logs.rs
  type ExportedLog (line 11) | pub struct ExportedLog {
    method from (line 24) | fn from(value: opentelemetry_proto::tonic::logs::v1::LogRecord) -> Self {
  type FakeLogsService (line 39) | pub(crate) struct FakeLogsService {
    method new (line 44) | pub fn new(tx: mpsc::Sender<ExportedLog>) -> Self {
  method export (line 51) | async fn export(

FILE: fake-opentelemetry-collector/src/metrics.rs
  type FakeMetricsService (line 13) | pub(crate) struct FakeMetricsService {
    method new (line 18) | pub fn new(tx: mpsc::Sender<ExportedMetric>) -> Self {
  method export (line 25) | async fn export(
  type ExportedMetric (line 51) | pub struct ExportedMetric {
    method from (line 183) | fn from(value: otel_metrics::ScopeMetrics) -> Self {
  type Metric (line 56) | pub struct Metric {
  type MetricsData (line 64) | pub enum MetricsData {
    method from (line 200) | fn from(value: otel_metrics::metric::Data) -> Self {
  type Gauge (line 73) | pub struct Gauge {
    method from (line 250) | fn from(value: otel_metrics::Gauge) -> Self {
  type Sum (line 78) | pub struct Sum {
    method from (line 240) | fn from(value: otel_metrics::Sum) -> Self {
  type Histogram (line 85) | pub struct Histogram {
    method from (line 231) | fn from(value: otel_metrics::Histogram) -> Self {
  type ExponentialHistogram (line 91) | pub struct ExponentialHistogram {
    method from (line 222) | fn from(value: otel_metrics::ExponentialHistogram) -> Self {
  type Summary (line 97) | pub struct Summary {
    method from (line 214) | fn from(value: otel_metrics::Summary) -> Self {
  type NumberDataPoint (line 102) | pub struct NumberDataPoint {
    method from (line 258) | fn from(value: &otel_metrics::NumberDataPoint) -> Self {
  type HistogramDataPoint (line 112) | pub struct HistogramDataPoint {
    method from (line 306) | fn from(value: &otel_metrics::HistogramDataPoint) -> Self {
  type ExponentialHistogramDataPoint (line 127) | pub struct ExponentialHistogramDataPoint {
    method from (line 324) | fn from(value: &otel_metrics::ExponentialHistogramDataPoint) -> Self {
  type Buckets (line 145) | pub struct Buckets {
    method from (line 345) | fn from(value: &otel_metrics::exponential_histogram_data_point::Bucket...
  type SummaryDataPoint (line 151) | pub struct SummaryDataPoint {
    method from (line 283) | fn from(value: &otel_metrics::SummaryDataPoint) -> Self {
  type ValueAtQuantile (line 162) | pub struct ValueAtQuantile {
    method from (line 297) | fn from(value: &otel_metrics::summary_data_point::ValueAtQuantile) -> ...
  type Exemplar (line 168) | pub struct Exemplar {
    method from (line 271) | fn from(value: &otel_metrics::Exemplar) -> Self {
  type Value (line 177) | pub enum Value {
    method from (line 354) | fn from(value: otel_metrics::exemplar::Value) -> Self {
    method from (line 363) | fn from(value: otel_metrics::number_data_point::Value) -> Self {

FILE: fake-opentelemetry-collector/src/trace.rs
  type ExportedSpan (line 15) | pub struct ExportedSpan {
    method from (line 34) | fn from(value: opentelemetry_proto::tonic::trace::v1::Span) -> Self {
  type Status (line 56) | pub struct Status {
    method from (line 62) | fn from(value: opentelemetry_proto::tonic::trace::v1::Status) -> Self {
  type Link (line 71) | pub struct Link {
    method from (line 80) | fn from(value: &opentelemetry_proto::tonic::trace::v1::span::Link) -> ...
  type Event (line 92) | pub struct Event {
    method from (line 100) | fn from(value: &opentelemetry_proto::tonic::trace::v1::span::Event) ->...
  type FakeTraceService (line 110) | pub(crate) struct FakeTraceService {
    method new (line 115) | pub fn new(tx: mpsc::Sender<ExportedSpan>) -> Self {
  method export (line 122) | async fn export(

FILE: fake-opentelemetry-collector/tests/demo_log.rs
  function demo_fake_logger_and_collector (line 8) | async fn demo_fake_logger_and_collector() {

FILE: fake-opentelemetry-collector/tests/demo_metrics.rs
  function demo_fake_meter_and_collector (line 7) | async fn demo_fake_meter_and_collector() {

FILE: fake-opentelemetry-collector/tests/demo_trace.rs
  function demo_fake_tracer_and_collector (line 9) | async fn demo_fake_tracer_and_collector() {

FILE: init-tracing-opentelemetry/src/config.rs
  type Guard (line 70) | pub struct Guard {
    method global (line 82) | pub fn global(otel_guard: Option<OtelGuard>) -> Self {
    method non_global (line 90) | pub fn non_global(
    method otel_guard (line 102) | pub fn otel_guard(&self) -> Option<&OtelGuard> {
    method has_otel (line 108) | pub fn has_otel(&self) -> bool {
    method is_non_global (line 114) | pub fn is_non_global(&self) -> bool {
    method is_global (line 120) | pub fn is_global(&self) -> bool {
  type LogFormat (line 127) | pub enum LogFormat {
  method default (line 142) | fn default() -> Self {
  type LogTimer (line 152) | pub enum LogTimer {
  method default (line 159) | fn default() -> Self {
  type WriterConfig (line 170) | pub enum WriterConfig {
  type LevelConfig (line 182) | pub struct LevelConfig {
  method default (line 194) | fn default() -> Self {
  type FeatureSet (line 207) | pub struct FeatureSet {
  method default (line 225) | fn default() -> Self {
  type OtelConfig (line 244) | pub struct OtelConfig {
  method default (line 256) | fn default() -> Self {
  type TracingConfig (line 269) | pub struct TracingConfig {
    method with_format (line 305) | pub fn with_format(mut self, format: LogFormat) -> Self {
    method with_pretty_format (line 312) | pub fn with_pretty_format(self) -> Self {
    method with_json_format (line 318) | pub fn with_json_format(self) -> Self {
    method with_full_format (line 324) | pub fn with_full_format(self) -> Self {
    method with_compact_format (line 330) | pub fn with_compact_format(self) -> Self {
    method with_logfmt_format (line 337) | pub fn with_logfmt_format(self) -> Self {
    method with_writer (line 345) | pub fn with_writer(mut self, writer: WriterConfig) -> Self {
    method with_stdout (line 352) | pub fn with_stdout(self) -> Self {
    method with_stderr (line 358) | pub fn with_stderr(self) -> Self {
    method with_file (line 364) | pub fn with_file<P: AsRef<Path>>(self, path: P) -> Self {
    method with_log_directives (line 373) | pub fn with_log_directives(mut self, directives: impl Into<String>) ->...
    method with_default_level (line 380) | pub fn with_default_level(mut self, level: LevelFilter) -> Self {
    method with_env_fallback (line 387) | pub fn with_env_fallback(mut self, env_var: impl Into<String>) -> Self {
    method with_otel_trace_level (line 394) | pub fn with_otel_trace_level(mut self, level: LevelFilter) -> Self {
    method with_otel_tracer_name (line 401) | pub fn with_otel_tracer_name(mut self, name: impl Into<String>) -> Self {
    method with_file_names (line 410) | pub fn with_file_names(mut self, enabled: bool) -> Self {
    method with_line_numbers (line 417) | pub fn with_line_numbers(mut self, enabled: bool) -> Self {
    method with_thread_names (line 424) | pub fn with_thread_names(mut self, enabled: bool) -> Self {
    method with_thread_ids (line 431) | pub fn with_thread_ids(mut self, enabled: bool) -> Self {
    method with_span_events (line 438) | pub fn with_span_events(mut self, events: FmtSpan) -> Self {
    method without_span_events (line 445) | pub fn without_span_events(mut self) -> Self {
    method with_uptime_timer (line 453) | pub fn with_uptime_timer(mut self, enabled: bool) -> Self {
    method with_timer (line 464) | pub fn with_timer(mut self, timer: LogTimer) -> Self {
    method with_target_display (line 471) | pub fn with_target_display(mut self, enabled: bool) -> Self {
    method with_otel (line 480) | pub fn with_otel(mut self, enabled: bool) -> Self {
    method with_logs (line 487) | pub fn with_logs(mut self, enabled: bool) -> Self {
    method with_metrics (line 494) | pub fn with_metrics(mut self, enabled: bool) -> Self {
    method with_resource_config (line 501) | pub fn with_resource_config(mut self, config: DetectResource) -> Self {
    method with_global_subscriber (line 512) | pub fn with_global_subscriber(mut self, global: bool) -> Self {
    method build_layer (line 520) | pub fn build_layer<S>(&self) -> Result<Box<dyn Layer<S> + Send + Sync ...
    method build_filter_layer (line 535) | pub fn build_filter_layer(&self) -> Result<EnvFilter, Error> {
    method init_subscriber (line 569) | pub fn init_subscriber(self) -> Result<Guard, Error> {
    method transform_identity (line 573) | fn transform_identity(s: Registry) -> Registry {
    method init_subscriber_ext (line 585) | pub fn init_subscriber_ext<F, SOut>(self, transform: F) -> Result<Guar...
    method register_otel_layers_with_resource (line 628) | fn register_otel_layers_with_resource<S>(
    method development (line 673) | pub fn development() -> Self {
    method production (line 690) | pub fn production() -> Self {
    method debug (line 708) | pub fn debug() -> Self {
    method minimal (line 721) | pub fn minimal() -> Self {
    method testing (line 739) | pub fn testing() -> Self {
  method default (line 287) | fn default() -> Self {
  function test_global_subscriber_true_returns_global_guard (line 756) | fn test_global_subscriber_true_returns_global_guard() {
  function test_global_subscriber_false_sets_config (line 767) | fn test_global_subscriber_false_sets_config() {
  function test_default_global_subscriber_is_true (line 776) | fn test_default_global_subscriber_is_true() {
  function test_init_subscriber_without_otel_succeeds (line 782) | fn test_init_subscriber_without_otel_succeeds() {
  function test_init_subscriber_with_otel_disabled_global (line 798) | fn test_init_subscriber_with_otel_disabled_global() {
  function test_init_subscriber_with_otel_disabled_non_global (line 815) | fn test_init_subscriber_with_otel_disabled_non_global() {
  function test_guard_helper_methods (line 832) | fn test_guard_helper_methods() {
  function test_guard_struct_direct_field_access (line 847) | fn test_guard_struct_direct_field_access() {
  function test_guard_struct_extensibility (line 861) | fn test_guard_struct_extensibility() {
  function test_init_with_transform (line 875) | async fn test_init_with_transform() {

FILE: init-tracing-opentelemetry/src/error.rs
  type Error (line 2) | pub enum Error {

FILE: init-tracing-opentelemetry/src/formats.rs
  type LayerBuilder (line 16) | pub trait LayerBuilder: Send + Sync {
    method build_layer (line 17) | fn build_layer<S>(
    method build_layer (line 98) | fn build_layer<S>(
    method build_layer (line 116) | fn build_layer<S>(
    method build_layer (line 134) | fn build_layer<S>(
    method build_layer (line 152) | fn build_layer<S>(
    method build_layer (line 172) | fn build_layer<S>(
  function configure_layer (line 25) | fn configure_layer<S, N, L, T, W>(
  function configure_writer (line 69) | fn configure_writer<S, N, L, T, W>(
  type PrettyLayerBuilder (line 95) | pub struct PrettyLayerBuilder;
  type JsonLayerBuilder (line 113) | pub struct JsonLayerBuilder;
  type FullLayerBuilder (line 131) | pub struct FullLayerBuilder;
  type CompactLayerBuilder (line 149) | pub struct CompactLayerBuilder;
  type LogfmtLayerBuilder (line 168) | pub struct LogfmtLayerBuilder;

FILE: init-tracing-opentelemetry/src/lib.rs
  function init_propagator (line 57) | pub fn init_propagator() -> Result<(), TraceError> {
  function propagator_from_string (line 81) | fn propagator_from_string(
  function init_tracing_failed_on_invalid_propagator (line 150) | fn init_tracing_failed_on_invalid_propagator() {

FILE: init-tracing-opentelemetry/src/otlp/logs.rs
  function identity (line 8) | pub fn identity(v: LoggerProviderBuilder) -> LoggerProviderBuilder {
  function init_loggerprovider (line 12) | pub fn init_loggerprovider<F>(

FILE: init-tracing-opentelemetry/src/otlp/metrics.rs
  function identity (line 13) | pub fn identity(v: MeterProviderBuilder) -> MeterProviderBuilder {
  function init_meterprovider (line 17) | pub fn init_meterprovider<F>(

FILE: init-tracing-opentelemetry/src/otlp/mod.rs
  type OtelGuard (line 23) | pub struct OtelGuard {
    method logger_provider (line 34) | pub fn logger_provider(&self) -> &impl LoggerProvider {
    method tracer_provider (line 39) | pub fn tracer_provider(&self) -> &impl TracerProvider {
    method meter_provider (line 45) | pub fn meter_provider(&self) -> &impl MeterProvider {
  method drop (line 52) | fn drop(&mut self) {
  function infer_protocol_from_env (line 69) | pub(crate) fn infer_protocol_from_env(
  function infer_protocol (line 80) | fn infer_protocol(maybe_protocol: Option<&str>, maybe_endpoint: Option<&...
  function debug_env (line 102) | pub fn debug_env() {
  function read_protocol_and_endpoint_from_env (line 119) | fn read_protocol_and_endpoint_from_env(
  function test_infer_protocol (line 175) | fn test_infer_protocol(

FILE: init-tracing-opentelemetry/src/otlp/traces.rs
  function identity (line 8) | pub fn identity(v: TracerProviderBuilder) -> TracerProviderBuilder {
  function init_tracerprovider (line 13) | pub fn init_tracerprovider<F>(

FILE: init-tracing-opentelemetry/src/resource.rs
  type DetectResource (line 20) | pub struct DetectResource {
    method with_fallback_service_name (line 30) | pub fn with_fallback_service_name(
    method with_fallback_service_version (line 42) | pub fn with_fallback_service_version(
    method build (line 51) | pub fn build(self) -> Resource {
  function debug_resource (line 65) | pub fn debug_resource(rsrc: &Resource) {
  type ServiceInfoDetector (line 72) | pub struct ServiceInfoDetector {
  method detect (line 78) | fn detect(&self) -> Resource {

FILE: init-tracing-opentelemetry/src/stdio.rs
  function identity (line 13) | pub fn identity<W: Write>(v: TracerProviderBuilder) -> TracerProviderBui...
  function init_tracer (line 17) | pub fn init_tracer<F, W>(resource: Resource, transform: F) -> Result<sdk...
  type WriteNoWhere (line 38) | pub struct WriteNoWhere;
  method write (line 41) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
  method flush (line 45) | fn flush(&mut self) -> std::io::Result<()> {

FILE: init-tracing-opentelemetry/src/tracing_subscriber_ext.rs
  function build_logger_text (line 37) | pub fn build_logger_text<S>() -> Box<dyn Layer<S> + Send + Sync + 'static>
  function build_loglevel_filter_layer (line 48) | pub fn build_loglevel_filter_layer() -> EnvFilter {
  function build_level_filter_layer (line 68) | pub fn build_level_filter_layer(log_directives: &str) -> Result<EnvFilte...
  function regiter_otel_layers (line 85) | pub fn regiter_otel_layers<S>(
  function register_otel_layers_with_resource (line 95) | pub fn register_otel_layers_with_resource<S>(
  function build_tracer_layer (line 126) | pub fn build_tracer_layer<S>() -> Result<(OpenTelemetryLayer<S, Tracer>,...
  function build_tracer_layer_with_resource (line 139) | pub fn build_tracer_layer_with_resource<S>(
  function build_logger_layer_with_resource (line 149) | pub(crate) fn build_logger_layer_with_resource(
  function build_tracer_layer_with_resource_and_name (line 163) | pub(crate) fn build_tracer_layer_with_resource_and_name<S>(
  function build_metrics_layer (line 190) | pub fn build_metrics_layer<S>()
  function build_metrics_layer_with_resource (line 200) | pub fn build_metrics_layer_with_resource<S>(
  function init_subscribers (line 220) | pub fn init_subscribers() -> Result<OtelGuard, Error> {
  function init_subscribers_and_loglevel (line 247) | pub fn init_subscribers_and_loglevel(log_directives: &str) -> Result<Ote...

FILE: testing-tracing-opentelemetry/src/lib.rs
  function assert_trace (line 12) | pub fn assert_trace(
  type FakeEnvironment (line 87) | pub struct FakeEnvironment {
    method setup (line 95) | pub async fn setup() -> Self {
    method collect_traces (line 128) | pub async fn collect_traces(
  function duplex_writer (line 150) | fn duplex_writer() -> (DuplexWriter, Receiver<Vec<u8>>) {
  type DuplexWriter (line 156) | struct DuplexWriter {
    type Writer (line 161) | type Writer = Self;
    method make_writer (line 163) | fn make_writer(&'a self) -> Self::Writer {
    method write (line 169) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
    method flush (line 174) | fn flush(&mut self) -> std::io::Result<()> {

FILE: tonic-tracing-opentelemetry/src/middleware/client.rs
  type OtelGrpcLayer (line 22) | pub struct OtelGrpcLayer;
    type Service (line 26) | type Service = OtelGrpcService<S>;
    method layer (line 27) | fn layer(&self, inner: S) -> Self::Service {
  type OtelGrpcService (line 33) | pub struct OtelGrpcService<S> {
  type Response (line 46) | type Response = Response<B2>;
  type Error (line 47) | type Error = S::Error;
  type Future (line 48) | type Future = ResponseFuture<S::Future>;
    type Output (line 94) | type Output = Result<Response<ResBody>, E>;
    method poll (line 96) | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Outp...
  function poll_ready (line 53) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::...
  function call (line 57) | fn call(&mut self, req: Request<B>) -> Self::Future {

FILE: tonic-tracing-opentelemetry/src/middleware/filters.rs
  function reject_healthcheck (line 2) | pub fn reject_healthcheck(path: &str) -> bool {

FILE: tonic-tracing-opentelemetry/src/middleware/server.rs
  type Filter (line 13) | pub type Filter = fn(&str) -> bool;
  type OtelGrpcLayer (line 22) | pub struct OtelGrpcLayer {
    method filter (line 29) | pub fn filter(self, filter: Filter) -> Self {
    type Service (line 38) | type Service = OtelGrpcService<S>;
    method layer (line 39) | fn layer(&self, inner: S) -> Self::Service {
  type OtelGrpcService (line 48) | pub struct OtelGrpcService<S> {
  type Response (line 60) | type Response = S::Response;
  type Error (line 61) | type Error = S::Error;
  type Future (line 62) | type Future = ResponseFuture<S::Future>;
    type Output (line 121) | type Output = Result<Response<ResBody>, Error>;
    method poll (line 123) | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Outp...
  function poll_ready (line 70) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::...
  function call (line 74) | fn call(&mut self, req: Request<B>) -> Self::Future {

FILE: tracing-opentelemetry-instrumentation-sdk/src/http/grpc.rs
  type GrpcCode (line 10) | pub enum GrpcCode {
  function update_span_from_response (line 65) | pub fn update_span_from_response<B>(
  function status_from_http_header (line 83) | fn status_from_http_header(headers: &HeaderMap) -> Option<u16> {
  function status_from_http_status (line 90) | fn status_from_http_status(status_code: http::StatusCode) -> Option<u16> {
  function status_is_error (line 116) | pub fn status_is_error(status: u16, is_spankind_server: bool) -> bool {
  function update_span_from_error (line 124) | fn update_span_from_error<E>(span: &tracing::Span, error: &E)
  function update_span_from_response_or_error (line 136) | pub fn update_span_from_response_or_error<B, E>(
  function make_span_from_request (line 155) | pub(crate) fn make_span_from_request<B>(
  function test_status_from_http_header (line 193) | fn test_status_from_http_header(#[case] input: i32) {

FILE: tracing-opentelemetry-instrumentation-sdk/src/http/grpc_client.rs
  function make_span_from_request (line 3) | pub fn make_span_from_request<B>(req: &http::Request<B>) -> tracing::Span {

FILE: tracing-opentelemetry-instrumentation-sdk/src/http/grpc_server.rs
  function make_span_from_request (line 3) | pub fn make_span_from_request<B>(req: &http::Request<B>) -> tracing::Span {

FILE: tracing-opentelemetry-instrumentation-sdk/src/http/http_server.rs
  function make_span_from_request (line 10) | pub fn make_span_from_request<B>(req: &http::Request<B>) -> tracing::Span {
  function update_span_from_response (line 38) | pub fn update_span_from_response<B>(span: &tracing::Span, response: &htt...
  function update_span_from_error (line 53) | pub fn update_span_from_error<E>(span: &tracing::Span, error: &E)
  function update_span_from_response_or_error (line 65) | pub fn update_span_from_response_or_error<B, E>(

FILE: tracing-opentelemetry-instrumentation-sdk/src/http/opentelemetry_http.rs
  type HeaderInjector (line 4) | pub struct HeaderInjector<'a>(pub &'a mut http::HeaderMap);
  method set (line 8) | fn set(&mut self, key: &str, value: String) {
  type HeaderExtractor (line 17) | pub struct HeaderExtractor<'a>(pub &'a http::HeaderMap);
  method get (line 21) | fn get(&self, key: &str) -> Option<&str> {
  method keys (line 26) | fn keys(&self) -> Vec<&str> {

FILE: tracing-opentelemetry-instrumentation-sdk/src/http/tools.rs
  function inject_context (line 8) | pub fn inject_context(context: &Context, headers: &mut http::HeaderMap) {
  function extract_context (line 17) | pub fn extract_context(headers: &http::HeaderMap) -> Context {
  function extract_service_method (line 22) | pub fn extract_service_method(uri: &Uri) -> (&str, &str) {
  function extract_client_ip_from_headers (line 36) | pub fn extract_client_ip_from_headers(headers: &HeaderMap) -> Option<&st...
  function extract_client_ip_from_x_forwarded_for (line 47) | fn extract_client_ip_from_x_forwarded_for(headers: &HeaderMap) -> Option...
  function extract_client_ip_from_forwarded (line 56) | fn extract_client_ip_from_forwarded(headers: &HeaderMap) -> Option<&str> {
  function http_target (line 76) | pub fn http_target(uri: &Uri) -> &str {
  function http_flavor (line 83) | pub fn http_flavor(version: Version) -> Cow<'static, str> {
  function url_scheme (line 95) | pub fn url_scheme(uri: &Uri) -> &str {
  function user_agent (line 100) | pub fn user_agent<B>(req: &http::Request<B>) -> &str {
  function http_host (line 107) | pub fn http_host<B>(req: &http::Request<B>) -> &str {
  function test_extract_service_method (line 125) | fn test_extract_service_method(
  function test_extract_url_scheme (line 137) | fn test_extract_url_scheme(#[case] input: &str, #[case] expected: &str) {
  function test_extract_client_ip_from_x_forwarded_for (line 151) | fn test_extract_client_ip_from_x_forwarded_for(#[case] input: &str, #[ca...
  function test_extract_client_ip_from_forwarded (line 181) | fn test_extract_client_ip_from_forwarded(#[case] input: &str, #[case] ex...

FILE: tracing-opentelemetry-instrumentation-sdk/src/lib.rs
  constant TRACING_TARGET (line 17) | pub const TRACING_TARGET: &str = "otel::tracing";
  constant TRACING_LEVEL (line 20) | pub const TRACING_LEVEL: tracing::Level = tracing::Level::TRACE;
  constant TRACING_LEVEL (line 23) | pub const TRACING_LEVEL: tracing::Level = tracing::Level::INFO;
  function find_current_context (line 68) | pub fn find_current_context() -> Context {
  function find_current_trace_id (line 85) | pub fn find_current_trace_id() -> Option<String> {
  function find_context_from_tracing (line 91) | pub fn find_context_from_tracing(span: &tracing::Span) -> Context {
  function find_trace_id_from_tracing (line 100) | pub fn find_trace_id_from_tracing(span: &tracing::Span) -> Option<String> {
  function find_trace_id (line 109) | pub fn find_trace_id(context: &Context) -> Option<String> {
  function find_span_id (line 138) | pub fn find_span_id(context: &Context) -> Option<String> {
  type BoxError (line 164) | pub type BoxError = Box<dyn std::error::Error + Send + Sync>;

FILE: tracing-opentelemetry-instrumentation-sdk/src/span_type.rs
  type SpanType (line 8) | pub enum SpanType {
  method fmt (line 25) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Condensed preview — 114 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (376K chars).
[
  {
    "path": ".editorconfig",
    "chars": 1356,
    "preview": "# https://editorconfig.org/\n\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ninsert_final_newline = true\ntrim_trai"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 832,
    "preview": "# These are supported funding model platforms\n\n# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, us"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1116,
    "preview": "---\nname: ci\n\non:\n  pull_request:\n    branches-ignore:\n      - \"release-plz-*\"\n  push:\n    branches:\n      - main\n      "
  },
  {
    "path": ".github/workflows/mega-linter.yml",
    "chars": 5709,
    "preview": "# MegaLinter GitHub Action configuration file\n# More info at https://megalinter.io\n---\nname: MegaLinter\n\n# Trigger mega-"
  },
  {
    "path": ".github/workflows/release-plz.yml",
    "chars": 706,
    "preview": "name: release-plz\n\npermissions:\n  pull-requests: write\n  contents: write\n\non:\n  workflow_dispatch:\n  push:\n    branches:"
  },
  {
    "path": ".gitignore",
    "chars": 4689,
    "preview": "# Created by https://www.toptal.com/developers/gitignore/api/git,bazel,vim,emacs,visualstudiocode,jetbrains+all,helm,rus"
  },
  {
    "path": ".mega-linter.yml",
    "chars": 1144,
    "preview": "# Configuration file for MegaLinter\n# See all available variables at https://megalinter.github.io/configuration/ and in "
  },
  {
    "path": ".mise.toml",
    "chars": 4852,
    "preview": "[env]\nOTEL_EXPORTER_OTLP_TRACES_ENDPOINT = \"http://127.0.0.1:4317\"\nOTEL_EXPORTER_OTLP_TRACES_PROTOCOL = \"grpc\"\nOTEL_TRAC"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 269,
    "preview": "{\n  \"cSpell.words\": [\n    \"insta\",\n    \"opentelemetry\",\n    \"OTEL\",\n    \"OTLP\",\n    \"sdktrace\",\n    \"semcov\"\n  ],\n  \"rus"
  },
  {
    "path": ".yamllint.yml",
    "chars": 608,
    "preview": "###########################################\n# These are the rules used for            #\n# linting all the yaml files in "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 9129,
    "preview": "<!-- markdownlint-disable MD024-->\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nTh"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 6051,
    "preview": "# Contributing to tracing-opentelemetry-instrumentation-sdk\n\nThank you for your interest in contributing! This document "
  },
  {
    "path": "Cargo.toml",
    "chars": 2084,
    "preview": "[workspace]\nresolver = \"2\"\nmembers = [\n  \"axum-tracing-opentelemetry\",\n  \"examples/*\",\n  \"fake-opentelemetry-collector\","
  },
  {
    "path": "LICENSE",
    "chars": 7048,
    "preview": "Creative Commons Legal Code\n\nCC0 1.0 Universal\n\n    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE\n"
  },
  {
    "path": "README.md",
    "chars": 1705,
    "preview": "# tracing-opentelemetry-instrumentation-sdk\n\nA set of rust crates to help working with tracing + opentelemetry\n\n- `init-"
  },
  {
    "path": "axum-tracing-opentelemetry/CHANGELOG.md",
    "chars": 4190,
    "preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
  },
  {
    "path": "axum-tracing-opentelemetry/Cargo.toml",
    "chars": 2245,
    "preview": "[package]\nname = \"axum-tracing-opentelemetry\"\ndescription = \"Middlewares and tools to integrate axum + tracing + opentel"
  },
  {
    "path": "axum-tracing-opentelemetry/README.md",
    "chars": 2434,
    "preview": "# axum-tracing-opentelemetry\n\n[![crates license](https://img.shields.io/crates/l/axum-tracing-opentelemetry.svg)](http:/"
  },
  {
    "path": "axum-tracing-opentelemetry/src/lib.rs",
    "chars": 590,
    "preview": "//#![warn(missing_docs)]\n#![forbid(unsafe_code)]\n#![warn(clippy::perf)]\n#![warn(clippy::pedantic)]\n#![allow(clippy::modu"
  },
  {
    "path": "axum-tracing-opentelemetry/src/middleware/mod.rs",
    "chars": 103,
    "preview": "mod response_injector;\nmod trace_extractor;\n\npub use response_injector::*;\npub use trace_extractor::*;\n"
  },
  {
    "path": "axum-tracing-opentelemetry/src/middleware/response_injector.rs",
    "chars": 1767,
    "preview": "use futures_core::future::BoxFuture;\nuse http::{Request, Response};\nuse std::task::{Context, Poll};\nuse tower::{Layer, S"
  },
  {
    "path": "axum-tracing-opentelemetry/src/middleware/trace_extractor.rs",
    "chars": 10087,
    "preview": "//\n//! `OpenTelemetry` tracing middleware.\n//!\n//! This returns a [`OtelAxumLayer`] configured to use [`OpenTelemetry`'s"
  },
  {
    "path": "cliff.toml",
    "chars": 3673,
    "preview": "# git-cliff ~ default configuration file\n# https://git-cliff.org/docs/configuration\n#\n# Lines starting with \"#\" are comm"
  },
  {
    "path": "deny.toml",
    "chars": 11831,
    "preview": "# This template contains all of the possible sections and their default values\n\n# Note that all fields that take a lint "
  },
  {
    "path": "examples/axum-otlp/Cargo.toml",
    "chars": 811,
    "preview": "[package]\nname = \"examples-axum-otlp\"\npublish = false\nedition.workspace = true\nversion.workspace = true\nrepository.works"
  },
  {
    "path": "examples/axum-otlp/README.md",
    "chars": 2923,
    "preview": "# `examples-axum-otlp`\n\nIn a terminal, run\n\nConfigure the [environment variables](https://opentelemetry.io/docs/language"
  },
  {
    "path": "examples/axum-otlp/src/main.rs",
    "chars": 2636,
    "preview": "#![allow(clippy::let_with_type_underscore)]\n#![allow(clippy::default_constructed_unit_structs)] // warning since 1.71\n\nu"
  },
  {
    "path": "examples/bug_234_tls/Cargo.toml",
    "chars": 811,
    "preview": "[package]\nname = \"bug_234_tls\"\npublish = false\nedition.workspace = true\nversion.workspace = true\nrepository.workspace = "
  },
  {
    "path": "examples/bug_234_tls/src/main.rs",
    "chars": 491,
    "preview": "use axum::{Router, response::Html, routing::get};\n\n#[tokio::main]\nasync fn main() {\n    // build our application with a "
  },
  {
    "path": "examples/grpc/Cargo.toml",
    "chars": 932,
    "preview": "[package]\nname = \"examples-grpc\"\npublish = false\nedition.workspace = true\nversion.workspace = true\nrepository.workspace "
  },
  {
    "path": "examples/grpc/build.rs",
    "chars": 697,
    "preview": "use std::path::PathBuf;\n\nfn main() {\n    // trigger rebuild if \"proto\" folder change or empty\n    print!(\"cargo:rerun-if"
  },
  {
    "path": "examples/grpc/proto/helloworld.proto",
    "chars": 478,
    "preview": "syntax = \"proto3\";\n\nimport \"google/protobuf/empty.proto\";\npackage helloworld;\n\nservice Greeter {\n  rpc SayHello (HelloRe"
  },
  {
    "path": "examples/grpc/src/client.rs",
    "chars": 1748,
    "preview": "use generated::greeter_client::GreeterClient;\nuse generated::{HelloRequest, StatusRequest};\nuse tonic::Code;\nuse tonic::"
  },
  {
    "path": "examples/grpc/src/generated/helloworld.rs",
    "chars": 15545,
    "preview": "// This file is @generated by prost-build.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct HelloReque"
  },
  {
    "path": "examples/grpc/src/server.rs",
    "chars": 2802,
    "preview": "use generated::greeter_server::{Greeter, GreeterServer};\nuse generated::{HelloReply, HelloRequest, StatusRequest};\nuse t"
  },
  {
    "path": "examples/init-tracing-with/.cargo/config.toml",
    "chars": 48,
    "preview": "[build]\nrustflags = [\"--cfg\", \"tokio_unstable\"]\n"
  },
  {
    "path": "examples/init-tracing-with/Cargo.toml",
    "chars": 466,
    "preview": "[package]\nname = \"init-tracing-with\"\npublish = false\nedition.workspace = true\nversion.workspace = true\nrepository.worksp"
  },
  {
    "path": "examples/init-tracing-with/src/main.rs",
    "chars": 1133,
    "preview": "use init_tracing_opentelemetry::TracingConfig;\nuse tokio_blocked::TokioBlockedLayer;\nuse tracing::info;\nuse tracing_subs"
  },
  {
    "path": "examples/load/Cargo.toml",
    "chars": 553,
    "preview": "[package]\nname = \"examples-load\"\npublish = false\nedition.workspace = true\nversion.workspace = true\nrepository.workspace "
  },
  {
    "path": "examples/load/README.md",
    "chars": 3135,
    "preview": "# examples use to\n\nNot an example, but a \"load application\" used to measure memory usage (+/-)\n\n```sh\n> bash -c \"cargo r"
  },
  {
    "path": "examples/load/src/main.rs",
    "chars": 1588,
    "preview": "use std::time::Instant;\n\nuse memory_stats::memory_stats;\nuse tracing::field::Empty;\nuse tracing_opentelemetry_instrument"
  },
  {
    "path": "examples/logging/Cargo.toml",
    "chars": 565,
    "preview": "[package]\nname = \"examples-logging\"\npublish = false\nedition.workspace = true\nversion.workspace = true\nrepository.workspa"
  },
  {
    "path": "examples/logging/src/main.rs",
    "chars": 679,
    "preview": "#[tracing::instrument]\nasync fn log() {\n    tracing::error!(\"This is ground control to Major Tom\");\n    tracing::warn!(\""
  },
  {
    "path": "fake-opentelemetry-collector/CHANGELOG.md",
    "chars": 2793,
    "preview": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changel"
  },
  {
    "path": "fake-opentelemetry-collector/Cargo.toml",
    "chars": 1131,
    "preview": "[package]\nname = \"fake-opentelemetry-collector\"\ndescription = \"A Fake (basic) opentelemetry collector, useful to test wh"
  },
  {
    "path": "fake-opentelemetry-collector/README.md",
    "chars": 2701,
    "preview": "# fake-opentelemetry-collector\n\nA Fake (basic) opentelemetry collector, useful to test what is collected by opentelemetr"
  },
  {
    "path": "fake-opentelemetry-collector/src/common.rs",
    "chars": 311,
    "preview": "use std::collections::BTreeMap;\n\npub(crate) fn cnv_attributes(\n    attributes: &[opentelemetry_proto::tonic::common::v1:"
  },
  {
    "path": "fake-opentelemetry-collector/src/lib.rs",
    "chars": 5658,
    "preview": "mod common;\nmod logs;\nmod metrics;\nmod trace;\n\nuse logs::*;\nuse metrics::*;\nuse trace::*;\n\npub use logs::ExportedLog;\npu"
  },
  {
    "path": "fake-opentelemetry-collector/src/logs.rs",
    "chars": 2438,
    "preview": "use crate::common::cnv_attributes;\nuse opentelemetry_proto::tonic::collector::logs::v1::{\n    ExportLogsServiceRequest, "
  },
  {
    "path": "fake-opentelemetry-collector/src/metrics.rs",
    "chars": 11255,
    "preview": "use crate::common::cnv_attributes;\nuse opentelemetry_proto::tonic::{\n    collector::metrics::v1::{\n        ExportMetrics"
  },
  {
    "path": "fake-opentelemetry-collector/src/trace.rs",
    "chars": 5035,
    "preview": "//! based on https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry-otlp/tests/smoke.rs\nuse crate:"
  },
  {
    "path": "fake-opentelemetry-collector/tests/demo_log.rs",
    "chars": 1923,
    "preview": "use std::time::Duration;\n\nuse fake_opentelemetry_collector::{FakeCollectorServer, setup_logger_provider};\nuse openteleme"
  },
  {
    "path": "fake-opentelemetry-collector/tests/demo_metrics.rs",
    "chars": 8431,
    "preview": "use fake_opentelemetry_collector::{FakeCollectorServer, setup_meter_provider};\nuse opentelemetry::{KeyValue, global};\nus"
  },
  {
    "path": "fake-opentelemetry-collector/tests/demo_trace.rs",
    "chars": 2355,
    "preview": "use std::time::Duration;\n\nuse fake_opentelemetry_collector::{FakeCollectorServer, setup_tracer_provider};\nuse openteleme"
  },
  {
    "path": "fake-opentelemetry-collector/tests/snapshots/demo_log__demo_fake_logger_and_collector.snap",
    "chars": 376,
    "preview": "---\nsource: fake-opentelemetry-collector/tests/demo_log.rs\nexpression: otel_logs\nsnapshot_kind: text\n---\n- trace_id: \"[t"
  },
  {
    "path": "fake-opentelemetry-collector/tests/snapshots/demo_metrics__demo_fake_meter_and_collector.snap",
    "chars": 2768,
    "preview": "---\nsource: fake-opentelemetry-collector/tests/demo_metrics.rs\nexpression: otel_metrics\n---\n- metrics:\n    - name: test_"
  },
  {
    "path": "fake-opentelemetry-collector/tests/snapshots/demo_trace__demo_fake_tracer_and_collector.snap",
    "chars": 616,
    "preview": "---\nsource: fake-opentelemetry-collector/tests/demo_trace.rs\nexpression: otel_spans\nsnapshot_kind: text\n---\n- trace_id: "
  },
  {
    "path": "init-tracing-opentelemetry/CHANGELOG.md",
    "chars": 8523,
    "preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
  },
  {
    "path": "init-tracing-opentelemetry/Cargo.toml",
    "chars": 3338,
    "preview": "[package]\nname = \"init-tracing-opentelemetry\"\ndescription = \"A set of helpers to initialize (and more) tracing + opentel"
  },
  {
    "path": "init-tracing-opentelemetry/README.md",
    "chars": 12996,
    "preview": "# init-tracing-opentelemetry\n\n[![crates license](https://img.shields.io/crates/l/init-tracing-opentelemetry.svg)](http:/"
  },
  {
    "path": "init-tracing-opentelemetry/src/config.rs",
    "chars": 28372,
    "preview": "//! Flexible tracing configuration with builder pattern.\n//!\n//! Provides [`TracingConfig`] for configurable tracing set"
  },
  {
    "path": "init-tracing-opentelemetry/src/error.rs",
    "chars": 584,
    "preview": "#[derive(thiserror::Error, Debug)]\npub enum Error {\n    #[error(transparent)]\n    IoError(#[from] std::io::Error),\n\n    "
  },
  {
    "path": "init-tracing-opentelemetry/src/formats.rs",
    "chars": 6182,
    "preview": "//! Format-specific layer builders for tracing output.\n//!\n//! Provides implementations for different log formats (Prett"
  },
  {
    "path": "init-tracing-opentelemetry/src/lib.rs",
    "chars": 5998,
    "preview": "//#![warn(missing_docs)]\n#![forbid(unsafe_code)]\n#![warn(clippy::perf)]\n#![warn(clippy::pedantic)]\n#![allow(clippy::modu"
  },
  {
    "path": "init-tracing-opentelemetry/src/otlp/logs.rs",
    "chars": 2085,
    "preview": "use super::infer_protocol_from_env;\nuse opentelemetry_otlp::{ExporterBuildError, LogExporter};\nuse opentelemetry_sdk::{R"
  },
  {
    "path": "init-tracing-opentelemetry/src/otlp/metrics.rs",
    "chars": 3566,
    "preview": "use super::infer_protocol_from_env;\nuse opentelemetry_otlp::{ExporterBuildError, MetricExporter, WithExportConfig};\nuse "
  },
  {
    "path": "init-tracing-opentelemetry/src/otlp/mod.rs",
    "chars": 5623,
    "preview": "#[cfg(feature = \"logs\")]\npub mod logs;\n#[cfg(feature = \"metrics\")]\npub mod metrics;\npub mod traces;\n\n#[cfg(feature = \"lo"
  },
  {
    "path": "init-tracing-opentelemetry/src/otlp/traces.rs",
    "chars": 2202,
    "preview": "use super::infer_protocol_from_env;\nuse opentelemetry_otlp::{ExporterBuildError, SpanExporter};\nuse opentelemetry_sdk::{"
  },
  {
    "path": "init-tracing-opentelemetry/src/resource.rs",
    "chars": 3702,
    "preview": "use std::borrow::Cow;\n\nuse opentelemetry::KeyValue;\n// use opentelemetry_resource_detectors::OsResourceDetector;\nuse ope"
  },
  {
    "path": "init-tracing-opentelemetry/src/stdio.rs",
    "chars": 1654,
    "preview": "use crate::Error;\nuse opentelemetry::InstrumentationScope;\nuse opentelemetry::trace::TracerProvider as _;\nuse openteleme"
  },
  {
    "path": "init-tracing-opentelemetry/src/tracing_subscriber_ext.rs",
    "chars": 9467,
    "preview": "#![allow(deprecated)]\nuse std::borrow::Cow;\n\nuse opentelemetry::trace::TracerProvider;\n#[cfg(feature = \"logs\")]\nuse open"
  },
  {
    "path": "release-plz.toml",
    "chars": 1742,
    "preview": "# [Configuration | Release-plz](https://release-plz.ieni.dev/docs/config)\n[workspace]\nfeatures_always_increment_minor = "
  },
  {
    "path": "renovate.json5",
    "chars": 910,
    "preview": "// https://docs.renovatebot.com/configuration-options/\n// https://www.augmentedmind.de/2023/07/30/renovate-bot-cheat-she"
  },
  {
    "path": "rust-toolchain.toml",
    "chars": 31,
    "preview": "[toolchain]\nchannel = \"1.91.0\"\n"
  },
  {
    "path": "testing-tracing-opentelemetry/Cargo.toml",
    "chars": 918,
    "preview": "[package]\nname = \"testing-tracing-opentelemetry\"\ndescription = \"helpers to help testing app + tracing + opentelemetry.\"\n"
  },
  {
    "path": "testing-tracing-opentelemetry/src/lib.rs",
    "chars": 6462,
    "preview": "use assert2::{assert, check};\nuse opentelemetry::trace::TracerProvider;\nuse opentelemetry_sdk::propagation::TraceContext"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__call_with_w3c_trace.snap",
    "chars": 957,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: tracing_events\nsnapshot_kind: text\n---\n- fields:\n    me"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__call_with_w3c_trace_otel_spans.snap",
    "chars": 1791,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: otel_spans\n---\n- trace_id: \"[trace_id:lg32]\"\n  span_id:"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__empty_http_route_for_nonexisting_route.snap",
    "chars": 923,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: tracing_events\n---\n- fields:\n    message: new\n  level: "
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__empty_http_route_for_nonexisting_route_otel_spans.snap",
    "chars": 1770,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: otel_spans\n---\n- trace_id: \"[trace_id:lg32]\"\n  span_id:"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__extract_route_from_nested.snap",
    "chars": 963,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: tracing_events\nsnapshot_kind: text\n---\n- fields:\n    me"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__extract_route_from_nested_otel_spans.snap",
    "chars": 1797,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: otel_spans\n---\n- trace_id: \"[trace_id:lg32]\"\n  span_id:"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__filled_http_headers.snap",
    "chars": 963,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: tracing_events\nsnapshot_kind: text\n---\n- fields:\n    me"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__filled_http_headers_otel_spans.snap",
    "chars": 1795,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: otel_spans\n---\n- trace_id: \"[trace_id:lg32]\"\n  span_id:"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__filled_http_route_for_existing_route.snap",
    "chars": 979,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: tracing_events\nsnapshot_kind: text\n---\n- fields:\n    me"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__filled_http_route_for_existing_route_otel_spans.snap",
    "chars": 1805,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: otel_spans\n---\n- trace_id: \"[trace_id:lg32]\"\n  span_id:"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__status_code_on_close_for_error.snap",
    "chars": 964,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: tracing_events\n---\n- fields:\n    message: new\n  level: "
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__status_code_on_close_for_error_otel_spans.snap",
    "chars": 1789,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: otel_spans\n---\n- trace_id: \"[trace_id:lg32]\"\n  span_id:"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__status_code_on_close_for_ok.snap",
    "chars": 957,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: tracing_events\nsnapshot_kind: text\n---\n- fields:\n    me"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__status_code_on_close_for_ok_otel_spans.snap",
    "chars": 1790,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: otel_spans\n---\n- trace_id: \"[trace_id:lg32]\"\n  span_id:"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__trace_id_in_child_span.snap",
    "chars": 2024,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: tracing_events\n---\n- fields:\n    message: new\n  level: "
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__trace_id_in_child_span_for_remote.snap",
    "chars": 2024,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: tracing_events\n---\n- fields:\n    message: new\n  level: "
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__trace_id_in_child_span_for_remote_otel_spans.snap",
    "chars": 2868,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: otel_spans\n---\n- trace_id: \"[trace_id:lg32]\"\n  span_id:"
  },
  {
    "path": "testing-tracing-opentelemetry/src/snapshots/testing_tracing_opentelemetry__trace_id_in_child_span_otel_spans.snap",
    "chars": 2867,
    "preview": "---\nsource: testing-tracing-opentelemetry/src/lib.rs\nexpression: otel_spans\n---\n- trace_id: \"[trace_id:lg32]\"\n  span_id:"
  },
  {
    "path": "tonic-tracing-opentelemetry/CHANGELOG.md",
    "chars": 2169,
    "preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
  },
  {
    "path": "tonic-tracing-opentelemetry/Cargo.toml",
    "chars": 2155,
    "preview": "[package]\nname = \"tonic-tracing-opentelemetry\"\ndescription = \"Middlewares and tools to integrate tonic + tracing + opent"
  },
  {
    "path": "tonic-tracing-opentelemetry/README.md",
    "chars": 2244,
    "preview": "# tonic-tracing-opentelemetry\n\n[![crates license](https://img.shields.io/crates/l/tonic-tracing-opentelemetry.svg)](http"
  },
  {
    "path": "tonic-tracing-opentelemetry/src/lib.rs",
    "chars": 202,
    "preview": "//#![warn(missing_docs)]\n#![forbid(unsafe_code)]\n#![warn(clippy::perf)]\n#![warn(clippy::pedantic)]\n#![allow(clippy::modu"
  },
  {
    "path": "tonic-tracing-opentelemetry/src/middleware/client.rs",
    "chars": 3324,
    "preview": "//! code based on [tonic/examples/src/tower/client.rs at master · hyperium/tonic · GitHub](https://github.com/hyperium/t"
  },
  {
    "path": "tonic-tracing-opentelemetry/src/middleware/filters.rs",
    "chars": 123,
    "preview": "#[must_use]\npub fn reject_healthcheck(path: &str) -> bool {\n    !path.contains(\"grpc.health.\") //\"grpc.health.v1.Health\""
  },
  {
    "path": "tonic-tracing-opentelemetry/src/middleware/mod.rs",
    "chars": 49,
    "preview": "pub mod client;\npub mod filters;\npub mod server;\n"
  },
  {
    "path": "tonic-tracing-opentelemetry/src/middleware/server.rs",
    "chars": 4154,
    "preview": "//! code based on [tonic/examples/src/tower/client.rs at master · hyperium/tonic · GitHub](https://github.com/hyperium/t"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/CHANGELOG.md",
    "chars": 3452,
    "preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/Cargo.toml",
    "chars": 1214,
    "preview": "[package]\nname = \"tracing-opentelemetry-instrumentation-sdk\"\ndescription = \"A set of helpers to build OpenTelemetry inst"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/README.md",
    "chars": 4738,
    "preview": "# tracing-opentelemetry-instrumentation-sdk\n\nProvide a set of helpers to build [OpenTelemetry] instrumentation based on "
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/src/http/grpc.rs",
    "chars": 6772,
    "preview": "use http::HeaderMap;\nuse opentelemetry_semantic_conventions::attribute::{\n    EXCEPTION_MESSAGE, OTEL_STATUS_CODE, RPC_G"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/src/http/grpc_client.rs",
    "chars": 174,
    "preview": "use super::grpc;\n\npub fn make_span_from_request<B>(req: &http::Request<B>) -> tracing::Span {\n    grpc::make_span_from_r"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/src/http/grpc_server.rs",
    "chars": 174,
    "preview": "use super::grpc;\n\npub fn make_span_from_request<B>(req: &http::Request<B>) -> tracing::Span {\n    grpc::make_span_from_r"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/src/http/http_server.rs",
    "chars": 3385,
    "preview": "use std::error::Error;\n\nuse crate::http::{http_flavor, http_host, url_scheme, user_agent};\nuse crate::otel_trace_span;\nu"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/src/http/mod.rs",
    "chars": 131,
    "preview": "pub mod grpc;\npub mod grpc_client;\npub mod grpc_server;\npub mod http_server;\nmod opentelemetry_http;\n\nmod tools;\npub use"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/src/http/opentelemetry_http.rs",
    "chars": 1128,
    "preview": "use opentelemetry::propagation::{Extractor, Injector};\n\n// copy from crate opentelemetry-http (to not be dependants of o"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/src/http/tools.rs",
    "chars": 6739,
    "preview": "use std::borrow::Cow;\n\nuse http::{HeaderMap, Uri, Version};\nuse opentelemetry::Context;\n\nuse super::opentelemetry_http::"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/src/lib.rs",
    "chars": 5434,
    "preview": "//#![warn(missing_docs)]\n#![forbid(unsafe_code)]\n#![warn(clippy::perf)]\n#![warn(clippy::pedantic)]\n#![allow(clippy::modu"
  },
  {
    "path": "tracing-opentelemetry-instrumentation-sdk/src/span_type.rs",
    "chars": 1398,
    "preview": "use std::fmt::Display;\n\n// SpanType is a non official open-telemetry key, only supported by Datadog, to help categorize "
  }
]

About this extraction

This page contains the full source code of the davidB/tracing-opentelemetry-instrumentation-sdk GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 114 files (344.3 KB), approximately 96.1k tokens, and a symbol index with 358 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!