├── .editorconfig ├── .envrc ├── .gitignore ├── .vim └── coc-settings.json ├── CODE_OF_CONDUCT.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── demo-screenshot.png ├── flake.lock ├── flake.nix ├── plugin ├── Cargo.toml ├── build.rs ├── cbindgen.toml ├── plugin.cpp └── src │ ├── activity.rs │ ├── exporter.rs │ └── lib.rs └── test.nix /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | max_line_length = 79 9 | 10 | [*.cpp] 11 | # sigh, tabs not supported by fourmolu 12 | indent_style = space 13 | indent_size = 2 14 | 15 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | [[ -f .envrc.local ]] && source ".envrc.local" 2 | use flake 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | result 3 | .envrc.local 4 | plugin/nix_otel_plugin.h 5 | -------------------------------------------------------------------------------- /.vim/coc-settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.cargo.runBuildScripts": false, 3 | "rust-analyzer.server.path": "direnv-ra" 4 | } 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, religion, or sexual identity 11 | and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the 27 | overall community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or 32 | advances of any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email 36 | address, without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | jade AT LFCODE DOT CA. 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series 87 | of actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or 94 | permanent ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within 114 | the community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.0, available at 120 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 121 | 122 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 123 | enforcement ladder](https://github.com/mozilla/diversity). 124 | 125 | [homepage]: https://www.contributor-covenant.org 126 | 127 | For answers to common questions about this code of conduct, see the FAQ at 128 | https://www.contributor-covenant.org/faq. Translations are available at 129 | https://www.contributor-covenant.org/translations. 130 | 131 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.65" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" 10 | 11 | [[package]] 12 | name = "async-stream" 13 | version = "0.3.3" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" 16 | dependencies = [ 17 | "async-stream-impl", 18 | "futures-core", 19 | ] 20 | 21 | [[package]] 22 | name = "async-stream-impl" 23 | version = "0.3.3" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" 26 | dependencies = [ 27 | "proc-macro2", 28 | "quote", 29 | "syn", 30 | ] 31 | 32 | [[package]] 33 | name = "async-trait" 34 | version = "0.1.57" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" 37 | dependencies = [ 38 | "proc-macro2", 39 | "quote", 40 | "syn", 41 | ] 42 | 43 | [[package]] 44 | name = "atty" 45 | version = "0.2.14" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 48 | dependencies = [ 49 | "hermit-abi", 50 | "libc", 51 | "winapi", 52 | ] 53 | 54 | [[package]] 55 | name = "autocfg" 56 | version = "1.1.0" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 59 | 60 | [[package]] 61 | name = "axum" 62 | version = "0.5.16" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "c9e3356844c4d6a6d6467b8da2cffb4a2820be256f50a3a386c9d152bab31043" 65 | dependencies = [ 66 | "async-trait", 67 | "axum-core", 68 | "bitflags", 69 | "bytes", 70 | "futures-util", 71 | "http", 72 | "http-body", 73 | "hyper", 74 | "itoa", 75 | "matchit", 76 | "memchr", 77 | "mime", 78 | "percent-encoding", 79 | "pin-project-lite", 80 | "serde", 81 | "sync_wrapper", 82 | "tokio", 83 | "tower", 84 | "tower-http", 85 | "tower-layer", 86 | "tower-service", 87 | ] 88 | 89 | [[package]] 90 | name = "axum-core" 91 | version = "0.2.8" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "d9f0c0a60006f2a293d82d571f635042a72edf927539b7685bd62d361963839b" 94 | dependencies = [ 95 | "async-trait", 96 | "bytes", 97 | "futures-util", 98 | "http", 99 | "http-body", 100 | "mime", 101 | "tower-layer", 102 | "tower-service", 103 | ] 104 | 105 | [[package]] 106 | name = "base64" 107 | version = "0.13.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 110 | 111 | [[package]] 112 | name = "bitflags" 113 | version = "1.3.2" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 116 | 117 | [[package]] 118 | name = "bumpalo" 119 | version = "3.11.0" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" 122 | 123 | [[package]] 124 | name = "bytes" 125 | version = "1.2.1" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" 128 | 129 | [[package]] 130 | name = "cbindgen" 131 | version = "0.24.3" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb" 134 | dependencies = [ 135 | "clap", 136 | "heck", 137 | "indexmap", 138 | "log", 139 | "proc-macro2", 140 | "quote", 141 | "serde", 142 | "serde_json", 143 | "syn", 144 | "tempfile", 145 | "toml", 146 | ] 147 | 148 | [[package]] 149 | name = "cc" 150 | version = "1.0.68" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" 153 | 154 | [[package]] 155 | name = "cfg-if" 156 | version = "1.0.0" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 159 | 160 | [[package]] 161 | name = "clap" 162 | version = "3.2.22" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" 165 | dependencies = [ 166 | "atty", 167 | "bitflags", 168 | "clap_lex", 169 | "indexmap", 170 | "strsim", 171 | "termcolor", 172 | "textwrap", 173 | ] 174 | 175 | [[package]] 176 | name = "clap_lex" 177 | version = "0.2.4" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" 180 | dependencies = [ 181 | "os_str_bytes", 182 | ] 183 | 184 | [[package]] 185 | name = "core-foundation" 186 | version = "0.9.3" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 189 | dependencies = [ 190 | "core-foundation-sys", 191 | "libc", 192 | ] 193 | 194 | [[package]] 195 | name = "core-foundation-sys" 196 | version = "0.8.3" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 199 | 200 | [[package]] 201 | name = "crossbeam-channel" 202 | version = "0.5.6" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" 205 | dependencies = [ 206 | "cfg-if", 207 | "crossbeam-utils", 208 | ] 209 | 210 | [[package]] 211 | name = "crossbeam-utils" 212 | version = "0.8.12" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" 215 | dependencies = [ 216 | "cfg-if", 217 | ] 218 | 219 | [[package]] 220 | name = "dashmap" 221 | version = "5.4.0" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" 224 | dependencies = [ 225 | "cfg-if", 226 | "hashbrown", 227 | "lock_api", 228 | "once_cell", 229 | "parking_lot_core", 230 | ] 231 | 232 | [[package]] 233 | name = "either" 234 | version = "1.8.0" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" 237 | 238 | [[package]] 239 | name = "fastrand" 240 | version = "1.8.0" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" 243 | dependencies = [ 244 | "instant", 245 | ] 246 | 247 | [[package]] 248 | name = "fixedbitset" 249 | version = "0.4.2" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" 252 | 253 | [[package]] 254 | name = "fnv" 255 | version = "1.0.7" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 258 | 259 | [[package]] 260 | name = "futures" 261 | version = "0.3.24" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" 264 | dependencies = [ 265 | "futures-channel", 266 | "futures-core", 267 | "futures-io", 268 | "futures-sink", 269 | "futures-task", 270 | "futures-util", 271 | ] 272 | 273 | [[package]] 274 | name = "futures-channel" 275 | version = "0.3.24" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" 278 | dependencies = [ 279 | "futures-core", 280 | "futures-sink", 281 | ] 282 | 283 | [[package]] 284 | name = "futures-core" 285 | version = "0.3.24" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" 288 | 289 | [[package]] 290 | name = "futures-executor" 291 | version = "0.3.24" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" 294 | dependencies = [ 295 | "futures-core", 296 | "futures-task", 297 | "futures-util", 298 | ] 299 | 300 | [[package]] 301 | name = "futures-io" 302 | version = "0.3.24" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" 305 | 306 | [[package]] 307 | name = "futures-macro" 308 | version = "0.3.24" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" 311 | dependencies = [ 312 | "proc-macro2", 313 | "quote", 314 | "syn", 315 | ] 316 | 317 | [[package]] 318 | name = "futures-sink" 319 | version = "0.3.24" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" 322 | 323 | [[package]] 324 | name = "futures-task" 325 | version = "0.3.24" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" 328 | 329 | [[package]] 330 | name = "futures-util" 331 | version = "0.3.24" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" 334 | dependencies = [ 335 | "futures-channel", 336 | "futures-core", 337 | "futures-io", 338 | "futures-macro", 339 | "futures-sink", 340 | "futures-task", 341 | "memchr", 342 | "pin-project-lite", 343 | "pin-utils", 344 | "slab", 345 | ] 346 | 347 | [[package]] 348 | name = "getrandom" 349 | version = "0.2.7" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" 352 | dependencies = [ 353 | "cfg-if", 354 | "libc", 355 | "wasi", 356 | ] 357 | 358 | [[package]] 359 | name = "h2" 360 | version = "0.3.14" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" 363 | dependencies = [ 364 | "bytes", 365 | "fnv", 366 | "futures-core", 367 | "futures-sink", 368 | "futures-util", 369 | "http", 370 | "indexmap", 371 | "slab", 372 | "tokio", 373 | "tokio-util", 374 | "tracing", 375 | ] 376 | 377 | [[package]] 378 | name = "hashbrown" 379 | version = "0.12.3" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 382 | 383 | [[package]] 384 | name = "heck" 385 | version = "0.4.0" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 388 | 389 | [[package]] 390 | name = "hermit-abi" 391 | version = "0.1.15" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" 394 | dependencies = [ 395 | "libc", 396 | ] 397 | 398 | [[package]] 399 | name = "http" 400 | version = "0.2.8" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" 403 | dependencies = [ 404 | "bytes", 405 | "fnv", 406 | "itoa", 407 | ] 408 | 409 | [[package]] 410 | name = "http-body" 411 | version = "0.4.5" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 414 | dependencies = [ 415 | "bytes", 416 | "http", 417 | "pin-project-lite", 418 | ] 419 | 420 | [[package]] 421 | name = "http-range-header" 422 | version = "0.3.0" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" 425 | 426 | [[package]] 427 | name = "httparse" 428 | version = "1.8.0" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 431 | 432 | [[package]] 433 | name = "httpdate" 434 | version = "1.0.2" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 437 | 438 | [[package]] 439 | name = "hyper" 440 | version = "0.14.20" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" 443 | dependencies = [ 444 | "bytes", 445 | "futures-channel", 446 | "futures-core", 447 | "futures-util", 448 | "h2", 449 | "http", 450 | "http-body", 451 | "httparse", 452 | "httpdate", 453 | "itoa", 454 | "pin-project-lite", 455 | "socket2", 456 | "tokio", 457 | "tower-service", 458 | "tracing", 459 | "want", 460 | ] 461 | 462 | [[package]] 463 | name = "hyper-timeout" 464 | version = "0.4.1" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" 467 | dependencies = [ 468 | "hyper", 469 | "pin-project-lite", 470 | "tokio", 471 | "tokio-io-timeout", 472 | ] 473 | 474 | [[package]] 475 | name = "indexmap" 476 | version = "1.9.1" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 479 | dependencies = [ 480 | "autocfg", 481 | "hashbrown", 482 | ] 483 | 484 | [[package]] 485 | name = "instant" 486 | version = "0.1.12" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 489 | dependencies = [ 490 | "cfg-if", 491 | ] 492 | 493 | [[package]] 494 | name = "itertools" 495 | version = "0.10.5" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 498 | dependencies = [ 499 | "either", 500 | ] 501 | 502 | [[package]] 503 | name = "itoa" 504 | version = "1.0.4" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" 507 | 508 | [[package]] 509 | name = "js-sys" 510 | version = "0.3.60" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" 513 | dependencies = [ 514 | "wasm-bindgen", 515 | ] 516 | 517 | [[package]] 518 | name = "lazy_static" 519 | version = "1.4.0" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 522 | 523 | [[package]] 524 | name = "libc" 525 | version = "0.2.134" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" 528 | 529 | [[package]] 530 | name = "lock_api" 531 | version = "0.4.9" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" 534 | dependencies = [ 535 | "autocfg", 536 | "scopeguard", 537 | ] 538 | 539 | [[package]] 540 | name = "log" 541 | version = "0.4.17" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 544 | dependencies = [ 545 | "cfg-if", 546 | ] 547 | 548 | [[package]] 549 | name = "matchit" 550 | version = "0.5.0" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" 553 | 554 | [[package]] 555 | name = "memchr" 556 | version = "2.5.0" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 559 | 560 | [[package]] 561 | name = "mime" 562 | version = "0.3.16" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 565 | 566 | [[package]] 567 | name = "mio" 568 | version = "0.8.4" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" 571 | dependencies = [ 572 | "libc", 573 | "log", 574 | "wasi", 575 | "windows-sys", 576 | ] 577 | 578 | [[package]] 579 | name = "multimap" 580 | version = "0.8.3" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" 583 | 584 | [[package]] 585 | name = "nix-otel-plugin" 586 | version = "0.1.0" 587 | dependencies = [ 588 | "cbindgen", 589 | "cc", 590 | "opentelemetry", 591 | "opentelemetry-otlp", 592 | "opentelemetry_sdk", 593 | "pkg-config", 594 | "thread_local", 595 | "tokio", 596 | "tonic", 597 | ] 598 | 599 | [[package]] 600 | name = "num_cpus" 601 | version = "1.13.1" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 604 | dependencies = [ 605 | "hermit-abi", 606 | "libc", 607 | ] 608 | 609 | [[package]] 610 | name = "once_cell" 611 | version = "1.15.0" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" 614 | 615 | [[package]] 616 | name = "openssl-probe" 617 | version = "0.1.5" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 620 | 621 | [[package]] 622 | name = "opentelemetry" 623 | version = "0.18.0" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "69d6c3d7288a106c0a363e4b0e8d308058d56902adefb16f4936f417ffef086e" 626 | dependencies = [ 627 | "opentelemetry_api", 628 | "opentelemetry_sdk", 629 | ] 630 | 631 | [[package]] 632 | name = "opentelemetry-otlp" 633 | version = "0.11.0" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "d1c928609d087790fc936a1067bdc310ae702bdf3b090c3f281b713622c8bbde" 636 | dependencies = [ 637 | "async-trait", 638 | "futures", 639 | "futures-util", 640 | "http", 641 | "opentelemetry", 642 | "opentelemetry-proto", 643 | "prost", 644 | "thiserror", 645 | "tokio", 646 | "tonic", 647 | ] 648 | 649 | [[package]] 650 | name = "opentelemetry-proto" 651 | version = "0.1.0" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "d61a2f56df5574508dd86aaca016c917489e589ece4141df1b5e349af8d66c28" 654 | dependencies = [ 655 | "futures", 656 | "futures-util", 657 | "opentelemetry", 658 | "prost", 659 | "tonic", 660 | "tonic-build", 661 | ] 662 | 663 | [[package]] 664 | name = "opentelemetry_api" 665 | version = "0.18.0" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "c24f96e21e7acc813c7a8394ee94978929db2bcc46cf6b5014fc612bf7760c22" 668 | dependencies = [ 669 | "fnv", 670 | "futures-channel", 671 | "futures-util", 672 | "indexmap", 673 | "js-sys", 674 | "once_cell", 675 | "pin-project-lite", 676 | "thiserror", 677 | ] 678 | 679 | [[package]] 680 | name = "opentelemetry_sdk" 681 | version = "0.18.0" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "1ca41c4933371b61c2a2f214bf16931499af4ec90543604ec828f7a625c09113" 684 | dependencies = [ 685 | "async-trait", 686 | "crossbeam-channel", 687 | "dashmap", 688 | "fnv", 689 | "futures-channel", 690 | "futures-executor", 691 | "futures-util", 692 | "once_cell", 693 | "opentelemetry_api", 694 | "percent-encoding", 695 | "rand", 696 | "thiserror", 697 | "tokio", 698 | "tokio-stream", 699 | ] 700 | 701 | [[package]] 702 | name = "os_str_bytes" 703 | version = "6.3.0" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" 706 | 707 | [[package]] 708 | name = "parking_lot" 709 | version = "0.12.1" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 712 | dependencies = [ 713 | "lock_api", 714 | "parking_lot_core", 715 | ] 716 | 717 | [[package]] 718 | name = "parking_lot_core" 719 | version = "0.9.3" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" 722 | dependencies = [ 723 | "cfg-if", 724 | "libc", 725 | "redox_syscall", 726 | "smallvec", 727 | "windows-sys", 728 | ] 729 | 730 | [[package]] 731 | name = "percent-encoding" 732 | version = "2.2.0" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" 735 | 736 | [[package]] 737 | name = "petgraph" 738 | version = "0.6.2" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" 741 | dependencies = [ 742 | "fixedbitset", 743 | "indexmap", 744 | ] 745 | 746 | [[package]] 747 | name = "pin-project" 748 | version = "1.0.12" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" 751 | dependencies = [ 752 | "pin-project-internal", 753 | ] 754 | 755 | [[package]] 756 | name = "pin-project-internal" 757 | version = "1.0.12" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" 760 | dependencies = [ 761 | "proc-macro2", 762 | "quote", 763 | "syn", 764 | ] 765 | 766 | [[package]] 767 | name = "pin-project-lite" 768 | version = "0.2.9" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 771 | 772 | [[package]] 773 | name = "pin-utils" 774 | version = "0.1.0" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 777 | 778 | [[package]] 779 | name = "pkg-config" 780 | version = "0.3.19" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 783 | 784 | [[package]] 785 | name = "ppv-lite86" 786 | version = "0.2.16" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 789 | 790 | [[package]] 791 | name = "prettyplease" 792 | version = "0.1.20" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "83fead41e178796ef8274dc612a7d8ce4c7e10ca35cd2c5b5ad24cac63aeb6c0" 795 | dependencies = [ 796 | "proc-macro2", 797 | "syn", 798 | ] 799 | 800 | [[package]] 801 | name = "proc-macro2" 802 | version = "1.0.46" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" 805 | dependencies = [ 806 | "unicode-ident", 807 | ] 808 | 809 | [[package]] 810 | name = "prost" 811 | version = "0.11.0" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "399c3c31cdec40583bb68f0b18403400d01ec4289c383aa047560439952c4dd7" 814 | dependencies = [ 815 | "bytes", 816 | "prost-derive", 817 | ] 818 | 819 | [[package]] 820 | name = "prost-build" 821 | version = "0.11.1" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "7f835c582e6bd972ba8347313300219fed5bfa52caf175298d860b61ff6069bb" 824 | dependencies = [ 825 | "bytes", 826 | "heck", 827 | "itertools", 828 | "lazy_static", 829 | "log", 830 | "multimap", 831 | "petgraph", 832 | "prost", 833 | "prost-types", 834 | "regex", 835 | "tempfile", 836 | "which", 837 | ] 838 | 839 | [[package]] 840 | name = "prost-derive" 841 | version = "0.11.0" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | checksum = "7345d5f0e08c0536d7ac7229952590239e77abf0a0100a1b1d890add6ea96364" 844 | dependencies = [ 845 | "anyhow", 846 | "itertools", 847 | "proc-macro2", 848 | "quote", 849 | "syn", 850 | ] 851 | 852 | [[package]] 853 | name = "prost-types" 854 | version = "0.11.1" 855 | source = "registry+https://github.com/rust-lang/crates.io-index" 856 | checksum = "4dfaa718ad76a44b3415e6c4d53b17c8f99160dcb3a99b10470fce8ad43f6e3e" 857 | dependencies = [ 858 | "bytes", 859 | "prost", 860 | ] 861 | 862 | [[package]] 863 | name = "quote" 864 | version = "1.0.9" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 867 | dependencies = [ 868 | "proc-macro2", 869 | ] 870 | 871 | [[package]] 872 | name = "rand" 873 | version = "0.8.5" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 876 | dependencies = [ 877 | "libc", 878 | "rand_chacha", 879 | "rand_core", 880 | ] 881 | 882 | [[package]] 883 | name = "rand_chacha" 884 | version = "0.3.1" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 887 | dependencies = [ 888 | "ppv-lite86", 889 | "rand_core", 890 | ] 891 | 892 | [[package]] 893 | name = "rand_core" 894 | version = "0.6.4" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 897 | dependencies = [ 898 | "getrandom", 899 | ] 900 | 901 | [[package]] 902 | name = "redox_syscall" 903 | version = "0.2.16" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 906 | dependencies = [ 907 | "bitflags", 908 | ] 909 | 910 | [[package]] 911 | name = "regex" 912 | version = "1.6.0" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" 915 | dependencies = [ 916 | "regex-syntax", 917 | ] 918 | 919 | [[package]] 920 | name = "regex-syntax" 921 | version = "0.6.27" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" 924 | 925 | [[package]] 926 | name = "remove_dir_all" 927 | version = "0.5.3" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 930 | dependencies = [ 931 | "winapi", 932 | ] 933 | 934 | [[package]] 935 | name = "ring" 936 | version = "0.16.20" 937 | source = "registry+https://github.com/rust-lang/crates.io-index" 938 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 939 | dependencies = [ 940 | "cc", 941 | "libc", 942 | "once_cell", 943 | "spin", 944 | "untrusted", 945 | "web-sys", 946 | "winapi", 947 | ] 948 | 949 | [[package]] 950 | name = "rustls" 951 | version = "0.20.6" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" 954 | dependencies = [ 955 | "log", 956 | "ring", 957 | "sct", 958 | "webpki", 959 | ] 960 | 961 | [[package]] 962 | name = "rustls-native-certs" 963 | version = "0.6.2" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" 966 | dependencies = [ 967 | "openssl-probe", 968 | "rustls-pemfile", 969 | "schannel", 970 | "security-framework", 971 | ] 972 | 973 | [[package]] 974 | name = "rustls-pemfile" 975 | version = "1.0.1" 976 | source = "registry+https://github.com/rust-lang/crates.io-index" 977 | checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" 978 | dependencies = [ 979 | "base64", 980 | ] 981 | 982 | [[package]] 983 | name = "ryu" 984 | version = "1.0.11" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" 987 | 988 | [[package]] 989 | name = "schannel" 990 | version = "0.1.20" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" 993 | dependencies = [ 994 | "lazy_static", 995 | "windows-sys", 996 | ] 997 | 998 | [[package]] 999 | name = "scopeguard" 1000 | version = "1.1.0" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1003 | 1004 | [[package]] 1005 | name = "sct" 1006 | version = "0.7.0" 1007 | source = "registry+https://github.com/rust-lang/crates.io-index" 1008 | checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" 1009 | dependencies = [ 1010 | "ring", 1011 | "untrusted", 1012 | ] 1013 | 1014 | [[package]] 1015 | name = "security-framework" 1016 | version = "2.7.0" 1017 | source = "registry+https://github.com/rust-lang/crates.io-index" 1018 | checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" 1019 | dependencies = [ 1020 | "bitflags", 1021 | "core-foundation", 1022 | "core-foundation-sys", 1023 | "libc", 1024 | "security-framework-sys", 1025 | ] 1026 | 1027 | [[package]] 1028 | name = "security-framework-sys" 1029 | version = "2.6.1" 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" 1031 | checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" 1032 | dependencies = [ 1033 | "core-foundation-sys", 1034 | "libc", 1035 | ] 1036 | 1037 | [[package]] 1038 | name = "serde" 1039 | version = "1.0.145" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" 1042 | dependencies = [ 1043 | "serde_derive", 1044 | ] 1045 | 1046 | [[package]] 1047 | name = "serde_derive" 1048 | version = "1.0.145" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" 1051 | dependencies = [ 1052 | "proc-macro2", 1053 | "quote", 1054 | "syn", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "serde_json" 1059 | version = "1.0.86" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" 1062 | dependencies = [ 1063 | "itoa", 1064 | "ryu", 1065 | "serde", 1066 | ] 1067 | 1068 | [[package]] 1069 | name = "signal-hook-registry" 1070 | version = "1.4.0" 1071 | source = "registry+https://github.com/rust-lang/crates.io-index" 1072 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1073 | dependencies = [ 1074 | "libc", 1075 | ] 1076 | 1077 | [[package]] 1078 | name = "slab" 1079 | version = "0.4.7" 1080 | source = "registry+https://github.com/rust-lang/crates.io-index" 1081 | checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" 1082 | dependencies = [ 1083 | "autocfg", 1084 | ] 1085 | 1086 | [[package]] 1087 | name = "smallvec" 1088 | version = "1.10.0" 1089 | source = "registry+https://github.com/rust-lang/crates.io-index" 1090 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" 1091 | 1092 | [[package]] 1093 | name = "socket2" 1094 | version = "0.4.7" 1095 | source = "registry+https://github.com/rust-lang/crates.io-index" 1096 | checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" 1097 | dependencies = [ 1098 | "libc", 1099 | "winapi", 1100 | ] 1101 | 1102 | [[package]] 1103 | name = "spin" 1104 | version = "0.5.2" 1105 | source = "registry+https://github.com/rust-lang/crates.io-index" 1106 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1107 | 1108 | [[package]] 1109 | name = "strsim" 1110 | version = "0.10.0" 1111 | source = "registry+https://github.com/rust-lang/crates.io-index" 1112 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1113 | 1114 | [[package]] 1115 | name = "syn" 1116 | version = "1.0.102" 1117 | source = "registry+https://github.com/rust-lang/crates.io-index" 1118 | checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" 1119 | dependencies = [ 1120 | "proc-macro2", 1121 | "quote", 1122 | "unicode-ident", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "sync_wrapper" 1127 | version = "0.1.1" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" 1130 | 1131 | [[package]] 1132 | name = "tempfile" 1133 | version = "3.3.0" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 1136 | dependencies = [ 1137 | "cfg-if", 1138 | "fastrand", 1139 | "libc", 1140 | "redox_syscall", 1141 | "remove_dir_all", 1142 | "winapi", 1143 | ] 1144 | 1145 | [[package]] 1146 | name = "termcolor" 1147 | version = "1.1.3" 1148 | source = "registry+https://github.com/rust-lang/crates.io-index" 1149 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 1150 | dependencies = [ 1151 | "winapi-util", 1152 | ] 1153 | 1154 | [[package]] 1155 | name = "textwrap" 1156 | version = "0.15.1" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" 1159 | 1160 | [[package]] 1161 | name = "thiserror" 1162 | version = "1.0.37" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" 1165 | dependencies = [ 1166 | "thiserror-impl", 1167 | ] 1168 | 1169 | [[package]] 1170 | name = "thiserror-impl" 1171 | version = "1.0.37" 1172 | source = "registry+https://github.com/rust-lang/crates.io-index" 1173 | checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" 1174 | dependencies = [ 1175 | "proc-macro2", 1176 | "quote", 1177 | "syn", 1178 | ] 1179 | 1180 | [[package]] 1181 | name = "thread_local" 1182 | version = "1.1.4" 1183 | source = "registry+https://github.com/rust-lang/crates.io-index" 1184 | checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" 1185 | dependencies = [ 1186 | "once_cell", 1187 | ] 1188 | 1189 | [[package]] 1190 | name = "tokio" 1191 | version = "1.21.2" 1192 | source = "registry+https://github.com/rust-lang/crates.io-index" 1193 | checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" 1194 | dependencies = [ 1195 | "autocfg", 1196 | "bytes", 1197 | "libc", 1198 | "memchr", 1199 | "mio", 1200 | "num_cpus", 1201 | "parking_lot", 1202 | "pin-project-lite", 1203 | "signal-hook-registry", 1204 | "socket2", 1205 | "tokio-macros", 1206 | "winapi", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "tokio-io-timeout" 1211 | version = "1.2.0" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" 1214 | dependencies = [ 1215 | "pin-project-lite", 1216 | "tokio", 1217 | ] 1218 | 1219 | [[package]] 1220 | name = "tokio-macros" 1221 | version = "1.8.0" 1222 | source = "registry+https://github.com/rust-lang/crates.io-index" 1223 | checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" 1224 | dependencies = [ 1225 | "proc-macro2", 1226 | "quote", 1227 | "syn", 1228 | ] 1229 | 1230 | [[package]] 1231 | name = "tokio-rustls" 1232 | version = "0.23.4" 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" 1234 | checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" 1235 | dependencies = [ 1236 | "rustls", 1237 | "tokio", 1238 | "webpki", 1239 | ] 1240 | 1241 | [[package]] 1242 | name = "tokio-stream" 1243 | version = "0.1.10" 1244 | source = "registry+https://github.com/rust-lang/crates.io-index" 1245 | checksum = "f6edf2d6bc038a43d31353570e27270603f4648d18f5ed10c0e179abe43255af" 1246 | dependencies = [ 1247 | "futures-core", 1248 | "pin-project-lite", 1249 | "tokio", 1250 | ] 1251 | 1252 | [[package]] 1253 | name = "tokio-util" 1254 | version = "0.7.4" 1255 | source = "registry+https://github.com/rust-lang/crates.io-index" 1256 | checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" 1257 | dependencies = [ 1258 | "bytes", 1259 | "futures-core", 1260 | "futures-sink", 1261 | "pin-project-lite", 1262 | "tokio", 1263 | "tracing", 1264 | ] 1265 | 1266 | [[package]] 1267 | name = "toml" 1268 | version = "0.5.9" 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" 1270 | checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" 1271 | dependencies = [ 1272 | "serde", 1273 | ] 1274 | 1275 | [[package]] 1276 | name = "tonic" 1277 | version = "0.8.2" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "55b9af819e54b8f33d453655bef9b9acc171568fb49523078d0cc4e7484200ec" 1280 | dependencies = [ 1281 | "async-stream", 1282 | "async-trait", 1283 | "axum", 1284 | "base64", 1285 | "bytes", 1286 | "futures-core", 1287 | "futures-util", 1288 | "h2", 1289 | "http", 1290 | "http-body", 1291 | "hyper", 1292 | "hyper-timeout", 1293 | "percent-encoding", 1294 | "pin-project", 1295 | "prost", 1296 | "prost-derive", 1297 | "rustls-native-certs", 1298 | "rustls-pemfile", 1299 | "tokio", 1300 | "tokio-rustls", 1301 | "tokio-stream", 1302 | "tokio-util", 1303 | "tower", 1304 | "tower-layer", 1305 | "tower-service", 1306 | "tracing", 1307 | "tracing-futures", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "tonic-build" 1312 | version = "0.8.2" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "48c6fd7c2581e36d63388a9e04c350c21beb7a8b059580b2e93993c526899ddc" 1315 | dependencies = [ 1316 | "prettyplease", 1317 | "proc-macro2", 1318 | "prost-build", 1319 | "quote", 1320 | "syn", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "tower" 1325 | version = "0.4.13" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 1328 | dependencies = [ 1329 | "futures-core", 1330 | "futures-util", 1331 | "indexmap", 1332 | "pin-project", 1333 | "pin-project-lite", 1334 | "rand", 1335 | "slab", 1336 | "tokio", 1337 | "tokio-util", 1338 | "tower-layer", 1339 | "tower-service", 1340 | "tracing", 1341 | ] 1342 | 1343 | [[package]] 1344 | name = "tower-http" 1345 | version = "0.3.4" 1346 | source = "registry+https://github.com/rust-lang/crates.io-index" 1347 | checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba" 1348 | dependencies = [ 1349 | "bitflags", 1350 | "bytes", 1351 | "futures-core", 1352 | "futures-util", 1353 | "http", 1354 | "http-body", 1355 | "http-range-header", 1356 | "pin-project-lite", 1357 | "tower", 1358 | "tower-layer", 1359 | "tower-service", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "tower-layer" 1364 | version = "0.3.1" 1365 | source = "registry+https://github.com/rust-lang/crates.io-index" 1366 | checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" 1367 | 1368 | [[package]] 1369 | name = "tower-service" 1370 | version = "0.3.2" 1371 | source = "registry+https://github.com/rust-lang/crates.io-index" 1372 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1373 | 1374 | [[package]] 1375 | name = "tracing" 1376 | version = "0.1.37" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 1379 | dependencies = [ 1380 | "cfg-if", 1381 | "log", 1382 | "pin-project-lite", 1383 | "tracing-attributes", 1384 | "tracing-core", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "tracing-attributes" 1389 | version = "0.1.23" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" 1392 | dependencies = [ 1393 | "proc-macro2", 1394 | "quote", 1395 | "syn", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "tracing-core" 1400 | version = "0.1.30" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" 1403 | dependencies = [ 1404 | "once_cell", 1405 | ] 1406 | 1407 | [[package]] 1408 | name = "tracing-futures" 1409 | version = "0.2.5" 1410 | source = "registry+https://github.com/rust-lang/crates.io-index" 1411 | checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" 1412 | dependencies = [ 1413 | "pin-project", 1414 | "tracing", 1415 | ] 1416 | 1417 | [[package]] 1418 | name = "try-lock" 1419 | version = "0.2.3" 1420 | source = "registry+https://github.com/rust-lang/crates.io-index" 1421 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1422 | 1423 | [[package]] 1424 | name = "unicode-ident" 1425 | version = "1.0.5" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" 1428 | 1429 | [[package]] 1430 | name = "untrusted" 1431 | version = "0.7.1" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1434 | 1435 | [[package]] 1436 | name = "want" 1437 | version = "0.3.0" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1440 | dependencies = [ 1441 | "log", 1442 | "try-lock", 1443 | ] 1444 | 1445 | [[package]] 1446 | name = "wasi" 1447 | version = "0.11.0+wasi-snapshot-preview1" 1448 | source = "registry+https://github.com/rust-lang/crates.io-index" 1449 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1450 | 1451 | [[package]] 1452 | name = "wasm-bindgen" 1453 | version = "0.2.83" 1454 | source = "registry+https://github.com/rust-lang/crates.io-index" 1455 | checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" 1456 | dependencies = [ 1457 | "cfg-if", 1458 | "wasm-bindgen-macro", 1459 | ] 1460 | 1461 | [[package]] 1462 | name = "wasm-bindgen-backend" 1463 | version = "0.2.83" 1464 | source = "registry+https://github.com/rust-lang/crates.io-index" 1465 | checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" 1466 | dependencies = [ 1467 | "bumpalo", 1468 | "log", 1469 | "once_cell", 1470 | "proc-macro2", 1471 | "quote", 1472 | "syn", 1473 | "wasm-bindgen-shared", 1474 | ] 1475 | 1476 | [[package]] 1477 | name = "wasm-bindgen-macro" 1478 | version = "0.2.83" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" 1481 | dependencies = [ 1482 | "quote", 1483 | "wasm-bindgen-macro-support", 1484 | ] 1485 | 1486 | [[package]] 1487 | name = "wasm-bindgen-macro-support" 1488 | version = "0.2.83" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" 1491 | dependencies = [ 1492 | "proc-macro2", 1493 | "quote", 1494 | "syn", 1495 | "wasm-bindgen-backend", 1496 | "wasm-bindgen-shared", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "wasm-bindgen-shared" 1501 | version = "0.2.83" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" 1504 | 1505 | [[package]] 1506 | name = "web-sys" 1507 | version = "0.3.60" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" 1510 | dependencies = [ 1511 | "js-sys", 1512 | "wasm-bindgen", 1513 | ] 1514 | 1515 | [[package]] 1516 | name = "webpki" 1517 | version = "0.22.0" 1518 | source = "registry+https://github.com/rust-lang/crates.io-index" 1519 | checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" 1520 | dependencies = [ 1521 | "ring", 1522 | "untrusted", 1523 | ] 1524 | 1525 | [[package]] 1526 | name = "which" 1527 | version = "4.3.0" 1528 | source = "registry+https://github.com/rust-lang/crates.io-index" 1529 | checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" 1530 | dependencies = [ 1531 | "either", 1532 | "libc", 1533 | "once_cell", 1534 | ] 1535 | 1536 | [[package]] 1537 | name = "winapi" 1538 | version = "0.3.9" 1539 | source = "registry+https://github.com/rust-lang/crates.io-index" 1540 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1541 | dependencies = [ 1542 | "winapi-i686-pc-windows-gnu", 1543 | "winapi-x86_64-pc-windows-gnu", 1544 | ] 1545 | 1546 | [[package]] 1547 | name = "winapi-i686-pc-windows-gnu" 1548 | version = "0.4.0" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1551 | 1552 | [[package]] 1553 | name = "winapi-util" 1554 | version = "0.1.5" 1555 | source = "registry+https://github.com/rust-lang/crates.io-index" 1556 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1557 | dependencies = [ 1558 | "winapi", 1559 | ] 1560 | 1561 | [[package]] 1562 | name = "winapi-x86_64-pc-windows-gnu" 1563 | version = "0.4.0" 1564 | source = "registry+https://github.com/rust-lang/crates.io-index" 1565 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1566 | 1567 | [[package]] 1568 | name = "windows-sys" 1569 | version = "0.36.1" 1570 | source = "registry+https://github.com/rust-lang/crates.io-index" 1571 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" 1572 | dependencies = [ 1573 | "windows_aarch64_msvc", 1574 | "windows_i686_gnu", 1575 | "windows_i686_msvc", 1576 | "windows_x86_64_gnu", 1577 | "windows_x86_64_msvc", 1578 | ] 1579 | 1580 | [[package]] 1581 | name = "windows_aarch64_msvc" 1582 | version = "0.36.1" 1583 | source = "registry+https://github.com/rust-lang/crates.io-index" 1584 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" 1585 | 1586 | [[package]] 1587 | name = "windows_i686_gnu" 1588 | version = "0.36.1" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" 1591 | 1592 | [[package]] 1593 | name = "windows_i686_msvc" 1594 | version = "0.36.1" 1595 | source = "registry+https://github.com/rust-lang/crates.io-index" 1596 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" 1597 | 1598 | [[package]] 1599 | name = "windows_x86_64_gnu" 1600 | version = "0.36.1" 1601 | source = "registry+https://github.com/rust-lang/crates.io-index" 1602 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" 1603 | 1604 | [[package]] 1605 | name = "windows_x86_64_msvc" 1606 | version = "0.36.1" 1607 | source = "registry+https://github.com/rust-lang/crates.io-index" 1608 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" 1609 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "plugin", 4 | ] 5 | 6 | [profile.dev] 7 | panic = "abort" 8 | 9 | [profile.release] 10 | panic = "abort" 11 | 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License Copyright (c) 2022 Jade Lovelace 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice (including the next 11 | paragraph) shall be included in all copies or substantial portions of the 12 | Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 17 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 | OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nix-otel 2 | 3 | ![Screenshot of Honeycomb from nix-otel instrumenting building itself](./demo-screenshot.png) 4 | 5 | This program shims the Nix logger with a Nix plugin to extract precise timing 6 | for builds from Nix. It has only been tested against [Honeycomb] with 7 | OTLP/gRPC. 8 | 9 | [Honeycomb]: https://honeycomb.io 10 | 11 | ## Setup 12 | 13 | ### Installation 14 | 15 | To install nix-otel, it needs to be passed to Nix in the option `plugin-files`. 16 | [Currently](https://github.com/lf-/nix-otel/issues/3) nix-otel can only run on 17 | the Nix client, so my recommendation is to just use the flake from this 18 | repository and `--option plugin-files`, for now. In the future, it will be able 19 | to run on the daemon so it will be easier to install system wide. 20 | 21 | #### Important note 22 | 23 | You need to *ensure* that the version of Nix that `nix-otel` is loaded in is 24 | exactly the same as the one it's built against. We [found a strange macOS-only 25 | bug](https://github.com/lf-/nix-otel/pull/12) where `nix-otel` built against a 26 | different copy of Nix 2.11.0 than it was run against would not get any data. 27 | 28 | In practice, this means running with the `nix` binary provided by the `nix 29 | develop` shell from this project rather than the system Nix. 30 | 31 | ### Honeycomb 32 | 33 | Set env vars like so in `.envrc.local`: 34 | 35 | ``` 36 | export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io 37 | export OTEL_EXPORTER_OTLP_HEADERS=x-honeycomb-team=YOUR_APIKEY 38 | ``` 39 | 40 | Then set the Nix configuration option `plugin-files` to include the plugin .so 41 | or .dylib file. 42 | 43 | ### Other services 44 | 45 | No idea. Sorry. They probably work but might need some minor patches since 46 | [rust-opentelemetry-otlp doesn't support all environment variables 47 | yet](https://github.com/open-telemetry/opentelemetry-rust/issues/774). 48 | 49 | ## Development 50 | 51 | I use nix-direnv and direnv to make this project work across C++ and Rust. 52 | 53 | To make rust-analyzer work for you and pick up the right compiler and so on, 54 | you will need to create a wrapper script `direnv-ra` somewhere in your $PATH, 55 | like so: 56 | 57 | ```bash 58 | #!/bin/sh 59 | 60 | direnv exec . rust-analyzer "$@" 61 | ``` 62 | 63 | then set the "rust-analyzer.server.path" variable in your editor settings to 64 | point to it. 65 | 66 | ### Making the C++ IDE work 67 | 68 | This is unnecessarily silly because C++ is bad. Anyway, you can get clangd 69 | working on this project by doing the following: 70 | 71 | ``` 72 | [nix-shell]$ cargo clean -p nix-otel-plugin 73 | [nix-shell]$ bear -- cargo build 74 | ``` 75 | 76 | which will create a `compile_commands.json` with the appropriate contents. 77 | 78 | ### Running in development 79 | 80 | Run in development like so: 81 | 82 | ``` 83 | nix-otel/plugin » cargo b && nix --option plugin-files ../target/debug/libnix_otel_plugin.so build ..# 84 | ``` 85 | 86 | 87 | ## Project information 88 | 89 | Everyone is expected to follow the [code of conduct](./CODE_OF_CONDUCT.md) 90 | while participating in this project. 91 | -------------------------------------------------------------------------------- /demo-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lf-/nix-otel/25894595a8cbe1a09c93547d5bb839f439ee94bf/demo-screenshot.png -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "locked": { 5 | "lastModified": 1659877975, 6 | "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", 7 | "owner": "numtide", 8 | "repo": "flake-utils", 9 | "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "numtide", 14 | "repo": "flake-utils", 15 | "type": "github" 16 | } 17 | }, 18 | "nixpkgs": { 19 | "locked": { 20 | "lastModified": 1691186842, 21 | "narHash": "sha256-wxBVCvZUwq+XS4N4t9NqsHV4E64cPVqQ2fdDISpjcw0=", 22 | "owner": "nixos", 23 | "repo": "nixpkgs", 24 | "rev": "18036c0be90f4e308ae3ebcab0e14aae0336fe42", 25 | "type": "github" 26 | }, 27 | "original": { 28 | "owner": "nixos", 29 | "ref": "nixos-unstable", 30 | "repo": "nixpkgs", 31 | "type": "github" 32 | } 33 | }, 34 | "root": { 35 | "inputs": { 36 | "flake-utils": "flake-utils", 37 | "nixpkgs": "nixpkgs" 38 | } 39 | } 40 | }, 41 | "root": "root", 42 | "version": 7 43 | } 44 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Example rust project"; 3 | inputs = { 4 | nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; 5 | flake-utils.url = "github:numtide/flake-utils"; 6 | }; 7 | 8 | outputs = { self, nixpkgs, flake-utils }: 9 | flake-utils.lib.eachDefaultSystem 10 | ( 11 | system: 12 | let 13 | pkgs = import nixpkgs { 14 | inherit system; 15 | overlays = [ self.overlays.default ]; 16 | }; 17 | in 18 | { 19 | packages = rec { 20 | nix-otel = pkgs.nix-otel; 21 | default = nix-otel; 22 | }; 23 | checks = self.packages.${system}; 24 | 25 | # for debugging 26 | inherit pkgs; 27 | 28 | devShells.default = pkgs.nix-otel.overrideAttrs ( 29 | old: { 30 | # make rust-analyzer work 31 | RUST_SRC_PATH = pkgs.rustPlatform.rustLibSrc; 32 | 33 | # any dev tools you use in excess of the rust ones 34 | nativeBuildInputs = old.nativeBuildInputs ++ ( 35 | with pkgs; [ 36 | nix 37 | bear 38 | rust-analyzer 39 | rust-cbindgen 40 | clang-tools_14 41 | ] 42 | ); 43 | } 44 | ); 45 | } 46 | ) 47 | // { 48 | overlays.default = ( 49 | final: prev: 50 | let 51 | inherit (prev) lib; 52 | in 53 | { 54 | nix-otel = final.rustPlatform.buildRustPackage { 55 | pname = "nix-otel"; 56 | version = "0.1.0"; 57 | 58 | cargoLock = { 59 | lockFile = ./Cargo.lock; 60 | }; 61 | 62 | src = ./.; 63 | 64 | # tools on the builder machine needed to build; e.g. pkg-config 65 | nativeBuildInputs = with final; [ 66 | pkg-config 67 | protobuf 68 | ]; 69 | 70 | # native libs 71 | buildInputs = with final; [ 72 | boost 73 | nix 74 | ] ++ lib.optional final.stdenv.isDarwin 75 | final.darwin.apple_sdk.frameworks.Security; 76 | }; 77 | } 78 | ); 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /plugin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nix-otel-plugin" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | crate_type = ["cdylib"] 8 | test = false 9 | 10 | [build-dependencies] 11 | cc = "1.0.58" 12 | pkg-config = "0.3.18" 13 | cbindgen = "0.24.3" 14 | 15 | [dependencies] 16 | opentelemetry = "0.18.0" 17 | opentelemetry-otlp = { version = "0.11.0", features = ["tls", "tls-roots"] } 18 | opentelemetry_sdk = { version = "0.18.0", features = ["rt-tokio"] } 19 | thread_local = "1.1.4" 20 | tokio = { version = "1.21.2", features = ["full"] } 21 | tonic = { version = "0.8.2", features = ["tls", "tls-roots"] } 22 | -------------------------------------------------------------------------------- /plugin/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | extern crate cbindgen; 3 | 4 | trait AddPkg { 5 | fn add_pkg_config(&mut self, pkg: pkg_config::Library) -> &mut Self; 6 | } 7 | impl AddPkg for cc::Build { 8 | fn add_pkg_config(&mut self, pkg: pkg_config::Library) -> &mut Self { 9 | for p in pkg.include_paths.into_iter() { 10 | self.flag("-isystem").flag(p.to_str().unwrap()); 11 | } 12 | for p in pkg.link_paths.into_iter() { 13 | self.flag(&format!("-L{:?}", p)); 14 | } 15 | for p in pkg.libs.into_iter() { 16 | self.flag(&format!("-l{}", p)); 17 | } 18 | for p in pkg.framework_paths.into_iter() { 19 | self.flag(&format!("-F{:?}", p)); 20 | } 21 | for p in pkg.frameworks.into_iter() { 22 | self.flag(&format!("-framework {}", p)); 23 | } 24 | self 25 | } 26 | } 27 | 28 | fn main() { 29 | #[cfg(test)] 30 | { 31 | return; 32 | } 33 | 34 | let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); 35 | 36 | cbindgen::Builder::new() 37 | .with_crate(crate_dir) 38 | .generate() 39 | .expect("Unable to generate bindings") 40 | .write_to_file("nix_otel_plugin.h"); 41 | 42 | println!("cargo:rerun-if-changed=plugin.cpp"); 43 | let nix_expr = pkg_config::Config::new() 44 | .atleast_version("2.1.1") 45 | .probe("nix-expr") 46 | .unwrap(); 47 | let nix_store = pkg_config::Config::new() 48 | .atleast_version("2.1.1") 49 | .probe("nix-store") 50 | .unwrap(); 51 | let nix_main = pkg_config::Config::new() 52 | .atleast_version("2.1.1") 53 | .probe("nix-main") 54 | .unwrap(); 55 | 56 | let nix_ver = nix_expr.version.clone(); 57 | 58 | let mut parts = nix_ver.split('.').map(str::parse); 59 | let major: u32 = parts.next().unwrap().unwrap(); 60 | let minor = parts.next().unwrap().unwrap(); 61 | 62 | let mut cpp_version = "20"; 63 | 64 | if (major, minor) <= (2, 11) { 65 | cpp_version = "17"; 66 | } 67 | 68 | 69 | let mut build = cc::Build::new(); 70 | build 71 | .cpp(true) 72 | .opt_level(2) 73 | .shared_flag(true) 74 | .flag(&format!("-std=c++{}", cpp_version)) 75 | .add_pkg_config(nix_expr) 76 | .add_pkg_config(nix_store) 77 | .add_pkg_config(nix_main) 78 | .cargo_metadata(false) 79 | .file("plugin.cpp"); 80 | 81 | // HACK: For some reason, rustc doesn't link libc++ on macOS by itself even 82 | // though cc-rs has been told cpp(true). So we force it. 83 | if cfg!(target_os = "macos") { 84 | println!("cargo:rustc-link-lib=c++"); 85 | } 86 | 87 | // Indicate that we need to patch around an API change with macros 88 | if (major, minor) >= (2, 4) { 89 | build.define("NIX_2_4_0", None); 90 | } 91 | if (major, minor) >= (2, 6) { 92 | build.define("NIX_2_6_0", None); 93 | } 94 | if (major, minor) >= (2, 9) { 95 | build.define("NIX_2_9_0", None); 96 | } 97 | 98 | println!("cargo:rustc-link-lib=static:+whole-archive=nix_otel_plugin"); 99 | println!( 100 | "cargo:rustc-link-search=native={}", 101 | env::var("OUT_DIR").unwrap() 102 | ); 103 | 104 | build.compile("nix_otel_plugin"); 105 | } 106 | -------------------------------------------------------------------------------- /plugin/cbindgen.toml: -------------------------------------------------------------------------------- 1 | # This is a template cbindgen.toml file with all of the default values. 2 | # Some values are commented out because their absence is the real default. 3 | # 4 | # See https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml 5 | # for detailed documentation of every option here. 6 | 7 | language = "C++" 8 | 9 | ############## Options for Wrapping the Contents of the Header ################# 10 | 11 | # header = "/* Text to put at the beginning of the generated file. Probably a license. */" 12 | # trailer = "/* Text to put at the end of the generated file */" 13 | # include_guard = "my_bindings_h" 14 | # pragma_once = true 15 | # autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" 16 | include_version = false 17 | # namespace = "my_namespace" 18 | namespaces = [] 19 | using_namespaces = [] 20 | sys_includes = [] 21 | includes = [] 22 | no_includes = false 23 | after_includes = "" 24 | 25 | ############################ Code Style Options ################################ 26 | 27 | braces = "SameLine" 28 | line_length = 100 29 | tab_width = 2 30 | documentation = true 31 | documentation_style = "auto" 32 | documentation_length = "full" 33 | line_endings = "LF" # also "CR", "CRLF", "Native" 34 | 35 | ############################# Codegen Options ################################## 36 | 37 | style = "both" 38 | sort_by = "Name" # default for `fn.sort_by` and `const.sort_by` 39 | usize_is_size_t = true 40 | 41 | [defines] 42 | # "target_os = freebsd" = "DEFINE_FREEBSD" 43 | # "feature = serde" = "DEFINE_SERDE" 44 | 45 | [export] 46 | include = [] 47 | exclude = [] 48 | # prefix = "CAPI_" 49 | item_types = [] 50 | renaming_overrides_prefixing = false 51 | 52 | [export.rename] 53 | 54 | [export.body] 55 | 56 | [export.mangle] 57 | 58 | [fn] 59 | rename_args = "None" 60 | # must_use = "MUST_USE_FUNC" 61 | # no_return = "NO_RETURN" 62 | # prefix = "START_FUNC" 63 | # postfix = "END_FUNC" 64 | args = "auto" 65 | sort_by = "Name" 66 | 67 | [struct] 68 | rename_fields = "None" 69 | # must_use = "MUST_USE_STRUCT" 70 | derive_constructor = false 71 | derive_eq = false 72 | derive_neq = false 73 | derive_lt = false 74 | derive_lte = false 75 | derive_gt = false 76 | derive_gte = false 77 | 78 | [enum] 79 | rename_variants = "None" 80 | # must_use = "MUST_USE_ENUM" 81 | add_sentinel = false 82 | prefix_with_name = false 83 | derive_helper_methods = false 84 | derive_const_casts = false 85 | derive_mut_casts = false 86 | # cast_assert_name = "ASSERT" 87 | derive_tagged_enum_destructor = false 88 | derive_tagged_enum_copy_constructor = false 89 | enum_class = true 90 | private_default_tagged_enum_constructor = false 91 | 92 | [const] 93 | allow_static_const = true 94 | allow_constexpr = false 95 | sort_by = "Name" 96 | 97 | [macro_expansion] 98 | bitflags = false 99 | 100 | ############## Options for How Your Rust library Should Be Parsed ############## 101 | 102 | [parse] 103 | parse_deps = false 104 | # include = [] 105 | exclude = [] 106 | clean = false 107 | extra_bindings = [] 108 | 109 | [parse.expand] 110 | crates = [] 111 | all_features = false 112 | default_features = true 113 | features = [] 114 | -------------------------------------------------------------------------------- /plugin/plugin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #if HAVE_BOEHMGC 13 | 14 | #include 15 | #include 16 | 17 | #endif 18 | 19 | #include "./nix_otel_plugin.h" 20 | 21 | using namespace nix; 22 | 23 | extern "C" void discourage_linker_from_discarding() {} 24 | 25 | static auto marshalActivityType(ActivityType at) -> ActivityKind { 26 | switch (at) { 27 | case actCopyPath: 28 | return ActivityKind::CopyPath; 29 | case actFileTransfer: 30 | return ActivityKind::FileTransfer; 31 | case actRealise: 32 | return ActivityKind::Realise; 33 | case actCopyPaths: 34 | return ActivityKind::CopyPaths; 35 | case actBuilds: 36 | return ActivityKind::Builds; 37 | case actBuild: 38 | return ActivityKind::Build; 39 | case actOptimiseStore: 40 | return ActivityKind::OptimiseStore; 41 | case actVerifyPaths: 42 | return ActivityKind::VerifyPaths; 43 | case actSubstitute: 44 | return ActivityKind::Substitute; 45 | case actQueryPathInfo: 46 | return ActivityKind::QueryPathInfo; 47 | case actPostBuildHook: 48 | return ActivityKind::PostBuildHook; 49 | case actBuildWaiting: 50 | return ActivityKind::BuildWaiting; 51 | default: 52 | case actUnknown: 53 | return ActivityKind::Unknown; 54 | } 55 | } 56 | 57 | static auto marshalResultType(ResultType rt) -> ResultKind { 58 | switch (rt) { 59 | case resFileLinked: 60 | return ResultKind::FileLinked; 61 | case resBuildLogLine: 62 | return ResultKind::BuildLogLine; 63 | case resUntrustedPath: 64 | return ResultKind::UntrustedPath; 65 | case resCorruptedPath: 66 | return ResultKind::CorruptedPath; 67 | case resSetPhase: 68 | return ResultKind::SetPhase; 69 | case resProgress: 70 | return ResultKind::Progress; 71 | case resSetExpected: 72 | return ResultKind::SetExpected; 73 | case resPostBuildLogLine: 74 | return ResultKind::PostBuildLogLine; 75 | default: 76 | return ResultKind::Unknown; 77 | } 78 | } 79 | 80 | static auto marshalField(Logger::Field const &field) -> FfiField { 81 | if (field.type == nix::Logger::Field::tInt) { 82 | return FfiField{ 83 | .tag = FfiField::Tag::Num, 84 | .num = {field.i}, 85 | }; 86 | } else if (field.type == nix::Logger::Field::tString) { 87 | return FfiField{ 88 | .tag = FfiField::Tag::String, 89 | .string = {FfiString{.start = field.s.data(), .len = field.s.length()}}, 90 | }; 91 | } 92 | // w/e 93 | __builtin_abort(); 94 | } 95 | 96 | static auto marshalFields(Logger::Fields const &fields) 97 | -> std::vector { 98 | std::vector out{}; 99 | for (auto &&f : fields) { 100 | out.push_back(marshalField(f)); 101 | } 102 | 103 | return out; 104 | } 105 | 106 | static auto unwrapVectorToFfiFields(std::vector const &fields_) 107 | -> FfiFields { 108 | return FfiFields{.start = fields_.data(), .count = fields_.size()}; 109 | } 110 | 111 | class OTelLogger : public Logger { 112 | private: 113 | Logger *upstream; 114 | Context const *m_context; 115 | 116 | public: 117 | OTelLogger(Logger *upstream, Context const *context) 118 | : upstream(upstream), m_context(context) {} 119 | ~OTelLogger() = default; 120 | 121 | void stop() override { upstream->stop(); } 122 | 123 | bool isVerbose() override { return upstream->isVerbose(); } 124 | 125 | void log(Verbosity lvl, const FormatOrString &fs) override { 126 | upstream->log(lvl, fs); 127 | } 128 | 129 | void logEI(const ErrorInfo &ei) override { upstream->logEI(ei); } 130 | 131 | void warn(const std::string &msg) override { upstream->log(msg); } 132 | 133 | void startActivity(ActivityId act, Verbosity lvl, ActivityType type, 134 | const std::string &s, const Fields &fields, 135 | ActivityId parent) override { 136 | auto fields_ = marshalFields(fields); 137 | start_activity(m_context, act, marshalActivityType(type), s.c_str(), 138 | unwrapVectorToFfiFields(fields_), parent); 139 | upstream->startActivity(act, lvl, type, s, fields, parent); 140 | }; 141 | 142 | void stopActivity(ActivityId act) override { 143 | end_activity(m_context, act); 144 | upstream->stopActivity(act); 145 | }; 146 | 147 | void result(ActivityId act, ResultType type, const Fields &fields) override { 148 | auto fields_ = marshalFields(fields); 149 | on_result(m_context, act, marshalResultType(type), 150 | unwrapVectorToFfiFields(fields_)); 151 | upstream->result(act, type, fields); 152 | }; 153 | 154 | void writeToStdout(std::string_view s) override { 155 | upstream->writeToStdout(s); 156 | } 157 | 158 | std::optional ask(std::string_view s) override { 159 | return upstream->ask(s); 160 | } 161 | }; 162 | 163 | class PluginInstance { 164 | Context *context; 165 | Logger *oldLogger; 166 | 167 | public: 168 | PluginInstance() { 169 | Logger *oldLogger = logger; 170 | context = initialize_plugin(); 171 | logger = new OTelLogger(oldLogger, context); 172 | } 173 | 174 | ~PluginInstance() { 175 | auto toDestroy = logger; 176 | logger = oldLogger; 177 | deinitialize_plugin(context); 178 | delete toDestroy; 179 | } 180 | }; 181 | 182 | PluginInstance x{}; 183 | -------------------------------------------------------------------------------- /plugin/src/activity.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | use std::os::raw::c_char; 3 | use std::slice; 4 | 5 | #[derive(Clone, Copy, Debug)] 6 | #[repr(u32)] 7 | pub enum ResultKind { 8 | Unknown = 0, 9 | FileLinked = 100, 10 | BuildLogLine = 101, 11 | UntrustedPath = 102, 12 | CorruptedPath = 103, 13 | SetPhase = 104, 14 | Progress = 105, 15 | SetExpected = 106, 16 | PostBuildLogLine = 107, 17 | } 18 | 19 | #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] 20 | #[repr(transparent)] 21 | pub struct ActivityId(pub u64); 22 | 23 | #[derive(Clone, Copy, Debug)] 24 | #[repr(u32)] 25 | pub enum ActivityKind { 26 | Unknown = 0, 27 | CopyPath = 100, 28 | FileTransfer = 101, 29 | Realise = 102, 30 | CopyPaths = 103, 31 | Builds = 104, 32 | Build = 105, 33 | OptimiseStore = 106, 34 | VerifyPaths = 107, 35 | Substitute = 108, 36 | QueryPathInfo = 109, 37 | PostBuildHook = 110, 38 | BuildWaiting = 111, 39 | } 40 | 41 | #[derive(Debug)] 42 | pub struct ActivityRecord { 43 | pub id: ActivityId, 44 | pub parent: Option, 45 | pub name: String, 46 | pub kind: ActivityKind, 47 | pub fields: Vec, 48 | } 49 | 50 | #[repr(C)] 51 | pub struct FfiString { 52 | pub start: *const c_char, 53 | pub len: usize, 54 | } 55 | 56 | #[repr(C, u8)] 57 | pub enum FfiField { 58 | String(FfiString), 59 | Num(u64), 60 | } 61 | 62 | #[derive(Debug)] 63 | pub enum Field { 64 | String(String), 65 | Num(u64), 66 | } 67 | 68 | impl Display for Field { 69 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 70 | match self { 71 | Field::String(s) => f.write_str(&s), 72 | Field::Num(n) => n.fmt(f), 73 | } 74 | } 75 | 76 | } 77 | 78 | pub unsafe fn unmarshal_string(s: &FfiString) -> String { 79 | let bytes = unsafe { slice::from_raw_parts(s.start as *const u8, s.len) }; 80 | String::from(String::from_utf8_lossy(bytes)) 81 | } 82 | 83 | pub unsafe fn unmarshal_field(field: &FfiField) -> Field { 84 | match field { 85 | FfiField::String(s) => Field::String(unsafe { unmarshal_string(s) }), 86 | FfiField::Num(n) => (Field::Num(*n)), 87 | } 88 | } 89 | 90 | pub unsafe fn unmarshal_fields(fields: FfiFields) -> Vec { 91 | let slice = unsafe { slice::from_raw_parts(fields.start, fields.count) }; 92 | slice 93 | .iter() 94 | .map(|ff| unsafe { unmarshal_field(ff) }) 95 | .collect() 96 | } 97 | 98 | #[repr(C)] 99 | pub struct FfiFields { 100 | pub start: *const FfiField, 101 | pub count: usize, 102 | } 103 | -------------------------------------------------------------------------------- /plugin/src/exporter.rs: -------------------------------------------------------------------------------- 1 | use std::{borrow::Cow, collections::HashMap, convert::TryFrom, time::SystemTime}; 2 | 3 | use opentelemetry::{ 4 | global, 5 | trace::{TraceContextExt, Tracer as TracerT}, 6 | Array, Context, KeyValue, 7 | }; 8 | use opentelemetry_otlp::WithExportConfig; 9 | use opentelemetry_sdk::{trace::Tracer, Resource}; 10 | use tokio::{runtime::Runtime, sync::mpsc}; 11 | use tonic::metadata::{AsciiMetadataKey, AsciiMetadataValue, MetadataMap}; 12 | 13 | use crate::activity::{ActivityId, ActivityRecord, Field, ResultKind}; 14 | 15 | struct SpanMap { 16 | pub map: HashMap, 17 | tracer: Tracer, 18 | } 19 | 20 | struct ActivityData { 21 | // record: ActivityRecord, 22 | context: Context, 23 | phase_span: Option, 24 | } 25 | 26 | fn fields_key_value(fields: &Vec) -> KeyValue { 27 | KeyValue::new( 28 | "nix.fields", 29 | opentelemetry::Value::Array(Array::String( 30 | fields.iter().map(|v| format!("{v}").into()).collect(), 31 | )), 32 | ) 33 | } 34 | 35 | impl SpanMap { 36 | fn begin(&mut self, context: &Context, record: ActivityRecord, start_time: SystemTime) { 37 | let id = record.id; 38 | let name = record.name.clone(); 39 | let parent_context = record 40 | .parent 41 | .and_then(|p| self.map.get(&p)) 42 | .map(|p| &p.context) 43 | .unwrap_or(context); 44 | 45 | let attrs = [ 46 | KeyValue::new("nix.activitykind", format!("{:?}", record.kind)), 47 | fields_key_value(&record.fields), 48 | ]; 49 | 50 | let ad = ActivityData { 51 | // TODO: is this actually right?! 52 | context: parent_context.with_span( 53 | self.tracer 54 | .span_builder(Cow::Owned(name)) 55 | .with_start_time(start_time) 56 | .with_attributes(attrs) 57 | .start_with_context(&self.tracer, parent_context), 58 | ), 59 | phase_span: None, 60 | }; 61 | 62 | self.map.insert(id, ad); 63 | } 64 | 65 | fn result(&mut self, act: ActivityId, kind: ResultKind, time: SystemTime, fields: Vec) { 66 | if let Some(ad) = self.map.get_mut(&act) { 67 | let attrs = vec![ 68 | KeyValue::new("nix.event_kind", format!("{kind:?}")), 69 | fields_key_value(&fields), 70 | ]; 71 | match kind { 72 | ResultKind::SetPhase => { 73 | if let Some(ref span) = ad.phase_span { 74 | span.span().end_with_timestamp(time); 75 | } 76 | ad.phase_span = Some( 77 | ad.context.with_span( 78 | self.tracer 79 | .span_builder(Cow::Owned( 80 | fields 81 | .get(0) 82 | .map(|f| format!("{f}")) 83 | .unwrap_or("no phase".to_owned()), 84 | )) 85 | .start_with_context(&self.tracer, &ad.context), 86 | ), 87 | ) 88 | } 89 | ResultKind::BuildLogLine => ad.context.span().add_event_with_timestamp( 90 | format!( 91 | "{}", 92 | fields 93 | .get(0) 94 | .unwrap_or(&Field::String("(no message)".to_string())), 95 | ), 96 | time, 97 | attrs, 98 | ), 99 | kind => { 100 | ad.context 101 | .span() 102 | .add_event_with_timestamp(format!("{kind:?}"), time, attrs) 103 | } 104 | } 105 | } 106 | } 107 | 108 | fn end(&mut self, act: ActivityId, end_time: SystemTime) { 109 | if let Some(ad) = self.map.get_mut(&act) { 110 | if let Some(ref span) = ad.phase_span { 111 | span.span().end_with_timestamp(end_time); 112 | } 113 | ad.context.span().end_with_timestamp(end_time); 114 | // intentionally don't remove it, since it may be used as a parent 115 | // for another span 116 | } 117 | } 118 | } 119 | impl SpanMap { 120 | fn new(tracer: Tracer) -> Self { 121 | Self { 122 | map: Default::default(), 123 | tracer, 124 | } 125 | } 126 | } 127 | 128 | #[derive(Debug)] 129 | pub enum Message { 130 | BeginActivity(ActivityRecord, SystemTime), 131 | EndActivity(ActivityId, SystemTime), 132 | Result(ActivityId, ResultKind, SystemTime, Vec), 133 | Terminate, 134 | } 135 | 136 | type Error = Box; 137 | 138 | fn startup() -> Result { 139 | let runtime = tokio::runtime::Builder::new_multi_thread() 140 | .worker_threads(2) 141 | .thread_name("nix_otel_plugin") 142 | .enable_all() 143 | .build() 144 | .unwrap(); 145 | Ok(runtime) 146 | } 147 | 148 | async fn process_message(message: Message, span_map: &mut SpanMap, root_context: &Context) { 149 | match message { 150 | Message::BeginActivity(rec, time) => { 151 | span_map.begin(root_context, rec, time); 152 | } 153 | Message::EndActivity(id, time) => { 154 | span_map.end(id, time); 155 | } 156 | Message::Result(id, kind, time, fields) => { 157 | span_map.result(id, kind, time, fields); 158 | } 159 | Message::Terminate => panic!("handled outside"), 160 | } 161 | } 162 | 163 | fn get_tracer_headers() -> MetadataMap { 164 | let mut map = MetadataMap::new(); 165 | let headers = std::env::var("OTEL_EXPORTER_OTLP_HEADERS"); 166 | if let Ok(h) = headers { 167 | h.split(',') 168 | .filter_map(|part| { 169 | let eq = part.find('=')?; 170 | let (key, val) = part.split_at(eq); 171 | let val = &val[1..]; 172 | Some(( 173 | AsciiMetadataKey::from_bytes(key.as_bytes()).ok()?, 174 | AsciiMetadataValue::try_from(val.as_bytes()).ok()?, 175 | )) 176 | }) 177 | .for_each(|(h, val)| { 178 | let _ = map.insert(h, val); 179 | }); 180 | } 181 | map 182 | } 183 | 184 | async fn exporter_run(mut recv: mpsc::UnboundedReceiver) -> Result<(), Error> { 185 | let tracer_meta = get_tracer_headers(); 186 | // FIXME(jade): this sets a global tracing provider, which is probably 187 | // *wrong* for a plugin to do. We could definitely desugar this and not 188 | // do the global provider. 189 | let tracer = opentelemetry_otlp::new_pipeline() 190 | .tracing() 191 | .with_exporter( 192 | opentelemetry_otlp::new_exporter() 193 | .tonic() 194 | .with_env() 195 | .with_metadata(tracer_meta), 196 | ) 197 | .with_trace_config( 198 | opentelemetry_sdk::trace::config() 199 | .with_resource(Resource::new([KeyValue::new("service.name", "nix-otel")])), 200 | ) 201 | .install_batch(opentelemetry_sdk::runtime::Tokio)?; 202 | 203 | let mut span_map = SpanMap::new(tracer.clone()); 204 | 205 | let root_context = Context::new(); 206 | let root_context = 207 | root_context.with_span(tracer.start_with_context( 208 | std::env::args().collect::>().join(" "), 209 | &root_context)); 210 | loop { 211 | match recv.recv().await { 212 | None | Some(Message::Terminate) => { 213 | recv.close(); 214 | // is this manual usage an async bug? who can say. the 215 | // background context stuff is a real good way to fuck up with 216 | // async though.... 217 | root_context.span().end(); 218 | break; 219 | } 220 | Some(v) => process_message(v, &mut span_map, &root_context).await, 221 | } 222 | } 223 | if let Some(tp) = tracer.provider() { 224 | for res in tp.force_flush() { 225 | if let Err(e) = res { 226 | eprintln!("send error: {e:?}"); 227 | } 228 | } 229 | drop(tp); 230 | } 231 | global::shutdown_tracer_provider(); 232 | Ok(()) 233 | } 234 | 235 | pub fn exporter_main(recv: mpsc::UnboundedReceiver) { 236 | let runtime = startup().expect("startup exporter"); 237 | runtime 238 | .block_on(exporter_run(recv)) 239 | .expect("fatal exporter error"); 240 | } 241 | -------------------------------------------------------------------------------- /plugin/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(unsafe_op_in_unsafe_fn)] 2 | use std::{ 3 | ffi::CStr, 4 | os::raw::c_char, 5 | sync::Mutex, 6 | thread::{self, JoinHandle}, 7 | time::SystemTime, 8 | }; 9 | 10 | use activity::{unmarshal_fields, ActivityId, ActivityKind, FfiFields, ResultKind}; 11 | use exporter::{exporter_main, Message}; 12 | use thread_local::ThreadLocal; 13 | use tokio::sync::mpsc; 14 | 15 | use crate::activity::ActivityRecord; 16 | mod activity; 17 | mod exporter; 18 | 19 | pub struct Context { 20 | /// This is `Some` always, except when the system is shut down 21 | exporter_thread: Option>, 22 | /// Channels to send stuff to the exporter thread 23 | channels: ThreadLocal>, 24 | /// Parent channel to clone into the thread local channels 25 | parent_channel: Mutex>, 26 | } 27 | 28 | fn exporter_channel(cx: &Context) -> &mpsc::UnboundedSender { 29 | cx.channels.get_or(|| { 30 | let chan = cx.parent_channel.lock().unwrap(); 31 | chan.clone() 32 | }) 33 | } 34 | 35 | fn tell(cx: &Context, message: Message) { 36 | let chan = exporter_channel(cx); 37 | chan.send(message).expect("sending record"); 38 | } 39 | 40 | #[no_mangle] 41 | pub extern "C" fn start_activity( 42 | cx: &Context, 43 | act: ActivityId, 44 | ty: ActivityKind, 45 | name: *const c_char, 46 | fields: FfiFields, 47 | parent: ActivityId, 48 | ) { 49 | let name = unsafe { CStr::from_ptr(name as *const _) }; 50 | let name_ = name.to_str().unwrap().to_owned(); 51 | let fields = unsafe { unmarshal_fields(fields) }; 52 | tell( 53 | cx, 54 | Message::BeginActivity( 55 | ActivityRecord { 56 | id: act, 57 | kind: ty, 58 | name: name_, 59 | parent: if parent == ActivityId(0) { 60 | None 61 | } else { 62 | Some(parent) 63 | }, 64 | fields, 65 | }, 66 | SystemTime::now(), 67 | ), 68 | ); 69 | } 70 | 71 | #[no_mangle] 72 | pub extern "C" fn on_result(cx: &Context, act: ActivityId, ty: ResultKind, fields: FfiFields) { 73 | let fields = unsafe { unmarshal_fields(fields) }; 74 | tell(cx, Message::Result(act, ty, SystemTime::now(), fields)) 75 | } 76 | 77 | #[no_mangle] 78 | pub extern "C" fn end_activity(cx: &Context, act: ActivityId) { 79 | tell(cx, Message::EndActivity(act, SystemTime::now())) 80 | } 81 | 82 | #[no_mangle] 83 | pub extern "C" fn initialize_plugin() -> *mut Context { 84 | let (send, recv) = mpsc::unbounded_channel(); 85 | let exporter_thread = thread::Builder::new() 86 | .name("OTel exporter thread".to_owned()) 87 | .spawn(|| exporter_main(recv)) 88 | .expect("startup exporter thread"); 89 | 90 | Box::into_raw(Box::new(Context { 91 | exporter_thread: Some(exporter_thread), 92 | channels: ThreadLocal::new(), 93 | parent_channel: Mutex::new(send), 94 | })) 95 | } 96 | 97 | /// SAFETY: 98 | /// The invariant that "cx" is exclusively available here is maintained by the 99 | /// other side of the FFI. Beware. 100 | #[no_mangle] 101 | pub extern "C" fn deinitialize_plugin(cx: &mut Context) { 102 | cx.parent_channel 103 | .lock() 104 | .unwrap() 105 | .send(Message::Terminate) 106 | .expect("exporter thread seems to have panicked"); 107 | 108 | // can't actually force the thread to terminate if something bad happens, 109 | // but we can join it 110 | if let Some(join_handle) = cx.exporter_thread.take() { 111 | join_handle.join().expect("panic in exporter thread"); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /test.nix: -------------------------------------------------------------------------------- 1 | # a test derivation that just sleeps a little 2 | let 3 | pkgs = import {}; 4 | in 5 | pkgs.stdenv.mkDerivation { 6 | unpackPhase = '' 7 | sleep 0.5 8 | ''; 9 | name = "test-0.0.0"; 10 | configurePhase = '' 11 | sleep 0.5 12 | ''; 13 | buildPhase = '' 14 | sleep 0.5 15 | ''; 16 | installPhase = '' 17 | sleep 0.2 18 | mkdir $out 19 | exit 1 20 | ''; 21 | } 22 | --------------------------------------------------------------------------------