{"id":29675804,"url":"https://github.com/oxidecomputer/slog-error-chain","last_synced_at":"2025-07-22T23:38:48.687Z","repository":{"id":212740626,"uuid":"732166974","full_name":"oxidecomputer/slog-error-chain","owner":"oxidecomputer","description":"Logging Rust errors with context","archived":false,"fork":false,"pushed_at":"2025-06-22T03:52:01.000Z","size":29,"stargazers_count":5,"open_issues_count":9,"forks_count":1,"subscribers_count":19,"default_branch":"main","last_synced_at":"2025-06-22T04:27:01.446Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oxidecomputer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-12-15T20:17:14.000Z","updated_at":"2025-04-04T04:33:15.000Z","dependencies_parsed_at":"2023-12-16T00:11:40.553Z","dependency_job_id":"347b03d0-fc4d-4b68-ae53-09f0fd57ff74","html_url":"https://github.com/oxidecomputer/slog-error-chain","commit_stats":null,"previous_names":["oxidecomputer/slog-error-chain"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/oxidecomputer/slog-error-chain","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oxidecomputer%2Fslog-error-chain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oxidecomputer%2Fslog-error-chain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oxidecomputer%2Fslog-error-chain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oxidecomputer%2Fslog-error-chain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oxidecomputer","download_url":"https://codeload.github.com/oxidecomputer/slog-error-chain/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oxidecomputer%2Fslog-error-chain/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266591233,"owners_count":23953082,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-22T23:38:46.076Z","updated_at":"2025-07-22T23:38:48.656Z","avatar_url":"https://github.com/oxidecomputer.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Overview\n\n`slog-error-chain` provides `std::fmt::Display`, `slog::KV`, and `slog::Value`\nadapters to report the full chain of error causes from `std::error::Error`s, and\na proc macro to derive `slog::KV` and `slog::Value` implementations for error\ntypes which will log the full chain of error causes.\n\nThis crate was born out of a use of `thiserror` to derive `std::error::Error`\nimplementations on error enums, although it does not depend on `thiserror` and\nwill work with any `Error`s. Error enums often wrap other error sources, such\nas:\n\n```rust\n#[derive(Debug, thiserror::Error)]\nenum MyError {\n    #[error(\"an I/O error occurred trying to open {}\", .path.display())]\n    OpeningFile {\n        path: PathBuf,\n        #[source]\n        err: io::Error,\n    },\n}\n```\n\nThe `Display` implementation produced by deriving `thiserror::Error` only prints\nthe topmost error, and does not print any causes. Given the example above, a\n`MyError::OpeningFile { .. }` error will `Display`-format as\n\n```text\n# println!(\"{my_error}\")\nan I/O error occurred trying to open /some/path\n```\n\nThis crate provides `InlineErrorChain`, which is an adapter that will print the\nfull error chain:\n\n```text\n# println!(\"{}\", InlineErrorChain::new(\u0026my_error))\nan I/O error occurred trying to open /some/path: file not found\n```\n\n`InlineErrorChain` also implements `slog::Value` and `slog::KV`, allowing it to\nbe logged directly:\n\n```rust\n// explicit key\ninfo!(\n    log, \"something happened\"; \"my-key\" =\u003e InlineErrorChain::new(\u0026err),\n);\n\n// key omitted; will log with the key \"error\"\ninfo!(\n    log, \"something happened\"; InlineErrorChain::new(\u0026err),\n);\n```\n\nWith the `derive` feature enabled, error types can `#[derive(SlogInlineError)]`\nto gain `slog::Value` and `slog::KV` implementations on themselves, allowing\nthem to be logged directly:\n\n```rust\nuse slog_error_chain::SlogInlineError;\n\n#[derive(Debug, thiserror::Error, SlogInlineError)]\nenum MyError {\n    #[error(\"an I/O error occurred trying to open {}\", .path.display())]\n    OpeningFile {\n        path: PathBuf,\n        #[source]\n        err: io::Error,\n    },\n}\n\nlet err = MyError::OpeningFile { .. };\n\n// explicit key; logs the full chain\ninfo!(log, \"something happened\"; \"my-key\" =\u003e \u0026err);\n\n// implicit key; logs the full chain with the key \"error\"\ninfo!(log, \"something happened\"; \u0026err);\n```\n\n### Aside: Embedding Source Error Strings\n\nAn easy solution to reach for when encountering the \"printing an error doesn't\nshow the underlying cause\" problem is to embed the inner error in the outer\nerror's display string, such as by adding `: {err}` to the above example:\n\n```rust\n#[derive(Debug, thiserror::Error)]\nenum MyError {\n    #[error(\"an I/O error occurred trying to open {}: {err}\", .path.display())]\n    OpeningFile {\n        path: PathBuf,\n        #[source]\n        err: io::Error,\n    },\n}\n```\n\nDoing so will make the `Display` implementation of `MyError` _look_ reasonable:\n\n```text\n# println!(\"{my_error}\")\nan I/O error occurred trying to open /some/path: file not found\n```\n\nbut this is incorrect! If you use an error adapter that knows how to walk the\nfull chain of errors (such as `InlineErrorChain` or `anyhow::Error`), you will\nsee \"double-speak\" along the chain:\n\n```text\n# println!(\"{}\", InlineErrorChain::new(\u0026my_error))\nan I/O error occurred trying to open /some/path: file not found: file not found\n```\n\nThe amount of doubled error text will compound as additional errors are added to\nthe chain, as each layer reprints the remainder of the chain starting from\nitself.\n\n### Cargo Features\n\n`slog-error-chain` gates additional functionality behind two cargo features:\n\n* `derive`: Provides the `#[derive(SlogInlineError)]` proc macro that can be\n  applied to error types; it provides implementations of `slog::Value` and\n  `slog::KV` that delegate to `InlineErrorChain`.\n* `nested-values`: Provides the `ArrayErrorChain` type, which is similar to\n  `InlineErrorChain` except that it also implements `slog::SerdeValue`, and for\n  loggers that support nested values, the error will be logged as an array of\n  strings (one element per error in the chain).\n\nIf both `derive` and `nested-values` are enabled, the\n`#[derive(SlogArrayError)]` proc macro is provided. This gives implementations\nof `slog::Value`, `slog::SerdeValue`, and `slog::KV` for the error type that\ndelegates to `ArrayErrorChain`. However, implementing `slog::SerdeValue` also\nrequires implementing `serde::Serialize`, so this proc macro cannot be used with\nerror types that already implement `serde::Serialize`.\n\n### Examples\n\n[`basic`](./examples/basic.rs) demonstrates raw `InlineErrorChain` usage:\n\n```console\n% cargo run --example basic\nDec 15 20:34:03.682 INFO logging error with Display impl, err: an I/O error occurred trying to open /some/path\nDec 15 20:34:03.682 INFO logging error with InlineErrorChain, explicit key, my-key: an I/O error occurred trying to open /some/path: custom I/O error\nDec 15 20:34:03.682 INFO logging error with InlineErrorChain, implicit key, error: an I/O error occurred trying to open /some/path: custom I/O error\n```\n\n[`derive`](./examples/derive.rs) demonstrates `#[derive(SlogInlineError)]`:\n\n```console\n% cargo run --example derive --features derive\nDec 15 20:44:45.976 INFO derived slog::Value with explicit key, my-key: outer error: inner error: custom I/O error\nDec 15 20:44:45.976 INFO derived slog::KV using implicit error key, error: outer error: inner error: custom I/O error\n```\n\n[`nested-values`](./examples/nested-values.rs) demonstrates the `nested-values`\nfeature (along with `#[derive(SlogArrayError)]`:\n\n```console\n% cargo run --example nested-values --features derive,nested-values\nDec 15 20:34:25.329 INFO slog-term inline error formatting, explicit key, my-key: outer error: inner error: custom I/O error\nDec 15 20:34:25.329 INFO slog-term inline error formatting, implicit key, error: outer error: inner error: custom I/O error\nDec 15 20:34:25.329 INFO slog-term structured error formatting, explicit key, my-key: outer error: inner error: custom I/O error\nDec 15 20:34:25.329 INFO slog-term structured error formatting, implicit key, error: outer error: inner error: custom I/O error\n{\"msg\":\"slog-json inline error formatting, explicit key\",\"level\":\"INFO\",\"ts\":\"2023-12-15T20:34:25.329726569Z\",\"my-key\":\"outer error: inner error: custom I/O error\"}\n{\"msg\":\"slog-json inline error formatting, implicit key\",\"level\":\"INFO\",\"ts\":\"2023-12-15T20:34:25.329768879Z\",\"error\":\"outer error: inner error: custom I/O error\"}\n{\"msg\":\"slog-json structured error formatting, explicit key\",\"level\":\"INFO\",\"ts\":\"2023-12-15T20:34:25.329805499Z\",\"my-key\":[\"outer error\",\"inner error\",\"custom I/O error\"]}\n{\"msg\":\"slog-json structured error formatting, implicit key\",\"level\":\"INFO\",\"ts\":\"2023-12-15T20:34:25.329853429Z\",\"error\":[\"outer error\",\"inner error\",\"custom I/O error\"]}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foxidecomputer%2Fslog-error-chain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foxidecomputer%2Fslog-error-chain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foxidecomputer%2Fslog-error-chain/lists"}