├── .dockerignore ├── .github ├── dependabot.yaml └── workflows │ ├── ci.yaml │ ├── release-backend.yml │ └── release-gateway.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── hello-tracing-backend ├── Cargo.toml ├── Dockerfile ├── bin │ └── entrypoint.sh ├── build.rs ├── config.yaml ├── k8s │ ├── deploy │ ├── hello-tracing-backend.yaml │ └── kustomization.yaml ├── proto │ └── hello-tracing-backend-v0.proto └── src │ ├── api.rs │ ├── api │ └── v0.rs │ ├── config.rs │ ├── lib.rs │ └── main.rs ├── hello-tracing-common ├── Cargo.toml ├── config.yaml └── src │ ├── config.rs │ ├── error.rs │ ├── lib.rs │ ├── otel.rs │ ├── otel │ └── grpc.rs │ └── telemetry.rs ├── hello-tracing-gateway ├── Cargo.toml ├── Dockerfile ├── bin │ └── entrypoint.sh ├── build.rs ├── config.yaml ├── k8s │ ├── deploy │ ├── hello-tracing-gateway.yaml │ └── kustomization.yaml ├── proto │ └── hello-tracing-backend-v0.proto └── src │ ├── api.rs │ ├── api │ └── v0.rs │ ├── backend.rs │ ├── config.rs │ ├── lib.rs │ └── main.rs ├── justfile ├── k8s └── hello-tracing.yaml ├── release.toml ├── rust-toolchain.toml ├── rustfmt.toml └── taplo.toml /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | target 3 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: cargo 5 | directory: / 6 | schedule: 7 | interval: daily 8 | 9 | - package-ecosystem: github-actions 10 | directory: / 11 | schedule: 12 | interval: daily 13 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags-ignore: 8 | - hello-tracing-backend/v* 9 | - hello-tracing-common/v* 10 | - hello-tracing-gateway/v* 11 | pull_request: 12 | branches: 13 | - main 14 | schedule: 15 | - cron: 0 4/12 * * * 16 | workflow_dispatch: 17 | inputs: 18 | nightly: 19 | description: use latest nightly 20 | required: true 21 | type: boolean 22 | 23 | concurrency: 24 | group: ${{github.workflow}}-${{github.head_ref || github.run_id}} 25 | cancel-in-progress: true 26 | 27 | jobs: 28 | toolchain: 29 | runs-on: ubuntu-latest 30 | env: 31 | nightly: ${{(github.event.inputs.nightly == 'true' || github.event_name == 'schedule') && 'true' || ''}} 32 | outputs: 33 | toolchain: ${{steps.set_toolchain.outputs.toolchain}} 34 | nightly_toolchain: ${{steps.set_toolchain.outputs.nightly_toolchain}} 35 | steps: 36 | - uses: actions/checkout@v4 37 | - name: Set toolchain 38 | id: set_toolchain 39 | run: | 40 | toolchain=$(grep channel rust-toolchain.toml | sed -r 's/channel = "(.*)"/\1/') 41 | echo "using toolchain $toolchain" 42 | echo "toolchain=$toolchain" >> "$GITHUB_OUTPUT" 43 | if [[ $toolchain =~ ^nightly.* ]]; then 44 | echo "using nightly_toolchain $toolchain" 45 | echo "nightly_toolchain=$toolchain" >> "$GITHUB_OUTPUT" 46 | else 47 | echo "using nightly_toolchain nightly" 48 | echo "nightly_toolchain=nightly" >> "$GITHUB_OUTPUT" 49 | fi 50 | 51 | check: 52 | runs-on: ubuntu-latest 53 | needs: toolchain 54 | steps: 55 | - uses: actions/checkout@v4 56 | 57 | - name: Install Rust 58 | uses: dtolnay/rust-toolchain@master 59 | with: 60 | toolchain: ${{needs.toolchain.outputs.toolchain}} 61 | 62 | - name: Install just 63 | uses: taiki-e/install-action@v2 64 | with: 65 | tool: just 66 | 67 | - name: Install protoc 68 | uses: arduino/setup-protoc@v3 69 | with: 70 | repo-token: ${{ secrets.GITHUB_TOKEN }} 71 | 72 | - uses: Swatinem/rust-cache@v2 73 | 74 | - name: just check 75 | run: | 76 | rustup override set ${{needs.toolchain.outputs.toolchain}} 77 | just check 78 | 79 | fmt-check: 80 | runs-on: ubuntu-latest 81 | needs: toolchain 82 | steps: 83 | - uses: actions/checkout@v4 84 | 85 | - name: Install Rust 86 | uses: dtolnay/rust-toolchain@master 87 | with: 88 | toolchain: ${{needs.toolchain.outputs.nightly_toolchain}} 89 | components: rustfmt 90 | 91 | - name: Install just 92 | uses: taiki-e/install-action@v2 93 | with: 94 | tool: just 95 | 96 | - uses: Swatinem/rust-cache@v2 97 | 98 | - name: just fmt-check 99 | run: | 100 | rustup override set ${{needs.toolchain.outputs.nightly_toolchain}} 101 | just fmt-check '' 102 | 103 | lint: 104 | runs-on: ubuntu-latest 105 | needs: [toolchain, check, fmt-check] 106 | steps: 107 | - uses: actions/checkout@v4 108 | 109 | - name: Install Rust 110 | uses: dtolnay/rust-toolchain@master 111 | with: 112 | components: clippy 113 | toolchain: ${{needs.toolchain.outputs.toolchain}} 114 | 115 | - name: Install just 116 | uses: taiki-e/install-action@v2 117 | with: 118 | tool: just 119 | 120 | - name: Install protoc 121 | uses: arduino/setup-protoc@v3 122 | with: 123 | repo-token: ${{ secrets.GITHUB_TOKEN }} 124 | 125 | - uses: Swatinem/rust-cache@v2 126 | 127 | - name: just lint 128 | run: | 129 | rustup override set ${{needs.toolchain.outputs.toolchain}} 130 | just lint 131 | 132 | test: 133 | runs-on: ubuntu-latest 134 | needs: [toolchain, check, fmt-check] 135 | steps: 136 | - uses: actions/checkout@v4 137 | 138 | - name: Install Rust 139 | uses: dtolnay/rust-toolchain@master 140 | with: 141 | toolchain: ${{needs.toolchain.outputs.toolchain}} 142 | 143 | - name: Install just 144 | uses: taiki-e/install-action@v2 145 | with: 146 | tool: just 147 | 148 | - name: Install protoc 149 | uses: arduino/setup-protoc@v3 150 | with: 151 | repo-token: ${{ secrets.GITHUB_TOKEN }} 152 | 153 | - uses: Swatinem/rust-cache@v2 154 | 155 | - name: just test 156 | run: | 157 | rustup override set ${{needs.toolchain.outputs.toolchain}} 158 | just test 159 | 160 | dependabot: 161 | runs-on: ubuntu-latest 162 | needs: [lint, test] 163 | if: github.event_name == 'pull_request' && github.actor == 'dependabot[bot]' 164 | permissions: 165 | contents: write 166 | pull-requests: write 167 | steps: 168 | - name: approve 169 | run: gh pr review --approve "$PR_URL" 170 | env: 171 | PR_URL: ${{github.event.pull_request.html_url}} 172 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 173 | 174 | - name: merge 175 | run: gh pr merge --auto --squash "$PR_URL" 176 | env: 177 | PR_URL: ${{github.event.pull_request.html_url}} 178 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 179 | -------------------------------------------------------------------------------- /.github/workflows/release-backend.yml: -------------------------------------------------------------------------------- 1 | name: Release backend 2 | 3 | on: 4 | push: 5 | tags: 6 | - hello-tracing-backend/v* 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | toolchain: 14 | runs-on: ubuntu-latest 15 | env: 16 | nightly: ${{(github.event.inputs.nightly == 'true' || github.event_name == 'schedule') && 'true' || ''}} 17 | outputs: 18 | toolchain: ${{steps.set_toolchain.outputs.toolchain}} 19 | nightly_toolchain: ${{steps.set_toolchain.outputs.nightly_toolchain}} 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Set toolchain 23 | id: set_toolchain 24 | run: | 25 | toolchain=$(grep channel rust-toolchain.toml | sed -r 's/channel = "(.*)"/\1/') 26 | echo "using toolchain $toolchain" 27 | echo "toolchain=$toolchain" >> "$GITHUB_OUTPUT" 28 | if [[ $toolchain =~ ^nightly.* ]]; then 29 | echo "using nightly_toolchain $toolchain" 30 | echo "nightly_toolchain=$toolchain" >> "$GITHUB_OUTPUT" 31 | else 32 | echo "using nightly_toolchain nightly" 33 | echo "nightly_toolchain=nightly" >> "$GITHUB_OUTPUT" 34 | fi 35 | 36 | release: 37 | runs-on: ubuntu-latest 38 | needs: [toolchain] 39 | steps: 40 | - name: Login to DockerHub 41 | uses: docker/login-action@v3 42 | with: 43 | username: ${{ secrets.DOCKERHUB_USERNAME }} 44 | password: ${{ secrets.DOCKERHUB_TOKEN }} 45 | 46 | - name: Prepare metadata (tags, labels) for Docker 47 | id: meta 48 | uses: docker/metadata-action@v5 49 | with: 50 | images: hseeberger/hello-tracing-backend 51 | tags: | 52 | type=match,pattern=hello-tracing-backend/v(\d.\d.\d),group=1 53 | type=sha,prefix=,suffix=,format=long 54 | type=raw,value=latest,enable={{is_default_branch}} 55 | 56 | - name: Set up Docker Buildx 57 | uses: docker/setup-buildx-action@v3 58 | 59 | - name: Docker build and push hello-tracing-backend 60 | uses: docker/build-push-action@v6 61 | with: 62 | push: true 63 | file: hello-tracing-backend/Dockerfile 64 | build-args: RUST_VERSION=${{needs.toolchain.outputs.toolchain}} 65 | platforms: linux/amd64,linux/arm64 66 | tags: ${{ steps.meta.outputs.tags }} 67 | labels: ${{ steps.meta.outputs.labels }} 68 | -------------------------------------------------------------------------------- /.github/workflows/release-gateway.yml: -------------------------------------------------------------------------------- 1 | name: Release gateway 2 | 3 | on: 4 | push: 5 | tags: 6 | - hello-tracing-gateway/v* 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | toolchain: 14 | runs-on: ubuntu-latest 15 | env: 16 | nightly: ${{(github.event.inputs.nightly == 'true' || github.event_name == 'schedule') && 'true' || ''}} 17 | outputs: 18 | toolchain: ${{steps.set_toolchain.outputs.toolchain}} 19 | nightly_toolchain: ${{steps.set_toolchain.outputs.nightly_toolchain}} 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Set toolchain 23 | id: set_toolchain 24 | run: | 25 | toolchain=$(grep channel rust-toolchain.toml | sed -r 's/channel = "(.*)"/\1/') 26 | echo "using toolchain $toolchain" 27 | echo "toolchain=$toolchain" >> "$GITHUB_OUTPUT" 28 | if [[ $toolchain =~ ^nightly.* ]]; then 29 | echo "using nightly_toolchain $toolchain" 30 | echo "nightly_toolchain=$toolchain" >> "$GITHUB_OUTPUT" 31 | else 32 | echo "using nightly_toolchain nightly" 33 | echo "nightly_toolchain=nightly" >> "$GITHUB_OUTPUT" 34 | fi 35 | 36 | release: 37 | runs-on: ubuntu-latest 38 | needs: [toolchain] 39 | steps: 40 | - name: Login to DockerHub 41 | uses: docker/login-action@v3 42 | with: 43 | username: ${{ secrets.DOCKERHUB_USERNAME }} 44 | password: ${{ secrets.DOCKERHUB_TOKEN }} 45 | 46 | - name: Prepare metadata (tags, labels) for Docker 47 | id: meta 48 | uses: docker/metadata-action@v5 49 | with: 50 | images: hseeberger/hello-tracing-gateway 51 | tags: | 52 | type=match,pattern=hello-tracing-gateway/v(\d.\d.\d),group=1 53 | type=sha,prefix=,suffix=,format=long 54 | type=raw,value=latest,enable={{is_default_branch}} 55 | 56 | - name: Set up Docker Buildx 57 | uses: docker/setup-buildx-action@v3 58 | 59 | - name: Docker build and push hello-tracing-gateway 60 | uses: docker/build-push-action@v6 61 | with: 62 | push: true 63 | file: hello-tracing-gateway/Dockerfile 64 | build-args: RUST_VERSION=${{needs.toolchain.outputs.toolchain}} 65 | platforms: linux/amd64,linux/arm64 66 | tags: ${{ steps.meta.outputs.tags }} 67 | labels: ${{ steps.meta.outputs.labels }} 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.1.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "anyhow" 31 | version = "1.0.98" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 34 | 35 | [[package]] 36 | name = "api-version" 37 | version = "0.3.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "1814b0ba6794ea388d68207f1e53f7e6f5e67a9cba1f235eab04120be0693a94" 40 | dependencies = [ 41 | "axum 0.8.1", 42 | "axum-extra", 43 | "futures", 44 | "regex", 45 | "tower 0.5.2", 46 | "tracing", 47 | "trait-variant", 48 | ] 49 | 50 | [[package]] 51 | name = "assert_matches" 52 | version = "1.5.0" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" 55 | 56 | [[package]] 57 | name = "async-stream" 58 | version = "0.3.6" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" 61 | dependencies = [ 62 | "async-stream-impl", 63 | "futures-core", 64 | "pin-project-lite", 65 | ] 66 | 67 | [[package]] 68 | name = "async-stream-impl" 69 | version = "0.3.6" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" 72 | dependencies = [ 73 | "proc-macro2", 74 | "quote", 75 | "syn", 76 | ] 77 | 78 | [[package]] 79 | name = "async-trait" 80 | version = "0.1.88" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" 83 | dependencies = [ 84 | "proc-macro2", 85 | "quote", 86 | "syn", 87 | ] 88 | 89 | [[package]] 90 | name = "atomic" 91 | version = "0.6.0" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" 94 | dependencies = [ 95 | "bytemuck", 96 | ] 97 | 98 | [[package]] 99 | name = "atomic-waker" 100 | version = "1.1.2" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 103 | 104 | [[package]] 105 | name = "autocfg" 106 | version = "1.4.0" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 109 | 110 | [[package]] 111 | name = "axum" 112 | version = "0.7.9" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" 115 | dependencies = [ 116 | "async-trait", 117 | "axum-core 0.4.5", 118 | "bytes", 119 | "futures-util", 120 | "http", 121 | "http-body", 122 | "http-body-util", 123 | "itoa", 124 | "matchit 0.7.3", 125 | "memchr", 126 | "mime", 127 | "percent-encoding", 128 | "pin-project-lite", 129 | "rustversion", 130 | "serde", 131 | "sync_wrapper", 132 | "tower 0.5.2", 133 | "tower-layer", 134 | "tower-service", 135 | ] 136 | 137 | [[package]] 138 | name = "axum" 139 | version = "0.8.1" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8" 142 | dependencies = [ 143 | "axum-core 0.5.0", 144 | "bytes", 145 | "form_urlencoded", 146 | "futures-util", 147 | "http", 148 | "http-body", 149 | "http-body-util", 150 | "hyper", 151 | "hyper-util", 152 | "itoa", 153 | "matchit 0.8.4", 154 | "memchr", 155 | "mime", 156 | "percent-encoding", 157 | "pin-project-lite", 158 | "rustversion", 159 | "serde", 160 | "serde_json", 161 | "serde_path_to_error", 162 | "serde_urlencoded", 163 | "sync_wrapper", 164 | "tokio", 165 | "tower 0.5.2", 166 | "tower-layer", 167 | "tower-service", 168 | "tracing", 169 | ] 170 | 171 | [[package]] 172 | name = "axum-core" 173 | version = "0.4.5" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" 176 | dependencies = [ 177 | "async-trait", 178 | "bytes", 179 | "futures-util", 180 | "http", 181 | "http-body", 182 | "http-body-util", 183 | "mime", 184 | "pin-project-lite", 185 | "rustversion", 186 | "sync_wrapper", 187 | "tower-layer", 188 | "tower-service", 189 | ] 190 | 191 | [[package]] 192 | name = "axum-core" 193 | version = "0.5.0" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733" 196 | dependencies = [ 197 | "bytes", 198 | "futures-util", 199 | "http", 200 | "http-body", 201 | "http-body-util", 202 | "mime", 203 | "pin-project-lite", 204 | "rustversion", 205 | "sync_wrapper", 206 | "tower-layer", 207 | "tower-service", 208 | "tracing", 209 | ] 210 | 211 | [[package]] 212 | name = "axum-extra" 213 | version = "0.10.0" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "460fc6f625a1f7705c6cf62d0d070794e94668988b1c38111baeec177c715f7b" 216 | dependencies = [ 217 | "axum 0.8.1", 218 | "axum-core 0.5.0", 219 | "bytes", 220 | "futures-util", 221 | "headers", 222 | "http", 223 | "http-body", 224 | "http-body-util", 225 | "mime", 226 | "pin-project-lite", 227 | "serde", 228 | "tower 0.5.2", 229 | "tower-layer", 230 | "tower-service", 231 | ] 232 | 233 | [[package]] 234 | name = "backtrace" 235 | version = "0.3.74" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 238 | dependencies = [ 239 | "addr2line", 240 | "cfg-if", 241 | "libc", 242 | "miniz_oxide", 243 | "object", 244 | "rustc-demangle", 245 | "windows-targets", 246 | ] 247 | 248 | [[package]] 249 | name = "base64" 250 | version = "0.21.7" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 253 | 254 | [[package]] 255 | name = "base64" 256 | version = "0.22.1" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 259 | 260 | [[package]] 261 | name = "bitflags" 262 | version = "2.8.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 265 | 266 | [[package]] 267 | name = "block-buffer" 268 | version = "0.10.4" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 271 | dependencies = [ 272 | "generic-array", 273 | ] 274 | 275 | [[package]] 276 | name = "bumpalo" 277 | version = "3.17.0" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" 280 | 281 | [[package]] 282 | name = "bytemuck" 283 | version = "1.21.0" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" 286 | 287 | [[package]] 288 | name = "byteorder" 289 | version = "1.5.0" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 292 | 293 | [[package]] 294 | name = "bytes" 295 | version = "1.10.0" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" 298 | 299 | [[package]] 300 | name = "cfg-if" 301 | version = "1.0.0" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 304 | 305 | [[package]] 306 | name = "cpufeatures" 307 | version = "0.2.17" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 310 | dependencies = [ 311 | "libc", 312 | ] 313 | 314 | [[package]] 315 | name = "crypto-common" 316 | version = "0.1.6" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 319 | dependencies = [ 320 | "generic-array", 321 | "typenum", 322 | ] 323 | 324 | [[package]] 325 | name = "deranged" 326 | version = "0.4.0" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" 329 | dependencies = [ 330 | "powerfmt", 331 | ] 332 | 333 | [[package]] 334 | name = "digest" 335 | version = "0.10.7" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 338 | dependencies = [ 339 | "block-buffer", 340 | "crypto-common", 341 | ] 342 | 343 | [[package]] 344 | name = "either" 345 | version = "1.13.0" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 348 | 349 | [[package]] 350 | name = "equivalent" 351 | version = "1.0.1" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 354 | 355 | [[package]] 356 | name = "errno" 357 | version = "0.3.10" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 360 | dependencies = [ 361 | "libc", 362 | "windows-sys 0.59.0", 363 | ] 364 | 365 | [[package]] 366 | name = "fastrand" 367 | version = "2.3.0" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 370 | 371 | [[package]] 372 | name = "figment" 373 | version = "0.10.19" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" 376 | dependencies = [ 377 | "atomic", 378 | "pear", 379 | "serde", 380 | "serde_yaml", 381 | "uncased", 382 | "version_check", 383 | ] 384 | 385 | [[package]] 386 | name = "fixedbitset" 387 | version = "0.5.7" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" 390 | 391 | [[package]] 392 | name = "fnv" 393 | version = "1.0.7" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 396 | 397 | [[package]] 398 | name = "form_urlencoded" 399 | version = "1.2.1" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 402 | dependencies = [ 403 | "percent-encoding", 404 | ] 405 | 406 | [[package]] 407 | name = "futures" 408 | version = "0.3.31" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 411 | dependencies = [ 412 | "futures-channel", 413 | "futures-core", 414 | "futures-executor", 415 | "futures-io", 416 | "futures-sink", 417 | "futures-task", 418 | "futures-util", 419 | ] 420 | 421 | [[package]] 422 | name = "futures-channel" 423 | version = "0.3.31" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 426 | dependencies = [ 427 | "futures-core", 428 | "futures-sink", 429 | ] 430 | 431 | [[package]] 432 | name = "futures-core" 433 | version = "0.3.31" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 436 | 437 | [[package]] 438 | name = "futures-executor" 439 | version = "0.3.31" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 442 | dependencies = [ 443 | "futures-core", 444 | "futures-task", 445 | "futures-util", 446 | ] 447 | 448 | [[package]] 449 | name = "futures-io" 450 | version = "0.3.31" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 453 | 454 | [[package]] 455 | name = "futures-macro" 456 | version = "0.3.31" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 459 | dependencies = [ 460 | "proc-macro2", 461 | "quote", 462 | "syn", 463 | ] 464 | 465 | [[package]] 466 | name = "futures-sink" 467 | version = "0.3.31" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 470 | 471 | [[package]] 472 | name = "futures-task" 473 | version = "0.3.31" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 476 | 477 | [[package]] 478 | name = "futures-util" 479 | version = "0.3.31" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 482 | dependencies = [ 483 | "futures-channel", 484 | "futures-core", 485 | "futures-io", 486 | "futures-macro", 487 | "futures-sink", 488 | "futures-task", 489 | "memchr", 490 | "pin-project-lite", 491 | "pin-utils", 492 | "slab", 493 | ] 494 | 495 | [[package]] 496 | name = "generic-array" 497 | version = "0.14.7" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 500 | dependencies = [ 501 | "typenum", 502 | "version_check", 503 | ] 504 | 505 | [[package]] 506 | name = "getrandom" 507 | version = "0.2.15" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 510 | dependencies = [ 511 | "cfg-if", 512 | "libc", 513 | "wasi 0.11.0+wasi-snapshot-preview1", 514 | ] 515 | 516 | [[package]] 517 | name = "getrandom" 518 | version = "0.3.1" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" 521 | dependencies = [ 522 | "cfg-if", 523 | "libc", 524 | "wasi 0.13.3+wasi-0.2.2", 525 | "windows-targets", 526 | ] 527 | 528 | [[package]] 529 | name = "gimli" 530 | version = "0.31.1" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 533 | 534 | [[package]] 535 | name = "glob" 536 | version = "0.3.2" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" 539 | 540 | [[package]] 541 | name = "h2" 542 | version = "0.4.7" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" 545 | dependencies = [ 546 | "atomic-waker", 547 | "bytes", 548 | "fnv", 549 | "futures-core", 550 | "futures-sink", 551 | "http", 552 | "indexmap 2.7.1", 553 | "slab", 554 | "tokio", 555 | "tokio-util", 556 | "tracing", 557 | ] 558 | 559 | [[package]] 560 | name = "hashbrown" 561 | version = "0.12.3" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 564 | 565 | [[package]] 566 | name = "hashbrown" 567 | version = "0.15.2" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 570 | 571 | [[package]] 572 | name = "headers" 573 | version = "0.4.0" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" 576 | dependencies = [ 577 | "base64 0.21.7", 578 | "bytes", 579 | "headers-core", 580 | "http", 581 | "httpdate", 582 | "mime", 583 | "sha1", 584 | ] 585 | 586 | [[package]] 587 | name = "headers-core" 588 | version = "0.3.0" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" 591 | dependencies = [ 592 | "http", 593 | ] 594 | 595 | [[package]] 596 | name = "heck" 597 | version = "0.5.0" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 600 | 601 | [[package]] 602 | name = "hello-tracing-backend" 603 | version = "1.3.6" 604 | dependencies = [ 605 | "anyhow", 606 | "axum 0.8.1", 607 | "hello-tracing-common", 608 | "opentelemetry", 609 | "opentelemetry-otlp", 610 | "prost", 611 | "serde", 612 | "serde_json", 613 | "tokio", 614 | "tonic", 615 | "tonic-build", 616 | "tower 0.5.2", 617 | "tower-http", 618 | "tracing", 619 | "tracing-opentelemetry", 620 | "tracing-subscriber", 621 | "walkdir", 622 | ] 623 | 624 | [[package]] 625 | name = "hello-tracing-common" 626 | version = "1.3.1" 627 | dependencies = [ 628 | "assert_matches", 629 | "axum 0.8.1", 630 | "figment", 631 | "opentelemetry", 632 | "opentelemetry-http", 633 | "opentelemetry-otlp", 634 | "opentelemetry_sdk", 635 | "prost", 636 | "serde", 637 | "serde_json", 638 | "thiserror", 639 | "time", 640 | "tokio", 641 | "tonic", 642 | "tower 0.5.2", 643 | "tracing", 644 | "tracing-opentelemetry", 645 | "tracing-subscriber", 646 | ] 647 | 648 | [[package]] 649 | name = "hello-tracing-gateway" 650 | version = "1.3.6" 651 | dependencies = [ 652 | "anyhow", 653 | "api-version", 654 | "async-trait", 655 | "axum 0.8.1", 656 | "hello-tracing-common", 657 | "opentelemetry", 658 | "opentelemetry-otlp", 659 | "prost", 660 | "serde", 661 | "serde_json", 662 | "tokio", 663 | "tonic", 664 | "tonic-build", 665 | "tower 0.5.2", 666 | "tower-http", 667 | "tracing", 668 | "tracing-opentelemetry", 669 | "tracing-subscriber", 670 | "walkdir", 671 | ] 672 | 673 | [[package]] 674 | name = "http" 675 | version = "1.3.1" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 678 | dependencies = [ 679 | "bytes", 680 | "fnv", 681 | "itoa", 682 | ] 683 | 684 | [[package]] 685 | name = "http-body" 686 | version = "1.0.1" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 689 | dependencies = [ 690 | "bytes", 691 | "http", 692 | ] 693 | 694 | [[package]] 695 | name = "http-body-util" 696 | version = "0.1.2" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 699 | dependencies = [ 700 | "bytes", 701 | "futures-util", 702 | "http", 703 | "http-body", 704 | "pin-project-lite", 705 | ] 706 | 707 | [[package]] 708 | name = "httparse" 709 | version = "1.10.0" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" 712 | 713 | [[package]] 714 | name = "httpdate" 715 | version = "1.0.3" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 718 | 719 | [[package]] 720 | name = "hyper" 721 | version = "1.6.0" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" 724 | dependencies = [ 725 | "bytes", 726 | "futures-channel", 727 | "futures-util", 728 | "h2", 729 | "http", 730 | "http-body", 731 | "httparse", 732 | "httpdate", 733 | "itoa", 734 | "pin-project-lite", 735 | "smallvec", 736 | "tokio", 737 | "want", 738 | ] 739 | 740 | [[package]] 741 | name = "hyper-timeout" 742 | version = "0.5.2" 743 | source = "registry+https://github.com/rust-lang/crates.io-index" 744 | checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" 745 | dependencies = [ 746 | "hyper", 747 | "hyper-util", 748 | "pin-project-lite", 749 | "tokio", 750 | "tower-service", 751 | ] 752 | 753 | [[package]] 754 | name = "hyper-util" 755 | version = "0.1.10" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" 758 | dependencies = [ 759 | "bytes", 760 | "futures-channel", 761 | "futures-util", 762 | "http", 763 | "http-body", 764 | "hyper", 765 | "pin-project-lite", 766 | "socket2", 767 | "tokio", 768 | "tower-service", 769 | "tracing", 770 | ] 771 | 772 | [[package]] 773 | name = "indexmap" 774 | version = "1.9.3" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 777 | dependencies = [ 778 | "autocfg", 779 | "hashbrown 0.12.3", 780 | ] 781 | 782 | [[package]] 783 | name = "indexmap" 784 | version = "2.7.1" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" 787 | dependencies = [ 788 | "equivalent", 789 | "hashbrown 0.15.2", 790 | ] 791 | 792 | [[package]] 793 | name = "inlinable_string" 794 | version = "0.1.15" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" 797 | 798 | [[package]] 799 | name = "itertools" 800 | version = "0.14.0" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" 803 | dependencies = [ 804 | "either", 805 | ] 806 | 807 | [[package]] 808 | name = "itoa" 809 | version = "1.0.14" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 812 | 813 | [[package]] 814 | name = "js-sys" 815 | version = "0.3.77" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 818 | dependencies = [ 819 | "once_cell", 820 | "wasm-bindgen", 821 | ] 822 | 823 | [[package]] 824 | name = "lazy_static" 825 | version = "1.5.0" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 828 | 829 | [[package]] 830 | name = "libc" 831 | version = "0.2.169" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 834 | 835 | [[package]] 836 | name = "linux-raw-sys" 837 | version = "0.4.15" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 840 | 841 | [[package]] 842 | name = "log" 843 | version = "0.4.25" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" 846 | 847 | [[package]] 848 | name = "matchers" 849 | version = "0.1.0" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 852 | dependencies = [ 853 | "regex-automata 0.1.10", 854 | ] 855 | 856 | [[package]] 857 | name = "matchit" 858 | version = "0.7.3" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" 861 | 862 | [[package]] 863 | name = "matchit" 864 | version = "0.8.4" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" 867 | 868 | [[package]] 869 | name = "memchr" 870 | version = "2.7.4" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 873 | 874 | [[package]] 875 | name = "mime" 876 | version = "0.3.17" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 879 | 880 | [[package]] 881 | name = "miniz_oxide" 882 | version = "0.8.4" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" 885 | dependencies = [ 886 | "adler2", 887 | ] 888 | 889 | [[package]] 890 | name = "mio" 891 | version = "1.0.3" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 894 | dependencies = [ 895 | "libc", 896 | "wasi 0.11.0+wasi-snapshot-preview1", 897 | "windows-sys 0.52.0", 898 | ] 899 | 900 | [[package]] 901 | name = "multimap" 902 | version = "0.10.0" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" 905 | 906 | [[package]] 907 | name = "num-conv" 908 | version = "0.1.0" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 911 | 912 | [[package]] 913 | name = "object" 914 | version = "0.36.7" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 917 | dependencies = [ 918 | "memchr", 919 | ] 920 | 921 | [[package]] 922 | name = "once_cell" 923 | version = "1.20.3" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" 926 | 927 | [[package]] 928 | name = "opentelemetry" 929 | version = "0.28.0" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "236e667b670a5cdf90c258f5a55794ec5ac5027e960c224bff8367a59e1e6426" 932 | dependencies = [ 933 | "futures-core", 934 | "futures-sink", 935 | "js-sys", 936 | "pin-project-lite", 937 | "thiserror", 938 | "tracing", 939 | ] 940 | 941 | [[package]] 942 | name = "opentelemetry-http" 943 | version = "0.28.0" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | checksum = "a8863faf2910030d139fb48715ad5ff2f35029fc5f244f6d5f689ddcf4d26253" 946 | dependencies = [ 947 | "async-trait", 948 | "bytes", 949 | "http", 950 | "opentelemetry", 951 | "tracing", 952 | ] 953 | 954 | [[package]] 955 | name = "opentelemetry-otlp" 956 | version = "0.28.0" 957 | source = "registry+https://github.com/rust-lang/crates.io-index" 958 | checksum = "5bef114c6d41bea83d6dc60eb41720eedd0261a67af57b66dd2b84ac46c01d91" 959 | dependencies = [ 960 | "async-trait", 961 | "futures-core", 962 | "http", 963 | "opentelemetry", 964 | "opentelemetry-proto", 965 | "opentelemetry_sdk", 966 | "prost", 967 | "thiserror", 968 | "tokio", 969 | "tonic", 970 | ] 971 | 972 | [[package]] 973 | name = "opentelemetry-proto" 974 | version = "0.28.0" 975 | source = "registry+https://github.com/rust-lang/crates.io-index" 976 | checksum = "56f8870d3024727e99212eb3bb1762ec16e255e3e6f58eeb3dc8db1aa226746d" 977 | dependencies = [ 978 | "opentelemetry", 979 | "opentelemetry_sdk", 980 | "prost", 981 | "tonic", 982 | ] 983 | 984 | [[package]] 985 | name = "opentelemetry_sdk" 986 | version = "0.28.0" 987 | source = "registry+https://github.com/rust-lang/crates.io-index" 988 | checksum = "84dfad6042089c7fc1f6118b7040dc2eb4ab520abbf410b79dc481032af39570" 989 | dependencies = [ 990 | "async-trait", 991 | "futures-channel", 992 | "futures-executor", 993 | "futures-util", 994 | "glob", 995 | "opentelemetry", 996 | "percent-encoding", 997 | "rand", 998 | "serde_json", 999 | "thiserror", 1000 | "tokio", 1001 | "tokio-stream", 1002 | "tracing", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "pear" 1007 | version = "0.2.9" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" 1010 | dependencies = [ 1011 | "inlinable_string", 1012 | "pear_codegen", 1013 | "yansi", 1014 | ] 1015 | 1016 | [[package]] 1017 | name = "pear_codegen" 1018 | version = "0.2.9" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" 1021 | dependencies = [ 1022 | "proc-macro2", 1023 | "proc-macro2-diagnostics", 1024 | "quote", 1025 | "syn", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "percent-encoding" 1030 | version = "2.3.1" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1033 | 1034 | [[package]] 1035 | name = "petgraph" 1036 | version = "0.7.1" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" 1039 | dependencies = [ 1040 | "fixedbitset", 1041 | "indexmap 2.7.1", 1042 | ] 1043 | 1044 | [[package]] 1045 | name = "pin-project" 1046 | version = "1.1.9" 1047 | source = "registry+https://github.com/rust-lang/crates.io-index" 1048 | checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" 1049 | dependencies = [ 1050 | "pin-project-internal", 1051 | ] 1052 | 1053 | [[package]] 1054 | name = "pin-project-internal" 1055 | version = "1.1.9" 1056 | source = "registry+https://github.com/rust-lang/crates.io-index" 1057 | checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" 1058 | dependencies = [ 1059 | "proc-macro2", 1060 | "quote", 1061 | "syn", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "pin-project-lite" 1066 | version = "0.2.16" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1069 | 1070 | [[package]] 1071 | name = "pin-utils" 1072 | version = "0.1.0" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1075 | 1076 | [[package]] 1077 | name = "powerfmt" 1078 | version = "0.2.0" 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" 1080 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1081 | 1082 | [[package]] 1083 | name = "ppv-lite86" 1084 | version = "0.2.20" 1085 | source = "registry+https://github.com/rust-lang/crates.io-index" 1086 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 1087 | dependencies = [ 1088 | "zerocopy", 1089 | ] 1090 | 1091 | [[package]] 1092 | name = "prettyplease" 1093 | version = "0.2.29" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" 1096 | dependencies = [ 1097 | "proc-macro2", 1098 | "syn", 1099 | ] 1100 | 1101 | [[package]] 1102 | name = "proc-macro2" 1103 | version = "1.0.93" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 1106 | dependencies = [ 1107 | "unicode-ident", 1108 | ] 1109 | 1110 | [[package]] 1111 | name = "proc-macro2-diagnostics" 1112 | version = "0.10.1" 1113 | source = "registry+https://github.com/rust-lang/crates.io-index" 1114 | checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" 1115 | dependencies = [ 1116 | "proc-macro2", 1117 | "quote", 1118 | "syn", 1119 | "version_check", 1120 | "yansi", 1121 | ] 1122 | 1123 | [[package]] 1124 | name = "prost" 1125 | version = "0.13.5" 1126 | source = "registry+https://github.com/rust-lang/crates.io-index" 1127 | checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" 1128 | dependencies = [ 1129 | "bytes", 1130 | "prost-derive", 1131 | ] 1132 | 1133 | [[package]] 1134 | name = "prost-build" 1135 | version = "0.13.5" 1136 | source = "registry+https://github.com/rust-lang/crates.io-index" 1137 | checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" 1138 | dependencies = [ 1139 | "heck", 1140 | "itertools", 1141 | "log", 1142 | "multimap", 1143 | "once_cell", 1144 | "petgraph", 1145 | "prettyplease", 1146 | "prost", 1147 | "prost-types", 1148 | "regex", 1149 | "syn", 1150 | "tempfile", 1151 | ] 1152 | 1153 | [[package]] 1154 | name = "prost-derive" 1155 | version = "0.13.5" 1156 | source = "registry+https://github.com/rust-lang/crates.io-index" 1157 | checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" 1158 | dependencies = [ 1159 | "anyhow", 1160 | "itertools", 1161 | "proc-macro2", 1162 | "quote", 1163 | "syn", 1164 | ] 1165 | 1166 | [[package]] 1167 | name = "prost-types" 1168 | version = "0.13.5" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" 1171 | dependencies = [ 1172 | "prost", 1173 | ] 1174 | 1175 | [[package]] 1176 | name = "quote" 1177 | version = "1.0.38" 1178 | source = "registry+https://github.com/rust-lang/crates.io-index" 1179 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 1180 | dependencies = [ 1181 | "proc-macro2", 1182 | ] 1183 | 1184 | [[package]] 1185 | name = "rand" 1186 | version = "0.8.5" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1189 | dependencies = [ 1190 | "libc", 1191 | "rand_chacha", 1192 | "rand_core", 1193 | ] 1194 | 1195 | [[package]] 1196 | name = "rand_chacha" 1197 | version = "0.3.1" 1198 | source = "registry+https://github.com/rust-lang/crates.io-index" 1199 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1200 | dependencies = [ 1201 | "ppv-lite86", 1202 | "rand_core", 1203 | ] 1204 | 1205 | [[package]] 1206 | name = "rand_core" 1207 | version = "0.6.4" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1210 | dependencies = [ 1211 | "getrandom 0.2.15", 1212 | ] 1213 | 1214 | [[package]] 1215 | name = "regex" 1216 | version = "1.11.1" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1219 | dependencies = [ 1220 | "aho-corasick", 1221 | "memchr", 1222 | "regex-automata 0.4.9", 1223 | "regex-syntax 0.8.5", 1224 | ] 1225 | 1226 | [[package]] 1227 | name = "regex-automata" 1228 | version = "0.1.10" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1231 | dependencies = [ 1232 | "regex-syntax 0.6.29", 1233 | ] 1234 | 1235 | [[package]] 1236 | name = "regex-automata" 1237 | version = "0.4.9" 1238 | source = "registry+https://github.com/rust-lang/crates.io-index" 1239 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1240 | dependencies = [ 1241 | "aho-corasick", 1242 | "memchr", 1243 | "regex-syntax 0.8.5", 1244 | ] 1245 | 1246 | [[package]] 1247 | name = "regex-syntax" 1248 | version = "0.6.29" 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" 1250 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 1251 | 1252 | [[package]] 1253 | name = "regex-syntax" 1254 | version = "0.8.5" 1255 | source = "registry+https://github.com/rust-lang/crates.io-index" 1256 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1257 | 1258 | [[package]] 1259 | name = "rustc-demangle" 1260 | version = "0.1.24" 1261 | source = "registry+https://github.com/rust-lang/crates.io-index" 1262 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1263 | 1264 | [[package]] 1265 | name = "rustix" 1266 | version = "0.38.44" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 1269 | dependencies = [ 1270 | "bitflags", 1271 | "errno", 1272 | "libc", 1273 | "linux-raw-sys", 1274 | "windows-sys 0.59.0", 1275 | ] 1276 | 1277 | [[package]] 1278 | name = "rustversion" 1279 | version = "1.0.19" 1280 | source = "registry+https://github.com/rust-lang/crates.io-index" 1281 | checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" 1282 | 1283 | [[package]] 1284 | name = "ryu" 1285 | version = "1.0.19" 1286 | source = "registry+https://github.com/rust-lang/crates.io-index" 1287 | checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" 1288 | 1289 | [[package]] 1290 | name = "same-file" 1291 | version = "1.0.6" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1294 | dependencies = [ 1295 | "winapi-util", 1296 | ] 1297 | 1298 | [[package]] 1299 | name = "serde" 1300 | version = "1.0.219" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 1303 | dependencies = [ 1304 | "serde_derive", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "serde_derive" 1309 | version = "1.0.219" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 1312 | dependencies = [ 1313 | "proc-macro2", 1314 | "quote", 1315 | "syn", 1316 | ] 1317 | 1318 | [[package]] 1319 | name = "serde_json" 1320 | version = "1.0.139" 1321 | source = "registry+https://github.com/rust-lang/crates.io-index" 1322 | checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" 1323 | dependencies = [ 1324 | "itoa", 1325 | "memchr", 1326 | "ryu", 1327 | "serde", 1328 | ] 1329 | 1330 | [[package]] 1331 | name = "serde_path_to_error" 1332 | version = "0.1.16" 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" 1334 | checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" 1335 | dependencies = [ 1336 | "itoa", 1337 | "serde", 1338 | ] 1339 | 1340 | [[package]] 1341 | name = "serde_urlencoded" 1342 | version = "0.7.1" 1343 | source = "registry+https://github.com/rust-lang/crates.io-index" 1344 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1345 | dependencies = [ 1346 | "form_urlencoded", 1347 | "itoa", 1348 | "ryu", 1349 | "serde", 1350 | ] 1351 | 1352 | [[package]] 1353 | name = "serde_yaml" 1354 | version = "0.9.34+deprecated" 1355 | source = "registry+https://github.com/rust-lang/crates.io-index" 1356 | checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" 1357 | dependencies = [ 1358 | "indexmap 2.7.1", 1359 | "itoa", 1360 | "ryu", 1361 | "serde", 1362 | "unsafe-libyaml", 1363 | ] 1364 | 1365 | [[package]] 1366 | name = "sha1" 1367 | version = "0.10.6" 1368 | source = "registry+https://github.com/rust-lang/crates.io-index" 1369 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1370 | dependencies = [ 1371 | "cfg-if", 1372 | "cpufeatures", 1373 | "digest", 1374 | ] 1375 | 1376 | [[package]] 1377 | name = "sharded-slab" 1378 | version = "0.1.7" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1381 | dependencies = [ 1382 | "lazy_static", 1383 | ] 1384 | 1385 | [[package]] 1386 | name = "signal-hook-registry" 1387 | version = "1.4.2" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1390 | dependencies = [ 1391 | "libc", 1392 | ] 1393 | 1394 | [[package]] 1395 | name = "slab" 1396 | version = "0.4.9" 1397 | source = "registry+https://github.com/rust-lang/crates.io-index" 1398 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1399 | dependencies = [ 1400 | "autocfg", 1401 | ] 1402 | 1403 | [[package]] 1404 | name = "smallvec" 1405 | version = "1.13.2" 1406 | source = "registry+https://github.com/rust-lang/crates.io-index" 1407 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1408 | 1409 | [[package]] 1410 | name = "socket2" 1411 | version = "0.5.8" 1412 | source = "registry+https://github.com/rust-lang/crates.io-index" 1413 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 1414 | dependencies = [ 1415 | "libc", 1416 | "windows-sys 0.52.0", 1417 | ] 1418 | 1419 | [[package]] 1420 | name = "syn" 1421 | version = "2.0.98" 1422 | source = "registry+https://github.com/rust-lang/crates.io-index" 1423 | checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" 1424 | dependencies = [ 1425 | "proc-macro2", 1426 | "quote", 1427 | "unicode-ident", 1428 | ] 1429 | 1430 | [[package]] 1431 | name = "sync_wrapper" 1432 | version = "1.0.2" 1433 | source = "registry+https://github.com/rust-lang/crates.io-index" 1434 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1435 | 1436 | [[package]] 1437 | name = "tempfile" 1438 | version = "3.16.0" 1439 | source = "registry+https://github.com/rust-lang/crates.io-index" 1440 | checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" 1441 | dependencies = [ 1442 | "cfg-if", 1443 | "fastrand", 1444 | "getrandom 0.3.1", 1445 | "once_cell", 1446 | "rustix", 1447 | "windows-sys 0.59.0", 1448 | ] 1449 | 1450 | [[package]] 1451 | name = "thiserror" 1452 | version = "2.0.12" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 1455 | dependencies = [ 1456 | "thiserror-impl", 1457 | ] 1458 | 1459 | [[package]] 1460 | name = "thiserror-impl" 1461 | version = "2.0.12" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 1464 | dependencies = [ 1465 | "proc-macro2", 1466 | "quote", 1467 | "syn", 1468 | ] 1469 | 1470 | [[package]] 1471 | name = "thread_local" 1472 | version = "1.1.8" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 1475 | dependencies = [ 1476 | "cfg-if", 1477 | "once_cell", 1478 | ] 1479 | 1480 | [[package]] 1481 | name = "time" 1482 | version = "0.3.41" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" 1485 | dependencies = [ 1486 | "deranged", 1487 | "itoa", 1488 | "num-conv", 1489 | "powerfmt", 1490 | "serde", 1491 | "time-core", 1492 | "time-macros", 1493 | ] 1494 | 1495 | [[package]] 1496 | name = "time-core" 1497 | version = "0.1.4" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" 1500 | 1501 | [[package]] 1502 | name = "time-macros" 1503 | version = "0.2.22" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" 1506 | dependencies = [ 1507 | "num-conv", 1508 | "time-core", 1509 | ] 1510 | 1511 | [[package]] 1512 | name = "tokio" 1513 | version = "1.45.1" 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" 1515 | checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" 1516 | dependencies = [ 1517 | "backtrace", 1518 | "bytes", 1519 | "libc", 1520 | "mio", 1521 | "pin-project-lite", 1522 | "signal-hook-registry", 1523 | "socket2", 1524 | "tokio-macros", 1525 | "windows-sys 0.52.0", 1526 | ] 1527 | 1528 | [[package]] 1529 | name = "tokio-macros" 1530 | version = "2.5.0" 1531 | source = "registry+https://github.com/rust-lang/crates.io-index" 1532 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 1533 | dependencies = [ 1534 | "proc-macro2", 1535 | "quote", 1536 | "syn", 1537 | ] 1538 | 1539 | [[package]] 1540 | name = "tokio-stream" 1541 | version = "0.1.17" 1542 | source = "registry+https://github.com/rust-lang/crates.io-index" 1543 | checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" 1544 | dependencies = [ 1545 | "futures-core", 1546 | "pin-project-lite", 1547 | "tokio", 1548 | ] 1549 | 1550 | [[package]] 1551 | name = "tokio-util" 1552 | version = "0.7.13" 1553 | source = "registry+https://github.com/rust-lang/crates.io-index" 1554 | checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" 1555 | dependencies = [ 1556 | "bytes", 1557 | "futures-core", 1558 | "futures-sink", 1559 | "pin-project-lite", 1560 | "tokio", 1561 | ] 1562 | 1563 | [[package]] 1564 | name = "tonic" 1565 | version = "0.12.3" 1566 | source = "registry+https://github.com/rust-lang/crates.io-index" 1567 | checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" 1568 | dependencies = [ 1569 | "async-stream", 1570 | "async-trait", 1571 | "axum 0.7.9", 1572 | "base64 0.22.1", 1573 | "bytes", 1574 | "h2", 1575 | "http", 1576 | "http-body", 1577 | "http-body-util", 1578 | "hyper", 1579 | "hyper-timeout", 1580 | "hyper-util", 1581 | "percent-encoding", 1582 | "pin-project", 1583 | "prost", 1584 | "socket2", 1585 | "tokio", 1586 | "tokio-stream", 1587 | "tower 0.4.13", 1588 | "tower-layer", 1589 | "tower-service", 1590 | "tracing", 1591 | ] 1592 | 1593 | [[package]] 1594 | name = "tonic-build" 1595 | version = "0.12.3" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" 1598 | dependencies = [ 1599 | "prettyplease", 1600 | "proc-macro2", 1601 | "prost-build", 1602 | "prost-types", 1603 | "quote", 1604 | "syn", 1605 | ] 1606 | 1607 | [[package]] 1608 | name = "tower" 1609 | version = "0.4.13" 1610 | source = "registry+https://github.com/rust-lang/crates.io-index" 1611 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 1612 | dependencies = [ 1613 | "futures-core", 1614 | "futures-util", 1615 | "indexmap 1.9.3", 1616 | "pin-project", 1617 | "pin-project-lite", 1618 | "rand", 1619 | "slab", 1620 | "tokio", 1621 | "tokio-util", 1622 | "tower-layer", 1623 | "tower-service", 1624 | "tracing", 1625 | ] 1626 | 1627 | [[package]] 1628 | name = "tower" 1629 | version = "0.5.2" 1630 | source = "registry+https://github.com/rust-lang/crates.io-index" 1631 | checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 1632 | dependencies = [ 1633 | "futures-core", 1634 | "futures-util", 1635 | "pin-project-lite", 1636 | "sync_wrapper", 1637 | "tokio", 1638 | "tower-layer", 1639 | "tower-service", 1640 | "tracing", 1641 | ] 1642 | 1643 | [[package]] 1644 | name = "tower-http" 1645 | version = "0.6.6" 1646 | source = "registry+https://github.com/rust-lang/crates.io-index" 1647 | checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" 1648 | dependencies = [ 1649 | "bitflags", 1650 | "bytes", 1651 | "http", 1652 | "http-body", 1653 | "pin-project-lite", 1654 | "tower-layer", 1655 | "tower-service", 1656 | "tracing", 1657 | ] 1658 | 1659 | [[package]] 1660 | name = "tower-layer" 1661 | version = "0.3.3" 1662 | source = "registry+https://github.com/rust-lang/crates.io-index" 1663 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 1664 | 1665 | [[package]] 1666 | name = "tower-service" 1667 | version = "0.3.3" 1668 | source = "registry+https://github.com/rust-lang/crates.io-index" 1669 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1670 | 1671 | [[package]] 1672 | name = "tracing" 1673 | version = "0.1.41" 1674 | source = "registry+https://github.com/rust-lang/crates.io-index" 1675 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1676 | dependencies = [ 1677 | "log", 1678 | "pin-project-lite", 1679 | "tracing-attributes", 1680 | "tracing-core", 1681 | ] 1682 | 1683 | [[package]] 1684 | name = "tracing-attributes" 1685 | version = "0.1.28" 1686 | source = "registry+https://github.com/rust-lang/crates.io-index" 1687 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 1688 | dependencies = [ 1689 | "proc-macro2", 1690 | "quote", 1691 | "syn", 1692 | ] 1693 | 1694 | [[package]] 1695 | name = "tracing-core" 1696 | version = "0.1.33" 1697 | source = "registry+https://github.com/rust-lang/crates.io-index" 1698 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1699 | dependencies = [ 1700 | "once_cell", 1701 | "valuable", 1702 | ] 1703 | 1704 | [[package]] 1705 | name = "tracing-opentelemetry" 1706 | version = "0.29.0" 1707 | source = "registry+https://github.com/rust-lang/crates.io-index" 1708 | checksum = "721f2d2569dce9f3dfbbddee5906941e953bfcdf736a62da3377f5751650cc36" 1709 | dependencies = [ 1710 | "js-sys", 1711 | "once_cell", 1712 | "opentelemetry", 1713 | "opentelemetry_sdk", 1714 | "tracing", 1715 | "tracing-core", 1716 | "tracing-subscriber", 1717 | "web-time", 1718 | ] 1719 | 1720 | [[package]] 1721 | name = "tracing-serde" 1722 | version = "0.2.0" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" 1725 | dependencies = [ 1726 | "serde", 1727 | "tracing-core", 1728 | ] 1729 | 1730 | [[package]] 1731 | name = "tracing-subscriber" 1732 | version = "0.3.19" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 1735 | dependencies = [ 1736 | "matchers", 1737 | "once_cell", 1738 | "regex", 1739 | "serde", 1740 | "serde_json", 1741 | "sharded-slab", 1742 | "thread_local", 1743 | "tracing", 1744 | "tracing-core", 1745 | "tracing-serde", 1746 | ] 1747 | 1748 | [[package]] 1749 | name = "trait-variant" 1750 | version = "0.1.2" 1751 | source = "registry+https://github.com/rust-lang/crates.io-index" 1752 | checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" 1753 | dependencies = [ 1754 | "proc-macro2", 1755 | "quote", 1756 | "syn", 1757 | ] 1758 | 1759 | [[package]] 1760 | name = "try-lock" 1761 | version = "0.2.5" 1762 | source = "registry+https://github.com/rust-lang/crates.io-index" 1763 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1764 | 1765 | [[package]] 1766 | name = "typenum" 1767 | version = "1.17.0" 1768 | source = "registry+https://github.com/rust-lang/crates.io-index" 1769 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1770 | 1771 | [[package]] 1772 | name = "uncased" 1773 | version = "0.9.10" 1774 | source = "registry+https://github.com/rust-lang/crates.io-index" 1775 | checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" 1776 | dependencies = [ 1777 | "version_check", 1778 | ] 1779 | 1780 | [[package]] 1781 | name = "unicode-ident" 1782 | version = "1.0.16" 1783 | source = "registry+https://github.com/rust-lang/crates.io-index" 1784 | checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" 1785 | 1786 | [[package]] 1787 | name = "unsafe-libyaml" 1788 | version = "0.2.11" 1789 | source = "registry+https://github.com/rust-lang/crates.io-index" 1790 | checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" 1791 | 1792 | [[package]] 1793 | name = "valuable" 1794 | version = "0.1.1" 1795 | source = "registry+https://github.com/rust-lang/crates.io-index" 1796 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 1797 | 1798 | [[package]] 1799 | name = "version_check" 1800 | version = "0.9.5" 1801 | source = "registry+https://github.com/rust-lang/crates.io-index" 1802 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1803 | 1804 | [[package]] 1805 | name = "walkdir" 1806 | version = "2.5.0" 1807 | source = "registry+https://github.com/rust-lang/crates.io-index" 1808 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 1809 | dependencies = [ 1810 | "same-file", 1811 | "winapi-util", 1812 | ] 1813 | 1814 | [[package]] 1815 | name = "want" 1816 | version = "0.3.1" 1817 | source = "registry+https://github.com/rust-lang/crates.io-index" 1818 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1819 | dependencies = [ 1820 | "try-lock", 1821 | ] 1822 | 1823 | [[package]] 1824 | name = "wasi" 1825 | version = "0.11.0+wasi-snapshot-preview1" 1826 | source = "registry+https://github.com/rust-lang/crates.io-index" 1827 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1828 | 1829 | [[package]] 1830 | name = "wasi" 1831 | version = "0.13.3+wasi-0.2.2" 1832 | source = "registry+https://github.com/rust-lang/crates.io-index" 1833 | checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" 1834 | dependencies = [ 1835 | "wit-bindgen-rt", 1836 | ] 1837 | 1838 | [[package]] 1839 | name = "wasm-bindgen" 1840 | version = "0.2.100" 1841 | source = "registry+https://github.com/rust-lang/crates.io-index" 1842 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 1843 | dependencies = [ 1844 | "cfg-if", 1845 | "once_cell", 1846 | "wasm-bindgen-macro", 1847 | ] 1848 | 1849 | [[package]] 1850 | name = "wasm-bindgen-backend" 1851 | version = "0.2.100" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 1854 | dependencies = [ 1855 | "bumpalo", 1856 | "log", 1857 | "proc-macro2", 1858 | "quote", 1859 | "syn", 1860 | "wasm-bindgen-shared", 1861 | ] 1862 | 1863 | [[package]] 1864 | name = "wasm-bindgen-macro" 1865 | version = "0.2.100" 1866 | source = "registry+https://github.com/rust-lang/crates.io-index" 1867 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 1868 | dependencies = [ 1869 | "quote", 1870 | "wasm-bindgen-macro-support", 1871 | ] 1872 | 1873 | [[package]] 1874 | name = "wasm-bindgen-macro-support" 1875 | version = "0.2.100" 1876 | source = "registry+https://github.com/rust-lang/crates.io-index" 1877 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 1878 | dependencies = [ 1879 | "proc-macro2", 1880 | "quote", 1881 | "syn", 1882 | "wasm-bindgen-backend", 1883 | "wasm-bindgen-shared", 1884 | ] 1885 | 1886 | [[package]] 1887 | name = "wasm-bindgen-shared" 1888 | version = "0.2.100" 1889 | source = "registry+https://github.com/rust-lang/crates.io-index" 1890 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 1891 | dependencies = [ 1892 | "unicode-ident", 1893 | ] 1894 | 1895 | [[package]] 1896 | name = "web-time" 1897 | version = "1.1.0" 1898 | source = "registry+https://github.com/rust-lang/crates.io-index" 1899 | checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 1900 | dependencies = [ 1901 | "js-sys", 1902 | "wasm-bindgen", 1903 | ] 1904 | 1905 | [[package]] 1906 | name = "winapi-util" 1907 | version = "0.1.9" 1908 | source = "registry+https://github.com/rust-lang/crates.io-index" 1909 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1910 | dependencies = [ 1911 | "windows-sys 0.59.0", 1912 | ] 1913 | 1914 | [[package]] 1915 | name = "windows-sys" 1916 | version = "0.52.0" 1917 | source = "registry+https://github.com/rust-lang/crates.io-index" 1918 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1919 | dependencies = [ 1920 | "windows-targets", 1921 | ] 1922 | 1923 | [[package]] 1924 | name = "windows-sys" 1925 | version = "0.59.0" 1926 | source = "registry+https://github.com/rust-lang/crates.io-index" 1927 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1928 | dependencies = [ 1929 | "windows-targets", 1930 | ] 1931 | 1932 | [[package]] 1933 | name = "windows-targets" 1934 | version = "0.52.6" 1935 | source = "registry+https://github.com/rust-lang/crates.io-index" 1936 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1937 | dependencies = [ 1938 | "windows_aarch64_gnullvm", 1939 | "windows_aarch64_msvc", 1940 | "windows_i686_gnu", 1941 | "windows_i686_gnullvm", 1942 | "windows_i686_msvc", 1943 | "windows_x86_64_gnu", 1944 | "windows_x86_64_gnullvm", 1945 | "windows_x86_64_msvc", 1946 | ] 1947 | 1948 | [[package]] 1949 | name = "windows_aarch64_gnullvm" 1950 | version = "0.52.6" 1951 | source = "registry+https://github.com/rust-lang/crates.io-index" 1952 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1953 | 1954 | [[package]] 1955 | name = "windows_aarch64_msvc" 1956 | version = "0.52.6" 1957 | source = "registry+https://github.com/rust-lang/crates.io-index" 1958 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1959 | 1960 | [[package]] 1961 | name = "windows_i686_gnu" 1962 | version = "0.52.6" 1963 | source = "registry+https://github.com/rust-lang/crates.io-index" 1964 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1965 | 1966 | [[package]] 1967 | name = "windows_i686_gnullvm" 1968 | version = "0.52.6" 1969 | source = "registry+https://github.com/rust-lang/crates.io-index" 1970 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1971 | 1972 | [[package]] 1973 | name = "windows_i686_msvc" 1974 | version = "0.52.6" 1975 | source = "registry+https://github.com/rust-lang/crates.io-index" 1976 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1977 | 1978 | [[package]] 1979 | name = "windows_x86_64_gnu" 1980 | version = "0.52.6" 1981 | source = "registry+https://github.com/rust-lang/crates.io-index" 1982 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1983 | 1984 | [[package]] 1985 | name = "windows_x86_64_gnullvm" 1986 | version = "0.52.6" 1987 | source = "registry+https://github.com/rust-lang/crates.io-index" 1988 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1989 | 1990 | [[package]] 1991 | name = "windows_x86_64_msvc" 1992 | version = "0.52.6" 1993 | source = "registry+https://github.com/rust-lang/crates.io-index" 1994 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1995 | 1996 | [[package]] 1997 | name = "wit-bindgen-rt" 1998 | version = "0.33.0" 1999 | source = "registry+https://github.com/rust-lang/crates.io-index" 2000 | checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" 2001 | dependencies = [ 2002 | "bitflags", 2003 | ] 2004 | 2005 | [[package]] 2006 | name = "yansi" 2007 | version = "1.0.1" 2008 | source = "registry+https://github.com/rust-lang/crates.io-index" 2009 | checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" 2010 | 2011 | [[package]] 2012 | name = "zerocopy" 2013 | version = "0.7.35" 2014 | source = "registry+https://github.com/rust-lang/crates.io-index" 2015 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2016 | dependencies = [ 2017 | "byteorder", 2018 | "zerocopy-derive", 2019 | ] 2020 | 2021 | [[package]] 2022 | name = "zerocopy-derive" 2023 | version = "0.7.35" 2024 | source = "registry+https://github.com/rust-lang/crates.io-index" 2025 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2026 | dependencies = [ 2027 | "proc-macro2", 2028 | "quote", 2029 | "syn", 2030 | ] 2031 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "hello-tracing-backend", 4 | "hello-tracing-common", 5 | "hello-tracing-gateway", 6 | ] 7 | resolver = "2" 8 | 9 | [workspace.package] 10 | edition = "2021" 11 | authors = [ "Heiko Seeberger " ] 12 | license = "Apache-2.0" 13 | readme = "README.md" 14 | homepage = "https://github.com/hseeberger/hello-tracing-rs" 15 | repository = "https://github.com/hseeberger/hello-tracing-rs" 16 | documentation = "https://github.com/hseeberger/hello-tracing-rs" 17 | publish = false 18 | 19 | [workspace.dependencies] 20 | anyhow = { version = "1.0" } 21 | assert_matches = { version = "1.5" } 22 | api-version = { version = "0.3" } 23 | async-trait = { version = "0.1" } 24 | axum = { version = "0.8" } 25 | figment = { version = "0.10" } 26 | opentelemetry = { version = "0.28" } 27 | opentelemetry_sdk = { version = "0.28" } 28 | opentelemetry-http = { version = "0.28" } 29 | opentelemetry-otlp = { version = "0.28", default-features = false } 30 | prost = { version = "0.13" } 31 | serde = { version = "1.0" } 32 | serde_json = { version = "1.0" } 33 | time = { version = "0.3" } 34 | thiserror = { version = "2.0" } 35 | tokio = { version = "1" } 36 | tonic = { version = "0.12" } 37 | tonic-build = { version = "0.12" } 38 | tower = { version = "0.5" } 39 | tower-http = { version = "0.6" } 40 | tracing = { version = "0.1", default-features = false } 41 | tracing-opentelemetry = { version = "0.29", default-features = false } 42 | tracing-subscriber = { version = "0.3", default-features = false } 43 | walkdir = { version = "2.5" } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hello-tracing-rs 2 | 3 | Simple dockerized Rust/Axum/toic based tracing demo. 4 | 5 | ## Run the gateway 6 | 7 | From the workspace root directory: 8 | 9 | ``` 10 | just run-gateway 11 | ``` 12 | 13 | ## Run the backend 14 | 15 | From the workspace root directory: 16 | 17 | ``` 18 | just run-backend 19 | ``` 20 | 21 | ## Configure Grafana Agent 22 | 23 | ``` 24 | server: 25 | log_level: warn 26 | 27 | logs: 28 | configs: 29 | - name: default 30 | clients: 31 | - url: https://:@logs-prod-eu-west-0.grafana.net/loki/api/v1/push 32 | positions: 33 | filename: /tmp/positions.yaml 34 | scrape_configs: 35 | - job_name: hello-tracing-rs 36 | static_configs: 37 | - targets: 38 | - localhost 39 | labels: 40 | __path__: /Users/heiko/tmp/hello-tracing-gateway.log 41 | app: hello-tracing-rs 42 | service: hello-tracing-gateway 43 | - targets: 44 | - localhost 45 | labels: 46 | __path__: /Users/heiko/tmp/hello-tracing-backend.log 47 | app: hello-tracing-rs 48 | service: hello-tracing-backend 49 | 50 | traces: 51 | configs: 52 | - name: default 53 | remote_write: 54 | - endpoint: tempo-eu-west-0.grafana.net:443 55 | basic_auth: 56 | username: 57 | password: 58 | receivers: 59 | otlp: 60 | protocols: 61 | grpc: 62 | ``` 63 | ## License ## 64 | 65 | This code is open source software licensed under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0.html). 66 | -------------------------------------------------------------------------------- /hello-tracing-backend/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-tracing-backend" 3 | version = "1.3.6" 4 | description = "hello-tracing-backend" 5 | edition = { workspace = true } 6 | authors = { workspace = true } 7 | license = { workspace = true } 8 | readme = { workspace = true } 9 | homepage = { workspace = true } 10 | repository = { workspace = true } 11 | documentation = { workspace = true } 12 | publish = { workspace = true } 13 | 14 | [dependencies] 15 | hello-tracing-common = { path = "../hello-tracing-common" } 16 | anyhow = { workspace = true } 17 | axum = { workspace = true, features = [ "http2" ] } 18 | opentelemetry = { workspace = true } 19 | opentelemetry-otlp = { workspace = true } 20 | prost = { workspace = true } 21 | serde = { workspace = true } 22 | serde_json = { workspace = true } 23 | tokio = { workspace = true, features = [ "rt-multi-thread", "signal" ] } 24 | tonic = { workspace = true } 25 | tower = { workspace = true } 26 | tower-http = { workspace = true, features = [ "trace" ] } 27 | tracing = { workspace = true } 28 | tracing-opentelemetry = { workspace = true } 29 | tracing-subscriber = { workspace = true } 30 | 31 | [build-dependencies] 32 | anyhow = { workspace = true } 33 | tonic-build = { workspace = true } 34 | walkdir = { workspace = true } 35 | -------------------------------------------------------------------------------- /hello-tracing-backend/Dockerfile: -------------------------------------------------------------------------------- 1 | # ---------- BUILD STAGE ---------- # 2 | 3 | ARG RUST_VERSION 4 | FROM rust:$RUST_VERSION-bookworm AS build_stage 5 | 6 | ARG PROFILE=release 7 | 8 | WORKDIR /build 9 | 10 | # Install protobuf-compiler. 11 | RUN apt-get update && apt-get install -y protobuf-compiler 12 | 13 | COPY ./Cargo.toml ./Cargo.lock ./ 14 | COPY ./rust-toolchain.toml ./ 15 | COPY ./hello-tracing-backend/Cargo.toml ./hello-tracing-backend/ 16 | COPY ./hello-tracing-common/Cargo.toml ./hello-tracing-common/ 17 | COPY ./hello-tracing-gateway/Cargo.toml ./hello-tracing-gateway/ 18 | 19 | RUN mkdir ./hello-tracing-backend/src && \ 20 | echo "fn main() {}" > ./hello-tracing-backend/src/main.rs && \ 21 | mkdir ./hello-tracing-common/src && \ 22 | echo "fn main() {}" > ./hello-tracing-common/src/main.rs && \ 23 | mkdir ./hello-tracing-gateway/src && \ 24 | echo "fn main() {}" > ./hello-tracing-gateway/src/main.rs && \ 25 | find . -path '*/src/*' | xargs touch -t 197001010001 -m 26 | 27 | RUN cargo build -p hello-tracing-backend --locked --profile $PROFILE && \ 28 | find ./target | xargs touch -t 197001010002 -m 29 | 30 | COPY ./ ./ 31 | 32 | RUN cargo build -p hello-tracing-backend --locked --profile $PROFILE && \ 33 | mv ./target/$([ "$PROFILE" = "release" ] && echo "release" || echo "debug")/hello-tracing-backend / 34 | 35 | # ---------- RUNTIME STAGE ---------- # 36 | 37 | FROM debian:bookworm-slim 38 | 39 | RUN adduser --disabled-password --gecos "" --home "/nonexistent" --shell "/sbin/nologin" --no-create-home --uid "10001" appuser 40 | RUN mkdir /var/run/hello-tracing-backend && chown appuser:appuser /var/run/hello-tracing-backend 41 | 42 | COPY --from=build_stage --chown=appuser:appuser /build/hello-tracing-backend/bin/entrypoint.sh /usr/local/bin/ 43 | COPY --from=build_stage --chown=appuser:appuser /hello-tracing-backend /usr/local/bin/ 44 | COPY --from=build_stage --chown=appuser:appuser /build/hello-tracing-backend/config.yaml /opt/hello-tracing-backend/ 45 | 46 | USER appuser 47 | 48 | WORKDIR /opt/hello-tracing-backend 49 | 50 | ENTRYPOINT ["entrypoint.sh"] 51 | -------------------------------------------------------------------------------- /hello-tracing-backend/bin/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | trap 'rm /var/run/hello-tracing-backend/running' EXIT 4 | 5 | touch /var/run/hello-tracing-backend/running 6 | hello-tracing-backend 7 | -------------------------------------------------------------------------------- /hello-tracing-backend/build.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use std::{ 3 | ffi::OsStr, 4 | path::{Path, PathBuf}, 5 | vec, 6 | }; 7 | use walkdir::WalkDir; 8 | 9 | const PROTOS: &str = "proto"; 10 | 11 | fn main() -> Result<()> { 12 | let protos = list_protos(Path::new(PROTOS))?; 13 | tonic_build::configure() 14 | .build_client(false) 15 | .compile_protos(&protos, &[PROTOS]) 16 | .context("compile protos") 17 | } 18 | 19 | fn list_protos(dir: &Path) -> Result> { 20 | WalkDir::new(dir) 21 | .into_iter() 22 | .try_fold(vec![], |mut protos, entry| { 23 | let entry = entry.context("read proto file")?; 24 | let path = entry.path(); 25 | if path.extension().and_then(OsStr::to_str) == Some("proto") { 26 | protos.push(path.to_path_buf()); 27 | } 28 | Ok(protos) 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /hello-tracing-backend/config.yaml: -------------------------------------------------------------------------------- 1 | api: 2 | address: "0.0.0.0" 3 | port: 8080 4 | 5 | telemetry: 6 | tracing: 7 | enabled: true 8 | service_name: "hello-tracing-backend" 9 | otlp_exporter_endpoint: "http://localhost:4317" 10 | -------------------------------------------------------------------------------- /hello-tracing-backend/k8s/deploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage() { 4 | echo "Deploy to k8s" 5 | echo " -c Context for kubectl" 6 | echo " -v Version of the Docker image, i.e. the value of the tag" 7 | echo " -h Print usage instructions" 8 | } 9 | 10 | while getopts "v:c:h" opt; do 11 | case $opt in 12 | c) 13 | KUBECTL_CONTEXT=$OPTARG 14 | ;; 15 | v) 16 | VERSION=$OPTARG 17 | ;; 18 | h) 19 | usage 20 | exit 0 21 | ;; 22 | esac 23 | done 24 | 25 | if [ -z "$VERSION" ]; then 26 | VERSION=$(git tag | grep hello-tracing-backend/v | sed -e "s/^hello-tracing-backend\/v//" | sort --version-sort -r | head -1) 27 | if [ -z "$VERSION" ]; then 28 | echo "ERROR: cannot determine version" >&2 29 | exit 1 30 | fi 31 | fi 32 | export VERSION 33 | echo "Deploying version $VERSION" 34 | 35 | current_dir=$(pwd) 36 | cd $(dirname $0) 37 | kustomize build | envsubst | kubectl apply -f - 38 | cd $current_dir 39 | -------------------------------------------------------------------------------- /hello-tracing-backend/k8s/hello-tracing-backend.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: hello-tracing-backend-grpc 5 | namespace: hello-tracing 6 | spec: 7 | selector: 8 | app: hello-tracing-backend 9 | ports: 10 | - name: grpc 11 | port: 80 12 | targetPort: grpc 13 | 14 | --- 15 | apiVersion: apps/v1 16 | kind: Deployment 17 | metadata: 18 | name: hello-tracing-backend 19 | namespace: hello-tracing 20 | spec: 21 | replicas: 2 22 | selector: 23 | matchLabels: 24 | app: hello-tracing-backend 25 | template: 26 | metadata: 27 | name: hello-tracing-backend 28 | namespace: hello-tracing 29 | labels: 30 | app: hello-tracing-backend 31 | spec: 32 | containers: 33 | - name: hello-tracing-backend 34 | image: hseeberger/hello-tracing-backend:latest 35 | imagePullPolicy: IfNotPresent 36 | ports: 37 | - name: grpc 38 | containerPort: 8080 39 | resources: 40 | requests: 41 | cpu: 25m 42 | memory: 25Mi 43 | limits: 44 | cpu: 100m 45 | memory: 100Mi 46 | # readinessProbe: 47 | # grpc: 48 | # port: 8080 49 | env: 50 | - name: RUST_LOG 51 | value: hello_tracing_backend=debug,hello_tracing_common=debug,info 52 | - name: HOST_IP 53 | valueFrom: 54 | fieldRef: 55 | fieldPath: status.hostIP 56 | - name: APP__TRACING__OTLP_EXPORTER_ENDPOINT 57 | value: http://$(HOST_IP):4317 58 | -------------------------------------------------------------------------------- /hello-tracing-backend/k8s/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - hello-tracing-backend.yaml 5 | images: 6 | - name: hseeberger/hello-tracing-backend 7 | newTag: $VERSION 8 | -------------------------------------------------------------------------------- /hello-tracing-backend/proto/hello-tracing-backend-v0.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package hello_tracing_backend_v0; 3 | 4 | service Hello { rpc Hello(HelloRequest) returns (HelloResponse); } 5 | 6 | message HelloRequest {} 7 | 8 | message HelloResponse { 9 | // Not calling it `message`, because it will interfere tracing `message`s. 10 | string text = 1; 11 | } 12 | -------------------------------------------------------------------------------- /hello-tracing-backend/src/api.rs: -------------------------------------------------------------------------------- 1 | mod v0; 2 | 3 | use anyhow::{Context, Result}; 4 | use axum::http::Request; 5 | use hello_tracing_common::otel::{accept_trace, record_trace_id}; 6 | use serde::Deserialize; 7 | use std::net::IpAddr; 8 | use tokio::signal::unix::{signal, SignalKind}; 9 | use tonic::transport::Server; 10 | use tower::ServiceBuilder; 11 | use tower_http::trace::TraceLayer; 12 | use tracing::{field, info_span, Span}; 13 | 14 | #[derive(Debug, Clone, Deserialize)] 15 | pub struct Config { 16 | address: IpAddr, 17 | port: u16, 18 | } 19 | 20 | pub async fn serve(config: Config) -> Result<()> { 21 | let Config { address, port } = config; 22 | 23 | let app = Server::builder() 24 | .layer( 25 | ServiceBuilder::new() 26 | .layer(TraceLayer::new_for_grpc().make_span_with(make_span)) 27 | .map_request(accept_trace) 28 | .map_request(record_trace_id), 29 | ) 30 | .add_service(v0::hello()); 31 | 32 | app.serve_with_shutdown((address, port).into(), shutdown_signal()) 33 | .await 34 | .context("run server") 35 | } 36 | 37 | fn make_span(request: &Request) -> Span { 38 | let headers = request.headers(); 39 | info_span!("incoming request", ?headers, trace_id = field::Empty) 40 | } 41 | 42 | async fn shutdown_signal() { 43 | signal(SignalKind::terminate()) 44 | .expect("install SIGTERM handler") 45 | .recv() 46 | .await; 47 | } 48 | -------------------------------------------------------------------------------- /hello-tracing-backend/src/api/v0.rs: -------------------------------------------------------------------------------- 1 | mod proto { 2 | tonic::include_proto!("hello_tracing_backend_v0"); 3 | } 4 | 5 | use self::proto::{ 6 | hello_server::{Hello, HelloServer}, 7 | HelloRequest, HelloResponse, 8 | }; 9 | use std::sync::atomic::{AtomicBool, Ordering}; 10 | use tonic::{Request, Response, Status}; 11 | use tracing::{debug, instrument}; 12 | 13 | const TEXTS: [&str; 2] = [ 14 | "Hello, I'm a tracing demo!", 15 | "Hello, I'm built with Rust, Axum and tonic!", 16 | ]; 17 | 18 | pub fn hello() -> HelloServer { 19 | HelloServer::new(HelloService(AtomicBool::default())) 20 | } 21 | 22 | pub struct HelloService(AtomicBool); 23 | 24 | #[tonic::async_trait] 25 | impl Hello for HelloService { 26 | #[instrument(name = "hello-handler", skip(self, _request))] 27 | async fn hello( 28 | &self, 29 | _request: Request, 30 | ) -> Result, Status> { 31 | // Toggle text index. 32 | let previous = self.0.load(Ordering::Acquire); 33 | let current = !previous; 34 | self.0.store(current, Ordering::Release); 35 | 36 | // Get text for this response. 37 | let text = if current { TEXTS[0] } else { TEXTS[1] }; 38 | let text = text.to_string(); 39 | debug!(text, "answering"); 40 | 41 | Ok(Response::new(HelloResponse { text })) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /hello-tracing-backend/src/config.rs: -------------------------------------------------------------------------------- 1 | use crate::api; 2 | use hello_tracing_common::telemetry; 3 | use serde::Deserialize; 4 | 5 | /// The main configuration hosting the application specific [Config] and the [telemetry::Config]. 6 | #[derive(Debug, Clone, Deserialize)] 7 | pub struct MainConfig { 8 | #[serde(flatten)] 9 | pub config: Config, 10 | 11 | #[serde(rename = "telemetry")] 12 | pub telemetry_config: telemetry::Config, 13 | } 14 | 15 | /// The application sepcific configuration. 16 | #[derive(Debug, Clone, Deserialize)] 17 | pub struct Config { 18 | #[serde(rename = "api")] 19 | pub api_config: api::Config, 20 | } 21 | -------------------------------------------------------------------------------- /hello-tracing-backend/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod api; 2 | mod config; 3 | 4 | use crate::config::{Config, MainConfig}; 5 | use anyhow::{Context, Result}; 6 | use hello_tracing_common::{config::ConfigExt, error::log_error, telemetry}; 7 | use std::panic; 8 | use tracing::{error, info}; 9 | 10 | /// The entry point into the application. 11 | pub async fn main() -> Result<()> { 12 | // Load configuration first, because needed for tracing initialization. 13 | let MainConfig { 14 | config, 15 | telemetry_config, 16 | } = MainConfig::load() 17 | .context("load configuration") 18 | .inspect_err(log_error)?; 19 | 20 | // Initialize tracing. 21 | telemetry::init(telemetry_config).inspect_err(log_error)?; 22 | 23 | // Replace the default panic hook with one that uses structured logging at ERROR level. 24 | panic::set_hook(Box::new(|panic| error!(%panic, "process panicked"))); 25 | 26 | // Run and log any error. 27 | run(config).await.inspect_err(|error| { 28 | error!( 29 | error = format!("{error:#}"), 30 | backtrace = %error.backtrace(), 31 | "process exited with ERROR" 32 | ) 33 | }) 34 | } 35 | 36 | async fn run(config: Config) -> Result<()> { 37 | info!(?config, "starting"); 38 | 39 | let Config { api_config } = config; 40 | 41 | api::serve(api_config).await 42 | } 43 | -------------------------------------------------------------------------------- /hello-tracing-backend/src/main.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() { 3 | // Error logging already happens in `hello_tracing_backend::main`. 4 | let _ = hello_tracing_backend::main().await; 5 | } 6 | -------------------------------------------------------------------------------- /hello-tracing-common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-tracing-common" 3 | version = "1.3.1" 4 | description = "hello-tracing-backend" 5 | edition = { workspace = true } 6 | authors = { workspace = true } 7 | license = { workspace = true } 8 | readme = { workspace = true } 9 | homepage = { workspace = true } 10 | repository = { workspace = true } 11 | documentation = { workspace = true } 12 | publish = { workspace = true } 13 | 14 | [dependencies] 15 | axum = { workspace = true } 16 | figment = { workspace = true, features = [ "env", "yaml" ] } 17 | opentelemetry = { workspace = true } 18 | opentelemetry-http = { workspace = true } 19 | opentelemetry_sdk = { workspace = true, features = [ "rt-tokio" ] } 20 | opentelemetry-otlp = { workspace = true, default-features = false, features = [ "trace", "grpc-tonic" ] } 21 | prost = { workspace = true } 22 | serde = { workspace = true, features = [ "derive" ] } 23 | serde_json = { workspace = true } 24 | thiserror = { workspace = true } 25 | time = { workspace = true, features = [ "formatting" ] } 26 | tokio = { workspace = true } 27 | tonic = { workspace = true } 28 | tower = { workspace = true } 29 | tracing = { workspace = true } 30 | tracing-opentelemetry = { workspace = true } 31 | tracing-subscriber = { workspace = true, features = [ "env-filter", "fmt", "json" ] } 32 | 33 | [dev-dependencies] 34 | assert_matches = { workspace = true } 35 | -------------------------------------------------------------------------------- /hello-tracing-common/config.yaml: -------------------------------------------------------------------------------- 1 | # Just for testing purposes! 2 | 3 | telemetry: 4 | tracing: 5 | enabled: false 6 | service_name: "test2" 7 | otlp_exporter_endpoint: "http://localhost:4317" 8 | -------------------------------------------------------------------------------- /hello-tracing-common/src/config.rs: -------------------------------------------------------------------------------- 1 | use figment::{ 2 | providers::{Env, Format, Yaml}, 3 | Figment, 4 | }; 5 | use serde::Deserialize; 6 | use std::env; 7 | 8 | const CONFIG_FILE: &str = "CONFIG_FILE"; 9 | 10 | /// Extension methods for "configuration structs" which can be deserialized. 11 | pub trait ConfigExt 12 | where 13 | Self: for<'de> Deserialize<'de>, 14 | { 15 | /// Load the configuration from the file at the value of the `CONFIG_FILE` environment variable 16 | /// or `config.yaml` by default, with an overlay provided by environment variables prefixed with 17 | /// `"APP__"` and split/nested via `"__"`. 18 | fn load() -> Result { 19 | let config_file = env::var(CONFIG_FILE) 20 | .map(Yaml::file_exact) 21 | .unwrap_or(Yaml::file_exact("config.yaml")); 22 | 23 | let config = Figment::new() 24 | .merge(config_file) 25 | .merge(Env::prefixed("APP__").split("__")) 26 | .extract()?; 27 | 28 | Ok(config) 29 | } 30 | } 31 | 32 | impl ConfigExt for T where T: for<'de> Deserialize<'de> {} 33 | 34 | #[cfg(test)] 35 | mod tests { 36 | use crate::{ 37 | config::{ConfigExt, CONFIG_FILE}, 38 | telemetry, 39 | }; 40 | use assert_matches::assert_matches; 41 | use serde::Deserialize; 42 | use std::env; 43 | 44 | #[test] 45 | fn test_load() { 46 | env::set_var("APP__FOO", "foo"); 47 | 48 | let config = Config::load(); 49 | assert_matches!( 50 | config, 51 | Ok(Config { 52 | foo, 53 | telemetry_config: telemetry::Config { 54 | tracing_config: telemetry::TracingConfig { 55 | enabled, 56 | .. 57 | } 58 | }, 59 | }) if foo == "foo" && !enabled 60 | ); 61 | 62 | env::set_var(CONFIG_FILE, "nonexistent.yaml"); 63 | let config = Config::load(); 64 | assert!(config.is_err()); 65 | } 66 | 67 | #[derive(Debug, Deserialize)] 68 | struct Config { 69 | foo: String, 70 | 71 | #[serde(rename = "telemetry")] 72 | telemetry_config: telemetry::Config, 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /hello-tracing-common/src/error.rs: -------------------------------------------------------------------------------- 1 | use serde_json::json; 2 | use std::{error::Error as StdError, fmt::Display}; 3 | use time::{format_description::well_known::Rfc3339, OffsetDateTime}; 4 | 5 | /// Alias for `async` and `anyhow` friendly dynamic error 6 | /// `Box`. 7 | #[allow(unused)] 8 | pub type BoxError = Box; 9 | 10 | /// Extension methods for types implementing `std::error::Error`. 11 | pub trait StdErrorExt 12 | where 13 | Self: StdError, 14 | { 15 | /// Format this error as a chain of colon separated strings built from this error and all 16 | /// recursive sources. 17 | /// 18 | /// Can be used to log errors like this: 19 | /// 20 | /// `error!(error = error.as_chain(), "cannot do this or that");` 21 | fn as_chain(&self) -> String { 22 | let mut sources = vec![]; 23 | sources.push(self.to_string()); 24 | 25 | let mut source = self.source(); 26 | while let Some(s) = source { 27 | sources.push(s.to_string()); 28 | source = s.source(); 29 | } 30 | 31 | sources.join(": ") 32 | } 33 | } 34 | 35 | impl StdErrorExt for T where T: StdError {} 36 | 37 | /// Log an error before structured logging, e.g. via Tokio Tracing, has been initialized in a 38 | /// similar structured way. 39 | pub fn log_error(error: &T) 40 | where 41 | T: Display + ?Sized, 42 | { 43 | let now = OffsetDateTime::now_utc() 44 | .format(&Rfc3339) 45 | .expect("now can be Rfc3339 formatted"); 46 | 47 | let error = serde_json::to_string(&json!({ 48 | "timestamp": now, 49 | "level": "ERROR", 50 | "message": "process exited with ERROR", 51 | "error": format!("{error:#}") 52 | })); 53 | 54 | // Not using `eprintln!`, because `tracing_subscriber::fmt` (Tokio Tracing) uses stdout. 55 | println!("{}", error.unwrap()); 56 | } 57 | 58 | #[cfg(test)] 59 | mod tests { 60 | use crate::error::StdErrorExt; 61 | use std::num::ParseIntError; 62 | use thiserror::Error; 63 | 64 | #[test] 65 | fn test_as_chain() { 66 | let number = "-1".parse::().map_err(Error); 67 | assert_eq!( 68 | number.unwrap_err().as_chain(), 69 | "error: invalid digit found in string" 70 | ); 71 | } 72 | 73 | #[derive(Debug, Error)] 74 | #[error("error")] 75 | struct Error(#[source] ParseIntError); 76 | } 77 | -------------------------------------------------------------------------------- /hello-tracing-common/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod error; 3 | pub mod otel; 4 | pub mod telemetry; 5 | -------------------------------------------------------------------------------- /hello-tracing-common/src/otel.rs: -------------------------------------------------------------------------------- 1 | pub mod grpc; 2 | 3 | use axum::http::Request; 4 | use opentelemetry::{global, trace::TraceContextExt}; 5 | use opentelemetry_http::HeaderExtractor; 6 | use tracing::Span; 7 | use tracing_opentelemetry::OpenTelemetrySpanExt; 8 | 9 | /// Trace context propagation: associate the current span with the OTel trace of the given request, 10 | /// if any and valid. 11 | pub fn accept_trace(request: Request) -> Request { 12 | // Current context, if no or invalid data is received. 13 | let parent_context = global::get_text_map_propagator(|propagator| { 14 | propagator.extract(&HeaderExtractor(request.headers())) 15 | }); 16 | Span::current().set_parent(parent_context); 17 | 18 | request 19 | } 20 | 21 | /// Recorcd the OTel trace ID of the given request as "trace_id" field in the current span. 22 | pub fn record_trace_id(request: Request) -> Request { 23 | let span = Span::current(); 24 | 25 | let trace_id = span.context().span().span_context().trace_id(); 26 | span.record("trace_id", trace_id.to_string()); 27 | 28 | request 29 | } 30 | -------------------------------------------------------------------------------- /hello-tracing-common/src/otel/grpc.rs: -------------------------------------------------------------------------------- 1 | use crate::error::StdErrorExt; 2 | use opentelemetry::{global, propagation::Injector}; 3 | use tonic::{ 4 | metadata::{MetadataKey, MetadataMap, MetadataValue}, 5 | Request, Status, 6 | }; 7 | use tracing::{warn, Span}; 8 | use tracing_opentelemetry::OpenTelemetrySpanExt; 9 | 10 | /// Trace context propagation: send the trace context by injecting it into the metadata of the given 11 | /// request. 12 | pub fn send_trace(mut request: Request) -> Result, Status> { 13 | global::get_text_map_propagator(|propagator| { 14 | let context = Span::current().context(); 15 | propagator.inject_context(&context, &mut MetadataInjector(request.metadata_mut())) 16 | }); 17 | 18 | Ok(request) 19 | } 20 | 21 | struct MetadataInjector<'a>(&'a mut MetadataMap); 22 | 23 | impl Injector for MetadataInjector<'_> { 24 | fn set(&mut self, key: &str, value: String) { 25 | match MetadataKey::from_bytes(key.as_bytes()) { 26 | Ok(key) => match MetadataValue::try_from(&value) { 27 | Ok(value) => { 28 | self.0.insert(key, value); 29 | } 30 | 31 | Err(error) => warn!(value, error = error.as_chain(), "parse metadata value"), 32 | }, 33 | 34 | Err(error) => warn!(key, error = error.as_chain(), "parse metadata key"), 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /hello-tracing-common/src/telemetry.rs: -------------------------------------------------------------------------------- 1 | use opentelemetry::trace::TracerProvider as _; 2 | use opentelemetry_otlp::{SpanExporter, WithExportConfig}; 3 | use opentelemetry_sdk::{propagation::TraceContextPropagator, trace::SdkTracerProvider, Resource}; 4 | use serde::Deserialize; 5 | use thiserror::Error; 6 | use tracing::error; 7 | use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; 8 | 9 | /// Telemetry (logging, tracing, metrics) configuration. 10 | #[derive(Debug, Clone, Deserialize)] 11 | pub struct Config { 12 | #[serde(rename = "tracing")] 13 | pub tracing_config: TracingConfig, 14 | } 15 | 16 | /// Tracing (as opposed to logging or metrics) configuration. 17 | #[derive(Debug, Clone, Deserialize)] 18 | pub struct TracingConfig { 19 | pub enabled: bool, 20 | pub service_name: String, 21 | pub otlp_exporter_endpoint: String, 22 | } 23 | 24 | /// Error possibly returned by [init]. 25 | #[derive(Debug, Error)] 26 | pub enum Error { 27 | #[error("cannot initialize tracing subscriber")] 28 | TryInitTracing(#[from] tracing_subscriber::util::TryInitError), 29 | 30 | #[error("cannot install OTLP tracer")] 31 | InstallOtlpTracer(#[from] opentelemetry::trace::TraceError), 32 | } 33 | 34 | /// Initialize telemetry: apply an `EnvFilter` using the `RUST_LOG` environment variable to define 35 | /// the log levels, add a formatter layer logging as JSON and an OpenTelemetry layer exporting 36 | /// tracing data if tracing is enabled. 37 | pub fn init(config: Config) -> Result<(), Error> { 38 | let Config { tracing_config } = config; 39 | 40 | let tracing = tracing_subscriber::registry() 41 | .with(EnvFilter::from_default_env()) 42 | .with(tracing_subscriber::fmt::layer().json().flatten_event(true)); 43 | 44 | // The below little code duplication is needed because `tracing` and 45 | // `tracing.with(otlp_layer(config)?)` have different types. 46 | if tracing_config.enabled { 47 | opentelemetry::global::set_text_map_propagator(TraceContextPropagator::new()); 48 | tracing.with(otlp_layer(tracing_config)?).try_init()? 49 | } else { 50 | tracing.try_init()? 51 | } 52 | 53 | Ok(()) 54 | } 55 | 56 | /// Create an OTLP layer exporting tracing data. 57 | fn otlp_layer(config: TracingConfig) -> Result, Error> 58 | where 59 | S: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span>, 60 | { 61 | let exporter = SpanExporter::builder() 62 | .with_tonic() 63 | .with_endpoint(config.otlp_exporter_endpoint) 64 | .build()?; 65 | 66 | let resource = Resource::builder() 67 | .with_service_name(config.service_name) 68 | .build(); 69 | 70 | let provider = SdkTracerProvider::builder() 71 | .with_resource(resource) 72 | .with_batch_exporter(exporter) 73 | .build(); 74 | 75 | let tracer = provider.tracer("config.service_name"); 76 | 77 | Ok(tracing_opentelemetry::layer().with_tracer(tracer)) 78 | } 79 | 80 | #[cfg(test)] 81 | mod tests { 82 | use crate::telemetry::{self, Config, TracingConfig}; 83 | 84 | #[tokio::test] 85 | async fn test_init() { 86 | let tracing_config = TracingConfig { 87 | enabled: true, 88 | service_name: "test".to_string(), 89 | otlp_exporter_endpoint: "http://localhost:4317".to_string(), 90 | }; 91 | let config = Config { tracing_config }; 92 | let result = telemetry::init(config); 93 | assert!(result.is_ok()); 94 | 95 | let tracing_config = TracingConfig { 96 | enabled: false, 97 | service_name: "test".to_string(), 98 | otlp_exporter_endpoint: "http://localhost:4317".to_string(), 99 | }; 100 | let config = Config { tracing_config }; 101 | let result = telemetry::init(config); 102 | assert!(result.is_err()); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /hello-tracing-gateway/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-tracing-gateway" 3 | version = "1.3.6" 4 | description = "hello-tracing-gateway" 5 | edition = { workspace = true } 6 | authors = { workspace = true } 7 | license = { workspace = true } 8 | readme = { workspace = true } 9 | homepage = { workspace = true } 10 | repository = { workspace = true } 11 | documentation = { workspace = true } 12 | publish = { workspace = true } 13 | 14 | [dependencies] 15 | hello-tracing-common = { path = "../hello-tracing-common" } 16 | anyhow = { workspace = true } 17 | api-version = { workspace = true } 18 | async-trait = { workspace = true } 19 | axum = { workspace = true, features = [ "http2" ] } 20 | opentelemetry = { workspace = true } 21 | opentelemetry-otlp = { workspace = true } 22 | prost = { workspace = true } 23 | serde = { workspace = true } 24 | serde_json = { workspace = true } 25 | tokio = { workspace = true, features = [ "rt-multi-thread", "signal" ] } 26 | tonic = { workspace = true } 27 | tower = { workspace = true } 28 | tower-http = { workspace = true, features = [ "trace" ] } 29 | tracing = { workspace = true } 30 | tracing-opentelemetry = { workspace = true } 31 | tracing-subscriber = { workspace = true } 32 | 33 | [build-dependencies] 34 | anyhow = { workspace = true } 35 | tonic-build = { workspace = true } 36 | walkdir = { workspace = true } 37 | -------------------------------------------------------------------------------- /hello-tracing-gateway/Dockerfile: -------------------------------------------------------------------------------- 1 | # ---------- BUILD STAGE ---------- # 2 | 3 | ARG RUST_VERSION 4 | FROM rust:$RUST_VERSION-bookworm AS build_stage 5 | 6 | ARG PROFILE=release 7 | 8 | WORKDIR /build 9 | 10 | # Install protobuf-compiler. 11 | RUN apt-get update && apt-get install -y protobuf-compiler 12 | 13 | COPY ./Cargo.toml ./Cargo.lock ./ 14 | COPY ./rust-toolchain.toml ./ 15 | COPY ./hello-tracing-backend/Cargo.toml ./hello-tracing-backend/ 16 | COPY ./hello-tracing-common/Cargo.toml ./hello-tracing-common/ 17 | COPY ./hello-tracing-gateway/Cargo.toml ./hello-tracing-gateway/ 18 | 19 | RUN mkdir ./hello-tracing-backend/src && \ 20 | echo "fn main() {}" > ./hello-tracing-backend/src/main.rs && \ 21 | mkdir ./hello-tracing-common/src && \ 22 | echo "fn main() {}" > ./hello-tracing-common/src/main.rs && \ 23 | mkdir ./hello-tracing-gateway/src && \ 24 | echo "fn main() {}" > ./hello-tracing-gateway/src/main.rs && \ 25 | find . -path '*/src/*' | xargs touch -t 197001010001 -m 26 | 27 | RUN cargo build -p hello-tracing-gateway --locked --profile $PROFILE && \ 28 | find ./target | xargs touch -t 197001010002 -m 29 | 30 | COPY ./ ./ 31 | 32 | RUN cargo build -p hello-tracing-gateway --locked --profile $PROFILE && \ 33 | mv ./target/$([ "$PROFILE" = "release" ] && echo "release" || echo "debug")/hello-tracing-gateway / 34 | 35 | # ---------- RUNTIME STAGE ---------- # 36 | 37 | FROM debian:bookworm-slim 38 | 39 | RUN adduser --disabled-password --gecos "" --home "/nonexistent" --shell "/sbin/nologin" --no-create-home --uid "10001" appuser 40 | RUN mkdir /var/run/hello-tracing-gateway && chown appuser:appuser /var/run/hello-tracing-gateway 41 | 42 | COPY --from=build_stage --chown=appuser:appuser /build/hello-tracing-gateway/bin/entrypoint.sh /usr/local/bin/ 43 | COPY --from=build_stage --chown=appuser:appuser /hello-tracing-gateway /usr/local/bin/ 44 | COPY --from=build_stage --chown=appuser:appuser /build/hello-tracing-gateway/config.yaml /opt/hello-tracing-gateway/ 45 | 46 | USER appuser 47 | 48 | WORKDIR /opt/hello-tracing-gateway 49 | 50 | ENTRYPOINT ["entrypoint.sh"] 51 | -------------------------------------------------------------------------------- /hello-tracing-gateway/bin/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | trap 'rm /var/run/hello-tracing-gateway/running' EXIT 4 | 5 | touch /var/run/hello-tracing-gateway/running 6 | hello-tracing-gateway 7 | -------------------------------------------------------------------------------- /hello-tracing-gateway/build.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use std::{ 3 | ffi::OsStr, 4 | path::{Path, PathBuf}, 5 | vec, 6 | }; 7 | use walkdir::WalkDir; 8 | 9 | const PROTOS: &str = "proto"; 10 | 11 | fn main() -> Result<()> { 12 | let protos = list_protos(Path::new(PROTOS))?; 13 | tonic_build::configure() 14 | .build_server(false) 15 | .compile_protos(&protos, &[PROTOS]) 16 | .context("compile protos") 17 | } 18 | 19 | fn list_protos(dir: &Path) -> Result> { 20 | WalkDir::new(dir) 21 | .into_iter() 22 | .try_fold(vec![], |mut protos, entry| { 23 | let entry = entry.context("read proto file")?; 24 | let path = entry.path(); 25 | if path.extension().and_then(OsStr::to_str) == Some("proto") { 26 | protos.push(path.to_path_buf()); 27 | } 28 | Ok(protos) 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /hello-tracing-gateway/config.yaml: -------------------------------------------------------------------------------- 1 | api: 2 | address: "0.0.0.0" 3 | port: 8080 4 | 5 | # backend: 6 | # endpoint: ... 7 | 8 | telemetry: 9 | tracing: 10 | enabled: true 11 | service_name: "hello-tracing-gateway" 12 | otlp_exporter_endpoint: "http://localhost:4317" 13 | -------------------------------------------------------------------------------- /hello-tracing-gateway/k8s/deploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage() { 4 | echo "Deploy to k8s" 5 | echo " -c Context for kubectl" 6 | echo " -v Version of the Docker image, i.e. the value of the tag" 7 | echo " -h Print usage instructions" 8 | } 9 | 10 | while getopts "v:c:h" opt; do 11 | case $opt in 12 | c) 13 | KUBECTL_CONTEXT=$OPTARG 14 | ;; 15 | v) 16 | VERSION=$OPTARG 17 | ;; 18 | h) 19 | usage 20 | exit 0 21 | ;; 22 | esac 23 | done 24 | 25 | if [ -z "$VERSION" ]; then 26 | VERSION=$(git tag | grep hello-tracing-gateway/v | sed -e "s/^hello-tracing-gateway\/v//" | sort --version-sort -r | head -1) 27 | if [ -z "$VERSION" ]; then 28 | echo "ERROR: cannot determine version" >&2 29 | exit 1 30 | fi 31 | fi 32 | export VERSION 33 | echo "Deploying version $VERSION" 34 | 35 | current_dir=$(pwd) 36 | cd $(dirname $0) 37 | kustomize build | envsubst | kubectl apply -f - 38 | cd $current_dir 39 | -------------------------------------------------------------------------------- /hello-tracing-gateway/k8s/hello-tracing-gateway.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: hello-tracing-gateway-http 5 | namespace: hello-tracing 6 | spec: 7 | selector: 8 | app: hello-tracing-gateway 9 | ports: 10 | - name: http 11 | port: 80 12 | targetPort: http 13 | 14 | --- 15 | apiVersion: apps/v1 16 | kind: Deployment 17 | metadata: 18 | name: hello-tracing-gateway 19 | namespace: hello-tracing 20 | spec: 21 | replicas: 2 22 | selector: 23 | matchLabels: 24 | app: hello-tracing-gateway 25 | template: 26 | metadata: 27 | name: hello-tracing-gateway 28 | namespace: hello-tracing 29 | labels: 30 | app: hello-tracing-gateway 31 | spec: 32 | containers: 33 | - name: hello-tracing-gateway 34 | image: hseeberger/hello-tracing-gateway:latest 35 | imagePullPolicy: IfNotPresent 36 | ports: 37 | - name: http 38 | containerPort: 8080 39 | resources: 40 | requests: 41 | cpu: 25m 42 | memory: 25Mi 43 | limits: 44 | cpu: 100m 45 | memory: 100Mi 46 | readinessProbe: 47 | httpGet: 48 | path: / 49 | port: http 50 | env: 51 | - name: RUST_LOG 52 | value: hello_tracing_gateway=debug,hello_tracing_common=debug,info 53 | - name: HOST_IP 54 | valueFrom: 55 | fieldRef: 56 | fieldPath: status.hostIP 57 | - name: APP__BACKEND__ENDPOINT 58 | value: http://hello-tracing-backend-grpc:80 59 | - name: APP__TRACING__OTLP_EXPORTER_ENDPOINT 60 | value: http://$(HOST_IP):4317 61 | -------------------------------------------------------------------------------- /hello-tracing-gateway/k8s/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - hello-tracing-gateway.yaml 5 | images: 6 | - name: hseeberger/hello-tracing-gateway 7 | newTag: $VERSION 8 | -------------------------------------------------------------------------------- /hello-tracing-gateway/proto/hello-tracing-backend-v0.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package hello_tracing_backend_v0; 3 | 4 | service Hello { rpc Hello(HelloRequest) returns (HelloResponse); } 5 | 6 | message HelloRequest {} 7 | 8 | message HelloResponse { 9 | // Not calling it `message`, because it will interfere tracing `message`s. 10 | string text = 1; 11 | } 12 | -------------------------------------------------------------------------------- /hello-tracing-gateway/src/api.rs: -------------------------------------------------------------------------------- 1 | mod v0; 2 | 3 | use crate::backend::Backend; 4 | use anyhow::{Context, Result}; 5 | use api_version::{ApiVersionLayer, ApiVersions}; 6 | use axum::{ 7 | body::Body, 8 | http::{Request, StatusCode, Uri}, 9 | response::IntoResponse, 10 | routing::get, 11 | Router, ServiceExt, 12 | }; 13 | use hello_tracing_common::otel::{accept_trace, record_trace_id}; 14 | use serde::Deserialize; 15 | use std::{convert::Infallible, net::IpAddr}; 16 | use tokio::{ 17 | net::TcpListener, 18 | signal::unix::{signal, SignalKind}, 19 | }; 20 | use tower::{Layer, ServiceBuilder}; 21 | use tower_http::trace::TraceLayer; 22 | use tracing::{field, info_span, trace_span, Span}; 23 | 24 | const API_VERSIONS: ApiVersions<1> = ApiVersions::new([0]); 25 | 26 | #[derive(Debug, Clone, Deserialize)] 27 | pub struct Config { 28 | pub address: IpAddr, 29 | pub port: u16, 30 | } 31 | 32 | pub async fn serve(config: Config, backend: Backend) -> Result<()> { 33 | let Config { address, port } = config; 34 | 35 | let app = Router::new() 36 | .route("/", get(ready)) 37 | .nest("/v0", v0::app(backend)) 38 | .layer( 39 | ServiceBuilder::new() 40 | .layer(TraceLayer::new_for_http().make_span_with(make_span)) 41 | .map_request(accept_trace) 42 | .map_request(record_trace_id), 43 | ); 44 | let app = ApiVersionLayer::new(API_VERSIONS, ApiVersionFilter).layer(app); 45 | 46 | let listener = TcpListener::bind((address, port)) 47 | .await 48 | .context("bind TcpListener")?; 49 | axum::serve(listener, app.into_make_service()) 50 | .with_graceful_shutdown(shutdown_signal()) 51 | .await 52 | .context("run server") 53 | } 54 | 55 | #[derive(Clone)] 56 | struct ApiVersionFilter; 57 | 58 | impl api_version::ApiVersionFilter for ApiVersionFilter { 59 | type Error = Infallible; 60 | 61 | async fn should_rewrite(&self, uri: &Uri) -> Result { 62 | Ok(uri.path() != "/") 63 | } 64 | } 65 | 66 | async fn ready() -> impl IntoResponse { 67 | StatusCode::OK 68 | } 69 | 70 | fn make_span(request: &Request) -> Span { 71 | let headers = request.headers(); 72 | 73 | let path = request.uri().path(); 74 | 75 | // Disable (well, silence) spans/traces for root spans (readiness checks). 76 | if path.is_empty() || path == "/" { 77 | trace_span!("incoming request", path, ?headers, trace_id = field::Empty) 78 | } else { 79 | info_span!("incoming request", path, ?headers, trace_id = field::Empty) 80 | } 81 | } 82 | 83 | async fn shutdown_signal() { 84 | signal(SignalKind::terminate()) 85 | .expect("install SIGTERM handler") 86 | .recv() 87 | .await; 88 | } 89 | -------------------------------------------------------------------------------- /hello-tracing-gateway/src/api/v0.rs: -------------------------------------------------------------------------------- 1 | use crate::backend::Backend; 2 | use axum::{extract::State, http::StatusCode, response::IntoResponse, routing::get, Router}; 3 | use tracing::{error, instrument}; 4 | 5 | pub fn app(backend: Backend) -> Router { 6 | let app_state = AppState { backend }; 7 | Router::new() 8 | .route("/hello", get(hello)) 9 | .with_state(app_state) 10 | } 11 | 12 | #[derive(Debug, Clone)] 13 | struct AppState { 14 | backend: Backend, 15 | } 16 | 17 | #[instrument(name = "hello-handler", skip(app_state))] 18 | async fn hello(State(app_state): State) -> impl IntoResponse { 19 | app_state.backend.hello().await.map_err(internal_error) 20 | } 21 | 22 | fn internal_error(error: anyhow::Error) -> StatusCode { 23 | error!( 24 | error = display(format!("{error:#}")), 25 | backtrace = %error.backtrace(), 26 | "internal error" 27 | ); 28 | StatusCode::INTERNAL_SERVER_ERROR 29 | } 30 | -------------------------------------------------------------------------------- /hello-tracing-gateway/src/backend.rs: -------------------------------------------------------------------------------- 1 | mod proto { 2 | tonic::include_proto!("hello_tracing_backend_v0"); 3 | } 4 | 5 | use self::proto::{hello_client::HelloClient, HelloRequest}; 6 | use anyhow::{Context, Result}; 7 | use hello_tracing_common::otel::grpc::send_trace; 8 | use serde::Deserialize; 9 | use std::str::FromStr; 10 | use tonic::transport::Endpoint; 11 | use tracing::{debug, instrument}; 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct Backend { 15 | endpoint: String, 16 | } 17 | 18 | impl Backend { 19 | pub fn new(config: Config) -> Self { 20 | let Config { endpoint } = config; 21 | Self { endpoint } 22 | } 23 | 24 | #[instrument(name = "hello-backend-client", skip(self))] 25 | pub async fn hello(&self) -> Result { 26 | let endpoint = Endpoint::from_str(&self.endpoint) 27 | .with_context(|| format!("create endpoint {}", self.endpoint))?; 28 | let channel = endpoint 29 | .connect() 30 | .await 31 | .with_context(|| format!("connect to endpoint {}", self.endpoint))?; 32 | let mut client = HelloClient::with_interceptor(channel, send_trace); 33 | 34 | let text = client 35 | .hello(HelloRequest {}) 36 | .await 37 | .with_context(|| format!("call Hello on endpoint {}", self.endpoint))? 38 | .into_inner() 39 | .text; 40 | 41 | debug!( 42 | text, 43 | endpoint = self.endpoint, 44 | "received response from Hello" 45 | ); 46 | 47 | Ok(text) 48 | } 49 | } 50 | 51 | #[derive(Debug, Clone, Deserialize)] 52 | pub struct Config { 53 | pub endpoint: String, 54 | } 55 | -------------------------------------------------------------------------------- /hello-tracing-gateway/src/config.rs: -------------------------------------------------------------------------------- 1 | use crate::{api, backend}; 2 | use hello_tracing_common::telemetry; 3 | use serde::Deserialize; 4 | 5 | /// The main configuration hosting the application specific [Config] and the [telemetry::Config]. 6 | #[derive(Debug, Clone, Deserialize)] 7 | pub struct MainConfig { 8 | #[serde(flatten)] 9 | pub config: Config, 10 | 11 | #[serde(rename = "telemetry")] 12 | pub telemetry_config: telemetry::Config, 13 | } 14 | 15 | /// The application sepcific configuration. 16 | #[derive(Debug, Clone, Deserialize)] 17 | pub struct Config { 18 | #[serde(rename = "api")] 19 | pub api_config: api::Config, 20 | 21 | #[serde(rename = "backend")] 22 | pub backend_config: backend::Config, 23 | } 24 | -------------------------------------------------------------------------------- /hello-tracing-gateway/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod api; 2 | mod backend; 3 | mod config; 4 | 5 | use crate::{ 6 | backend::Backend, 7 | config::{Config, MainConfig}, 8 | }; 9 | use anyhow::{Context, Result}; 10 | use hello_tracing_common::{config::ConfigExt, error::log_error, telemetry}; 11 | use std::panic; 12 | use tracing::{error, info}; 13 | 14 | /// The entry point into the application. 15 | pub async fn main() -> Result<()> { 16 | // Load configuration first, because needed for tracing initialization. 17 | let MainConfig { 18 | config, 19 | telemetry_config, 20 | } = MainConfig::load() 21 | .context("load configuration") 22 | .inspect_err(log_error)?; 23 | 24 | // Initialize tracing. 25 | telemetry::init(telemetry_config).inspect_err(log_error)?; 26 | 27 | // Replace the default panic hook with one that uses structured logging at ERROR level. 28 | panic::set_hook(Box::new(|panic| error!(%panic, "process panicked"))); 29 | 30 | // Run and log any error. 31 | run(config).await.inspect_err(|error| { 32 | error!( 33 | error = format!("{error:#}"), 34 | backtrace = %error.backtrace(), 35 | "process exited with ERROR" 36 | ) 37 | }) 38 | } 39 | 40 | async fn run(config: Config) -> Result<()> { 41 | info!(?config, "starting"); 42 | 43 | let Config { 44 | api_config, 45 | backend_config, 46 | } = config; 47 | 48 | let backend = Backend::new(backend_config); 49 | api::serve(api_config, backend).await 50 | } 51 | -------------------------------------------------------------------------------- /hello-tracing-gateway/src/main.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() { 3 | // Error logging already happens in `hello_tracing_gateway::main`. 4 | let _ = hello_tracing_gateway::main().await; 5 | } 6 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | set shell := ["bash", "-uc"] 2 | rust_version := `grep channel rust-toolchain.toml | sed -r 's/channel = "(.*)"/\1/'` 3 | 4 | check: 5 | cargo check -p hello-tracing-common 6 | cargo check -p hello-tracing-backend 7 | cargo check -p hello-tracing-gateway 8 | 9 | fmt toolchain="+nightly": 10 | cargo {{toolchain}} fmt 11 | 12 | fmt-check toolchain="+nightly": 13 | cargo {{toolchain}} fmt --check 14 | 15 | lint: 16 | cargo clippy -p hello-tracing-common --tests --no-deps -- -D warnings 17 | cargo clippy -p hello-tracing-backend --tests --no-deps -- -D warnings 18 | cargo clippy -p hello-tracing-gateway --tests --no-deps -- -D warnings 19 | 20 | test: 21 | cargo test -p hello-tracing-common 22 | cargo test -p hello-tracing-backend 23 | cargo test -p hello-tracing-gateway 24 | 25 | fix: 26 | cargo fix --tests --allow-dirty --allow-staged 27 | 28 | all: check fmt lint test 29 | 30 | run-gateway port="8080" backend_port="8081": 31 | RUST_LOG=hello_tracing_gateway=debug,info \ 32 | CONFIG_FILE=hello-tracing-gateway/config.yaml \ 33 | APP__API__PORT={{port}} \ 34 | APP__BACKEND__ENDPOINT=http://localhost:{{backend_port}} \ 35 | cargo run -p hello-tracing-gateway 36 | 37 | run-backend port="8081": 38 | RUST_LOG=hello_tracing_backend=debug,info \ 39 | CONFIG_FILE=hello-tracing-backend/config.yaml \ 40 | APP__API__PORT={{port}} \ 41 | cargo run -p hello-tracing-backend 42 | 43 | docker tag="latest": 44 | docker build \ 45 | --build-arg "RUST_VERSION={{rust_version}}" \ 46 | -t hseeberger/hello-tracing-backend:{{tag}} \ 47 | -f hello-tracing-backend/Dockerfile \ 48 | . 49 | docker build \ 50 | --build-arg "RUST_VERSION={{rust_version}}" \ 51 | -t hseeberger/hello-tracing-gateway:{{tag}} \ 52 | -f hello-tracing-gateway/Dockerfile \ 53 | . 54 | 55 | release level execute="": 56 | cargo release \ 57 | --exclude hello-tracing-common \ 58 | --sign-commit \ 59 | --sign-tag \ 60 | --no-verify \ 61 | {{level}} {{execute}} 62 | -------------------------------------------------------------------------------- /k8s/hello-tracing.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: hello-tracing 5 | # --- 6 | # apiVersion: networking.k8s.io/v1 7 | # kind: Ingress 8 | # metadata: 9 | # name: hello-tracing 10 | # namespace: hello-tracing 11 | # annotations: 12 | # cert-manager.io/cluster-issuer: letsencrypt 13 | # spec: 14 | # ingressClassName: nginx 15 | # tls: 16 | # - hosts: 17 | # - hello-tracing.heikoseeberger.de 18 | # secretName: hello-tracing-tls 19 | # rules: 20 | # - host: hello-tracing.heikoseeberger.de 21 | # http: 22 | # paths: 23 | # - pathType: Prefix 24 | # path: / 25 | # backend: 26 | # service: 27 | # name: hello-tracing-gateway-http 28 | # port: 29 | # name: http 30 | -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | pre-release-commit-message = "chore({{crate_name}}): release version {{version}}" 2 | tag-message = "release {{crate_name}} version {{version}}" 3 | tag-prefix = "{{crate_name}}/" 4 | consolidate-commits = false 5 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.85.0" 3 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2021" 2 | 3 | max_width = 100 4 | reorder_imports = true 5 | reorder_modules = true 6 | 7 | unstable_features = true 8 | comment_width = 100 9 | imports_granularity = "Crate" 10 | wrap_comments = true 11 | -------------------------------------------------------------------------------- /taplo.toml: -------------------------------------------------------------------------------- 1 | [formatting] 2 | align_entries = true 3 | column_width = 100 4 | allowed_blank_lines = 1 5 | indent_string = " " 6 | array_auto_collapse = false 7 | array_auto_expand = false 8 | compact_arrays = false 9 | --------------------------------------------------------------------------------