From 343f28aa2349fba84862997b69688ce603513b14 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Thu, 30 Oct 2025 15:34:54 +0000 Subject: [PATCH 01/13] feat: M-LOG-STRUCTURED guide --- src/SUMMARY.md | 1 + src/guidelines/libs/README.md | 1 + src/guidelines/libs/building/TELEMETRY.md | 1 + .../libs/telemetry/M-LOG-STRUCTURED.md | 117 ++++++++++++++++++ src/guidelines/libs/telemetry/README.md | 5 + 5 files changed, 125 insertions(+) create mode 100644 src/guidelines/libs/building/TELEMETRY.md create mode 100644 src/guidelines/libs/telemetry/M-LOG-STRUCTURED.md create mode 100644 src/guidelines/libs/telemetry/README.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index fc1ba13..67348a4 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -9,6 +9,7 @@ - [UX](./guidelines/libs/ux/README.md) - [Resilience](./guidelines/libs/resilience/README.md) - [Building](./guidelines/libs/building/README.md) + - [Telemetry](./guidelines/libs/telemetry/README.md) - [Applications](./guidelines/apps/README.md) - [FFI](./guidelines/ffi/README.md) - [Safety](./guidelines/safety/README.md) diff --git a/src/guidelines/libs/README.md b/src/guidelines/libs/README.md index 8b6faff..81cc421 100644 --- a/src/guidelines/libs/README.md +++ b/src/guidelines/libs/README.md @@ -8,3 +8,4 @@ Guidelines for libraries. If your crate contains a `lib.rs` you should consider - [UX](./ux/) - [Resilience](./resilience/) - [Building](./building/) +- [Telemetry](./telemetry/) diff --git a/src/guidelines/libs/building/TELEMETRY.md b/src/guidelines/libs/building/TELEMETRY.md new file mode 100644 index 0000000..d7cadff --- /dev/null +++ b/src/guidelines/libs/building/TELEMETRY.md @@ -0,0 +1 @@ +# Telemetry diff --git a/src/guidelines/libs/telemetry/M-LOG-STRUCTURED.md b/src/guidelines/libs/telemetry/M-LOG-STRUCTURED.md new file mode 100644 index 0000000..544c3e9 --- /dev/null +++ b/src/guidelines/libs/telemetry/M-LOG-STRUCTURED.md @@ -0,0 +1,117 @@ + + +## Use Structured Logging with Message Templates (M-LOG-STRUCTURED) { #M-LOG-STRUCTURED } + +To enable efficient querying and analysis of log data while avoiding runtime allocation overhead and improving maintainability. +0.1 + +Logging should use structured events with named properties following the [message templates](https://messagetemplates.org/) specification. This avoids string formatting allocations, enables property-based querying, and makes debugging production issues significantly easier. + +> **Note:** Examples use the [`tracing`](https://docs.rs/tracing/) crate's `event!` macro, but these principles apply to any logging API that supports structured logging (e.g., `log`, `slog`, custom telemetry systems). + +### Core Principles + +#### 1. Avoid String Formatting - Use Message Templates + +String formatting allocates memory at runtime even if logs are filtered out. Message templates defer formatting until viewing time, avoiding unnecessary allocations. + +```rust +// ❌ DON'T: String formatting causes allocations at runtime +tracing::info!("Request started: {} {}", method, uri); +tracing::info!(format!("User {} logged in from {}", username, ip)); + +// ✅ DO: Use message templates with named properties +event!( + name: "http.request.started", + Level::INFO, + http.request.method = method.as_str(), + url.path.redacted = redacted_path, + http.request.body_size = body.len(), // Captured but not in message template + "request started: {{http.request.method}} {{url.path.redacted}}", +); +``` + +Properties not referenced in the message template (like `http.request.body_size` above) are still captured as structured data for querying, without cluttering the human-readable message. + +Message templates use `{{property}}` syntax for placeholders. Double braces `{{` escape Rust's formatting syntax, preserving the template literal in the string rather than formatting the value immediately. Properties are captured at log time, but string formatting happens only when viewing logs. + +#### 2. Name Your Events + +Named events enable grouping, filtering, and aggregating related log entries across your system. This makes debugging production issues tractable—you can find all instances of "payment.processing.failed" rather than searching through arbitrary text. + +Use hierarchical dot-notation: `..` + +```rust +// ❌ DON'T: Unnamed events +tracing::info!("Processing complete"); + +// ✅ DO: Named events +event!( + name: "payment.processing.completed", + Level::INFO, + payment.id = payment_id, + payment.amount = amount, + "payment {{payment.id}} processed", +); +``` + +#### 3. Follow OpenTelemetry Semantic Conventions + +Standardized property names enable consistent querying across services, automatic correlation in observability tools, and easier onboarding for developers familiar with OTel conventions. + +Use [OTel semantic conventions](https://opentelemetry.io/docs/specs/semconv/) for common attributes: + +```rust +event!( + name: "http.request.completed", + Level::INFO, + http.request.method = method.as_str(), // Standard OTel name + http.response.status_code = status.as_u16(), // Standard OTel name + url.scheme = url.scheme_str(), // Standard OTel name + url.path.template = "/api/users/{id}", // Standard OTel name + server.address = server_host, // Standard OTel name + "{{http.request.method}} {{url.path.template}} returned {{http.response.status_code}}", +); +``` + +Common conventions: +- HTTP: `http.request.method`, `http.response.status_code`, `url.scheme`, `url.path`, `server.address` +- Database: `db.system`, `db.name`, `db.operation`, `db.statement` +- Errors: `error.type`, `error.message`, `exception.type`, `exception.stacktrace` + +#### 4. Redact Sensitive Data + +Logs often contain PII, authentication tokens, or secrets that violate privacy regulations (GDPR, CCPA) or security policies. Redaction prevents data leaks and compliance violations. + +Consider privacy when logging URLs, headers, or bodies. Add redaction where needed based on your data sensitivity: + +```rust +// ❌ DON'T: Log potentially sensitive data +event!( + name: "http.request.started", + Level::INFO, + url.full = url.to_string(), // May contain tokens in query params! + "request to {{url.full}}", +); + +// ✅ DO: Redact sensitive parts +let redacted_path = redact_sensitive_query_params(&url); +event!( + name: "http.request.started", + Level::INFO, + url.scheme = url.scheme_str(), + url.path.template = template.as_deref(), + url.path.redacted = redacted_path, + "request to {{url.scheme}}://{{url.path.redacted}}", +); +``` + +Common items requiring redaction: query parameters with tokens, authorization headers, cookies, request/response bodies with secrets, file paths revealing user identity, IP addresses (when considered PII). + +Consider using the [`data_privacy`](https://crates.io/crates/data_privacy) crate for consistent redaction across your application. + +### Further Reading + +- [Message Templates Specification](https://messagetemplates.org/) +- [OpenTelemetry Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/) +- [OWASP Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html) diff --git a/src/guidelines/libs/telemetry/README.md b/src/guidelines/libs/telemetry/README.md new file mode 100644 index 0000000..13954db --- /dev/null +++ b/src/guidelines/libs/telemetry/README.md @@ -0,0 +1,5 @@ + + +# Telemetry + +{{#include M-LOG-STRUCTURED.md}} From cda2ae742c2d61d14efa3451cae61ed0140df1a5 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Thu, 30 Oct 2025 21:24:01 +0000 Subject: [PATCH 02/13] shorten the guide --- .../libs/telemetry/M-LOG-STRUCTURED.md | 105 +++++++++--------- 1 file changed, 50 insertions(+), 55 deletions(-) diff --git a/src/guidelines/libs/telemetry/M-LOG-STRUCTURED.md b/src/guidelines/libs/telemetry/M-LOG-STRUCTURED.md index 544c3e9..86c0acd 100644 --- a/src/guidelines/libs/telemetry/M-LOG-STRUCTURED.md +++ b/src/guidelines/libs/telemetry/M-LOG-STRUCTURED.md @@ -2,113 +2,108 @@ ## Use Structured Logging with Message Templates (M-LOG-STRUCTURED) { #M-LOG-STRUCTURED } -To enable efficient querying and analysis of log data while avoiding runtime allocation overhead and improving maintainability. +To minimize the cost of logging and to improve filtering capabilities. 0.1 -Logging should use structured events with named properties following the [message templates](https://messagetemplates.org/) specification. This avoids string formatting allocations, enables property-based querying, and makes debugging production issues significantly easier. +Logging should use structured events with named properties and message templates following the [message templates](https://messagetemplates.org/) specification. > **Note:** Examples use the [`tracing`](https://docs.rs/tracing/) crate's `event!` macro, but these principles apply to any logging API that supports structured logging (e.g., `log`, `slog`, custom telemetry systems). -### Core Principles +### Avoid String Formatting -#### 1. Avoid String Formatting - Use Message Templates - -String formatting allocates memory at runtime even if logs are filtered out. Message templates defer formatting until viewing time, avoiding unnecessary allocations. +String formatting allocates memory at runtime, even if logs are filtered out. Message templates defer formatting until viewing time. ```rust -// ❌ DON'T: String formatting causes allocations at runtime -tracing::info!("Request started: {} {}", method, uri); -tracing::info!(format!("User {} logged in from {}", username, ip)); +// DON'T: String formatting causes allocations +tracing::info!("file opened: {}", path); +tracing::info!(format!("file opened: {}", path)); -// ✅ DO: Use message templates with named properties +// DO: Use message templates with named properties event!( - name: "http.request.started", + name: "file.open.success", Level::INFO, - http.request.method = method.as_str(), - url.path.redacted = redacted_path, - http.request.body_size = body.len(), // Captured but not in message template - "request started: {{http.request.method}} {{url.path.redacted}}", + file.path = path.display(), + "file opened: {{file.path}}", ); ``` -Properties not referenced in the message template (like `http.request.body_size` above) are still captured as structured data for querying, without cluttering the human-readable message. - -Message templates use `{{property}}` syntax for placeholders. Double braces `{{` escape Rust's formatting syntax, preserving the template literal in the string rather than formatting the value immediately. Properties are captured at log time, but string formatting happens only when viewing logs. +Message templates use `{{property}}` syntax for placeholders. Double braces escape Rust's formatting syntax, preserving the template literal. Properties are captured at log time, but string formatting happens only when viewing logs. -#### 2. Name Your Events - -Named events enable grouping, filtering, and aggregating related log entries across your system. This makes debugging production issues tractable—you can find all instances of "payment.processing.failed" rather than searching through arbitrary text. +### Name Your Events Use hierarchical dot-notation: `..` ```rust -// ❌ DON'T: Unnamed events -tracing::info!("Processing complete"); +// DON'T: Unnamed events +event!( + Level::INFO, + file.path = file_path, + "file {{file.path}} processed succesfully", +); -// ✅ DO: Named events +// DO: Named events event!( - name: "payment.processing.completed", + name: "file.processing.success", // event identifier Level::INFO, - payment.id = payment_id, - payment.amount = amount, - "payment {{payment.id}} processed", + file.path = file_path, + "file {{file.path}} processed succesfully", ); ``` -#### 3. Follow OpenTelemetry Semantic Conventions +Named events enable grouping and filtering across log entries. -Standardized property names enable consistent querying across services, automatic correlation in observability tools, and easier onboarding for developers familiar with OTel conventions. +### Follow OpenTelemetry Semantic Conventions -Use [OTel semantic conventions](https://opentelemetry.io/docs/specs/semconv/) for common attributes: +Use [OTel semantic conventions](https://opentelemetry.io/docs/specs/semconv/) for common attributes if needed. +This enables standardization and interoperability. ```rust event!( - name: "http.request.completed", + name: "file.write.success", Level::INFO, - http.request.method = method.as_str(), // Standard OTel name - http.response.status_code = status.as_u16(), // Standard OTel name - url.scheme = url.scheme_str(), // Standard OTel name - url.path.template = "/api/users/{id}", // Standard OTel name - server.address = server_host, // Standard OTel name - "{{http.request.method}} {{url.path.template}} returned {{http.response.status_code}}", + file.path = path.display(), // Standard OTel name + file.size = bytes_written, // Standard OTel name + file.directory = dir_path, // Standard OTel name + file.extension = extension, // Standard OTel name + file.operation = "write", // Custom name + "{{file.operation}} {{file.size}} bytes to {{file.path}} in {{file.directory}} extension={{file.extension}}", ); ``` Common conventions: + - HTTP: `http.request.method`, `http.response.status_code`, `url.scheme`, `url.path`, `server.address` +- File: `file.path`, `file.directory`, `file.name`, `file.extension`, `file.size` - Database: `db.system`, `db.name`, `db.operation`, `db.statement` - Errors: `error.type`, `error.message`, `exception.type`, `exception.stacktrace` -#### 4. Redact Sensitive Data - -Logs often contain PII, authentication tokens, or secrets that violate privacy regulations (GDPR, CCPA) or security policies. Redaction prevents data leaks and compliance violations. +### Redact Sensitive Data -Consider privacy when logging URLs, headers, or bodies. Add redaction where needed based on your data sensitivity: +Do not log plain sensitive data as this might lead to privacy and security incidents. ```rust -// ❌ DON'T: Log potentially sensitive data +// DON'T: Log potentially sensitive data event!( - name: "http.request.started", + name: "file.operation.started", Level::INFO, - url.full = url.to_string(), // May contain tokens in query params! - "request to {{url.full}}", + user.email = user.email, // Sensitive data + file.name = "license.txt", + "reading file {{file.name}} for user {{user.email}}", ); -// ✅ DO: Redact sensitive parts -let redacted_path = redact_sensitive_query_params(&url); +// DO: Redact sensitive parts event!( - name: "http.request.started", + name: "file.operation.started", Level::INFO, - url.scheme = url.scheme_str(), - url.path.template = template.as_deref(), - url.path.redacted = redacted_path, - "request to {{url.scheme}}://{{url.path.redacted}}", + user.email.redacted = redact_email(user.email), + file.name = "license.txt", + "reading file {{file.name}} for user {{user.email.redacted}}", ); ``` -Common items requiring redaction: query parameters with tokens, authorization headers, cookies, request/response bodies with secrets, file paths revealing user identity, IP addresses (when considered PII). +Sensitive data include user email, file paths revealing user identity, filenames containing secrets or tokens, file contents with PII, temporary file paths with session IDs and more. -Consider using the [`data_privacy`](https://crates.io/crates/data_privacy) crate for consistent redaction across your application. +Consider using the [`data_privacy`](https://crates.io/crates/data_privacy) crate for consistent redaction. ### Further Reading From 8121c4a0e0fe427a49a7677bf19954723fb9944f Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Thu, 30 Oct 2025 21:51:41 +0000 Subject: [PATCH 03/13] cleanup --- src/SUMMARY.md | 1 - src/guidelines/libs/README.md | 1 - src/guidelines/libs/telemetry/README.md | 5 ----- .../{libs/telemetry => universal}/M-LOG-STRUCTURED.md | 0 src/guidelines/universal/README.md | 1 + 5 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 src/guidelines/libs/telemetry/README.md rename src/guidelines/{libs/telemetry => universal}/M-LOG-STRUCTURED.md (100%) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 67348a4..fc1ba13 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -9,7 +9,6 @@ - [UX](./guidelines/libs/ux/README.md) - [Resilience](./guidelines/libs/resilience/README.md) - [Building](./guidelines/libs/building/README.md) - - [Telemetry](./guidelines/libs/telemetry/README.md) - [Applications](./guidelines/apps/README.md) - [FFI](./guidelines/ffi/README.md) - [Safety](./guidelines/safety/README.md) diff --git a/src/guidelines/libs/README.md b/src/guidelines/libs/README.md index 81cc421..8b6faff 100644 --- a/src/guidelines/libs/README.md +++ b/src/guidelines/libs/README.md @@ -8,4 +8,3 @@ Guidelines for libraries. If your crate contains a `lib.rs` you should consider - [UX](./ux/) - [Resilience](./resilience/) - [Building](./building/) -- [Telemetry](./telemetry/) diff --git a/src/guidelines/libs/telemetry/README.md b/src/guidelines/libs/telemetry/README.md deleted file mode 100644 index 13954db..0000000 --- a/src/guidelines/libs/telemetry/README.md +++ /dev/null @@ -1,5 +0,0 @@ - - -# Telemetry - -{{#include M-LOG-STRUCTURED.md}} diff --git a/src/guidelines/libs/telemetry/M-LOG-STRUCTURED.md b/src/guidelines/universal/M-LOG-STRUCTURED.md similarity index 100% rename from src/guidelines/libs/telemetry/M-LOG-STRUCTURED.md rename to src/guidelines/universal/M-LOG-STRUCTURED.md diff --git a/src/guidelines/universal/README.md b/src/guidelines/universal/README.md index 72f9048..3f464a1 100644 --- a/src/guidelines/universal/README.md +++ b/src/guidelines/universal/README.md @@ -13,3 +13,4 @@ {{#include M-PANIC-IS-STOP.md}} {{#include M-PANIC-ON-BUG.md}} {{#include M-DOCUMENTED-MAGIC.md}} +{{#include M-LOG-STRUCTURED.md}} From a81f8e89c9ce7e763a7897e0df289a3ddb414065 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Thu, 30 Oct 2025 21:53:06 +0000 Subject: [PATCH 04/13] Delete TELEMETRY.md --- src/guidelines/libs/building/TELEMETRY.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/guidelines/libs/building/TELEMETRY.md diff --git a/src/guidelines/libs/building/TELEMETRY.md b/src/guidelines/libs/building/TELEMETRY.md deleted file mode 100644 index d7cadff..0000000 --- a/src/guidelines/libs/building/TELEMETRY.md +++ /dev/null @@ -1 +0,0 @@ -# Telemetry From 77068c104e2b385bb43b66daca840a3e8800a369 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Thu, 30 Oct 2025 21:55:43 +0000 Subject: [PATCH 05/13] cleanup --- src/guidelines/universal/M-LOG-STRUCTURED.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/guidelines/universal/M-LOG-STRUCTURED.md b/src/guidelines/universal/M-LOG-STRUCTURED.md index 86c0acd..be98307 100644 --- a/src/guidelines/universal/M-LOG-STRUCTURED.md +++ b/src/guidelines/universal/M-LOG-STRUCTURED.md @@ -54,8 +54,7 @@ Named events enable grouping and filtering across log entries. ### Follow OpenTelemetry Semantic Conventions -Use [OTel semantic conventions](https://opentelemetry.io/docs/specs/semconv/) for common attributes if needed. -This enables standardization and interoperability. +Use [OTel semantic conventions](https://opentelemetry.io/docs/specs/semconv/) for common attributes if needed. This enables standardization and interoperability. ```rust event!( From 32f850e718658c900d20f56f8e51ca3bb66ae15f Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Thu, 30 Oct 2025 21:59:22 +0000 Subject: [PATCH 06/13] Update M-LOG-STRUCTURED.md --- src/guidelines/universal/M-LOG-STRUCTURED.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/guidelines/universal/M-LOG-STRUCTURED.md b/src/guidelines/universal/M-LOG-STRUCTURED.md index be98307..50d713c 100644 --- a/src/guidelines/universal/M-LOG-STRUCTURED.md +++ b/src/guidelines/universal/M-LOG-STRUCTURED.md @@ -5,13 +5,17 @@ To minimize the cost of logging and to improve filtering capabilities. 0.1 -Logging should use structured events with named properties and message templates following the [message templates](https://messagetemplates.org/) specification. +Logging should use structured events with named properties and message templates following +the [message templates](https://messagetemplates.org/) specification. -> **Note:** Examples use the [`tracing`](https://docs.rs/tracing/) crate's `event!` macro, but these principles apply to any logging API that supports structured logging (e.g., `log`, `slog`, custom telemetry systems). +> **Note:** Examples use the [`tracing`](https://docs.rs/tracing/) crate's `event!` macro, +but these principles apply to any logging API that supports structured logging (e.g., `log`, +`slog`, custom telemetry systems). ### Avoid String Formatting -String formatting allocates memory at runtime, even if logs are filtered out. Message templates defer formatting until viewing time. +String formatting allocates memory at runtime, even if logs are filtered out. Message templates defer +formatting until viewing time. ```rust // DON'T: String formatting causes allocations @@ -27,7 +31,8 @@ event!( ); ``` -Message templates use `{{property}}` syntax for placeholders. Double braces escape Rust's formatting syntax, preserving the template literal. Properties are captured at log time, but string formatting happens only when viewing logs. +Message templates use `{{property}}` syntax for placeholders. Double braces escape Rust's formatting syntax, +preserving the template literal. Properties are captured at log time, but string formatting happens only when viewing logs. ### Name Your Events @@ -54,7 +59,8 @@ Named events enable grouping and filtering across log entries. ### Follow OpenTelemetry Semantic Conventions -Use [OTel semantic conventions](https://opentelemetry.io/docs/specs/semconv/) for common attributes if needed. This enables standardization and interoperability. +Use [OTel semantic conventions](https://opentelemetry.io/docs/specs/semconv/) for common attributes if needed. +This enables standardization and interoperability. ```rust event!( @@ -100,7 +106,8 @@ event!( ); ``` -Sensitive data include user email, file paths revealing user identity, filenames containing secrets or tokens, file contents with PII, temporary file paths with session IDs and more. +Sensitive data include user email, file paths revealing user identity, filenames containing secrets or tokens, +file contents with PII, temporary file paths with session IDs and more. Consider using the [`data_privacy`](https://crates.io/crates/data_privacy) crate for consistent redaction. From 0bd2ceaabafdbe588cf3d28655f91ba2d46136e5 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Thu, 30 Oct 2025 22:03:23 +0000 Subject: [PATCH 07/13] Update M-LOG-STRUCTURED.md --- src/guidelines/universal/M-LOG-STRUCTURED.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/guidelines/universal/M-LOG-STRUCTURED.md b/src/guidelines/universal/M-LOG-STRUCTURED.md index 50d713c..3021c3d 100644 --- a/src/guidelines/universal/M-LOG-STRUCTURED.md +++ b/src/guidelines/universal/M-LOG-STRUCTURED.md @@ -17,7 +17,7 @@ but these principles apply to any logging API that supports structured logging ( String formatting allocates memory at runtime, even if logs are filtered out. Message templates defer formatting until viewing time. -```rust +```rust,ignore // DON'T: String formatting causes allocations tracing::info!("file opened: {}", path); tracing::info!(format!("file opened: {}", path)); @@ -38,7 +38,7 @@ preserving the template literal. Properties are captured at log time, but string Use hierarchical dot-notation: `..` -```rust +```rust,ignore // DON'T: Unnamed events event!( Level::INFO, @@ -62,7 +62,7 @@ Named events enable grouping and filtering across log entries. Use [OTel semantic conventions](https://opentelemetry.io/docs/specs/semconv/) for common attributes if needed. This enables standardization and interoperability. -```rust +```rust,ignore event!( name: "file.write.success", Level::INFO, @@ -86,7 +86,7 @@ Common conventions: Do not log plain sensitive data as this might lead to privacy and security incidents. -```rust +```rust,ignore // DON'T: Log potentially sensitive data event!( name: "file.operation.started", From aa4a3d66f5a719b401d43cbd2edb07eceddf4d70 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Thu, 30 Oct 2025 22:08:56 +0000 Subject: [PATCH 08/13] Update M-LOG-STRUCTURED.md --- src/guidelines/universal/M-LOG-STRUCTURED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/guidelines/universal/M-LOG-STRUCTURED.md b/src/guidelines/universal/M-LOG-STRUCTURED.md index 3021c3d..18b05e0 100644 --- a/src/guidelines/universal/M-LOG-STRUCTURED.md +++ b/src/guidelines/universal/M-LOG-STRUCTURED.md @@ -79,7 +79,7 @@ Common conventions: - HTTP: `http.request.method`, `http.response.status_code`, `url.scheme`, `url.path`, `server.address` - File: `file.path`, `file.directory`, `file.name`, `file.extension`, `file.size` -- Database: `db.system`, `db.name`, `db.operation`, `db.statement` +- Database: `db.system.name`, `db.namespace`, `db.operation.name`, `db.query.text` - Errors: `error.type`, `error.message`, `exception.type`, `exception.stacktrace` ### Redact Sensitive Data From 421945b3b12836658c9548c7e1e6659ef7933073 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Fri, 31 Oct 2025 13:23:34 +0000 Subject: [PATCH 09/13] Update M-LOG-STRUCTURED.md --- src/guidelines/universal/M-LOG-STRUCTURED.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/guidelines/universal/M-LOG-STRUCTURED.md b/src/guidelines/universal/M-LOG-STRUCTURED.md index 18b05e0..4f76478 100644 --- a/src/guidelines/universal/M-LOG-STRUCTURED.md +++ b/src/guidelines/universal/M-LOG-STRUCTURED.md @@ -31,8 +31,11 @@ event!( ); ``` -Message templates use `{{property}}` syntax for placeholders. Double braces escape Rust's formatting syntax, -preserving the template literal. Properties are captured at log time, but string formatting happens only when viewing logs. +> **Note**: Use `{{property}}` syntax in message templates. Double braces preserve the literal text +> while escaping Rust's format syntax. String formatting is deferred until logs are viewed. +> +> This pattern may trigger Clippy's [`literal_string_with_formatting_args`](https://rust-lang.github.io/rust-clippy/stable/index.html#literal_string_with_formatting_args) +> warning so consider suppressing it for logging. ### Name Your Events From 7f5d1b7ddc6ca344821ecfb6453a1ae6cfc93b8b Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Fri, 31 Oct 2025 13:43:23 +0000 Subject: [PATCH 10/13] clarification --- src/guidelines/universal/M-LOG-STRUCTURED.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/guidelines/universal/M-LOG-STRUCTURED.md b/src/guidelines/universal/M-LOG-STRUCTURED.md index 4f76478..fd5981b 100644 --- a/src/guidelines/universal/M-LOG-STRUCTURED.md +++ b/src/guidelines/universal/M-LOG-STRUCTURED.md @@ -15,7 +15,8 @@ but these principles apply to any logging API that supports structured logging ( ### Avoid String Formatting String formatting allocates memory at runtime, even if logs are filtered out. Message templates defer -formatting until viewing time. +formatting until viewing time. We recommend that message template includes all named properties for easier +inspection at viewing time. ```rust,ignore // DON'T: String formatting causes allocations From f076d8394395170ca8be4bc681cc44efdb8f8e02 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Fri, 31 Oct 2025 13:48:19 +0000 Subject: [PATCH 11/13] Update M-LOG-STRUCTURED.md --- src/guidelines/universal/M-LOG-STRUCTURED.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/guidelines/universal/M-LOG-STRUCTURED.md b/src/guidelines/universal/M-LOG-STRUCTURED.md index fd5981b..d764aea 100644 --- a/src/guidelines/universal/M-LOG-STRUCTURED.md +++ b/src/guidelines/universal/M-LOG-STRUCTURED.md @@ -14,9 +14,8 @@ but these principles apply to any logging API that supports structured logging ( ### Avoid String Formatting -String formatting allocates memory at runtime, even if logs are filtered out. Message templates defer -formatting until viewing time. We recommend that message template includes all named properties for easier -inspection at viewing time. +String formatting allocates memory at runtime. Message templates defer formatting until viewing time. +We recommend that message template includes all named properties for easier inspection at viewing time. ```rust,ignore // DON'T: String formatting causes allocations From 0b829dafb123d0cd4eb67655b36dc6b3d3153b12 Mon Sep 17 00:00:00 2001 From: Ralf Biedert Date: Fri, 31 Oct 2025 15:41:02 +0100 Subject: [PATCH 12/13] Cleanup, align with existing guidelines, link. --- src/guidelines/checklist/README.md | 2 ++ src/guidelines/universal/M-LOG-STRUCTURED.md | 21 +++++++------------ .../universal/M-STATIC-VERIFICATION.md | 3 +++ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/guidelines/checklist/README.md b/src/guidelines/checklist/README.md index 88366ab..45683a2 100644 --- a/src/guidelines/checklist/README.md +++ b/src/guidelines/checklist/README.md @@ -14,6 +14,7 @@ - [ ] Panic Means 'Stop the Program' ([M-PANIC-IS-STOP]) - [ ] Detected Programming Bugs are Panics, Not Errors ([M-PANIC-ON-BUG]) - [ ] All Magic Values and Behaviors are Documented ([M-DOCUMENTED-MAGIC]) + - [ ] Use Structured Logging with Message Templates ([M-LOG-STRUCTURED]) - **Library / Interoperability** - [ ] Types are Send ([M-TYPES-SEND]) - [ ] Native Escape Hatches ([M-ESCAPE-HATCHES]) @@ -73,6 +74,7 @@ [M-PANIC-IS-STOP]: ../universal/#M-PANIC-IS-STOP [M-PANIC-ON-BUG]: ../universal/#M-PANIC-ON-BUG [M-DOCUMENTED-MAGIC]: ../universal/#M-DOCUMENTED-MAGIC +[M-LOG-STRUCTURED]: ../universal/#M-LOG-STRUCTURED [M-TYPES-SEND]: ../libs/interop/#M-TYPES-SEND diff --git a/src/guidelines/universal/M-LOG-STRUCTURED.md b/src/guidelines/universal/M-LOG-STRUCTURED.md index d764aea..ce1efde 100644 --- a/src/guidelines/universal/M-LOG-STRUCTURED.md +++ b/src/guidelines/universal/M-LOG-STRUCTURED.md @@ -18,11 +18,11 @@ String formatting allocates memory at runtime. Message templates defer formattin We recommend that message template includes all named properties for easier inspection at viewing time. ```rust,ignore -// DON'T: String formatting causes allocations +// Bad: String formatting causes allocations tracing::info!("file opened: {}", path); tracing::info!(format!("file opened: {}", path)); -// DO: Use message templates with named properties +// Good: Message templates with named properties event!( name: "file.open.success", Level::INFO, @@ -31,25 +31,22 @@ event!( ); ``` -> **Note**: Use `{{property}}` syntax in message templates. Double braces preserve the literal text +> **Note**: Use `{{property}}` the syntax in message templates which preserves the literal text > while escaping Rust's format syntax. String formatting is deferred until logs are viewed. -> -> This pattern may trigger Clippy's [`literal_string_with_formatting_args`](https://rust-lang.github.io/rust-clippy/stable/index.html#literal_string_with_formatting_args) -> warning so consider suppressing it for logging. ### Name Your Events Use hierarchical dot-notation: `..` ```rust,ignore -// DON'T: Unnamed events +// Bad: Unnamed events event!( Level::INFO, file.path = file_path, "file {{file.path}} processed succesfully", ); -// DO: Named events +// Good: Named events event!( name: "file.processing.success", // event identifier Level::INFO, @@ -90,7 +87,7 @@ Common conventions: Do not log plain sensitive data as this might lead to privacy and security incidents. ```rust,ignore -// DON'T: Log potentially sensitive data +// Bad: Logs potentially sensitive data event!( name: "file.operation.started", Level::INFO, @@ -99,7 +96,7 @@ event!( "reading file {{file.name}} for user {{user.email}}", ); -// DO: Redact sensitive parts +// Good: Redact sensitive parts event!( name: "file.operation.started", Level::INFO, @@ -110,9 +107,7 @@ event!( ``` Sensitive data include user email, file paths revealing user identity, filenames containing secrets or tokens, -file contents with PII, temporary file paths with session IDs and more. - -Consider using the [`data_privacy`](https://crates.io/crates/data_privacy) crate for consistent redaction. +file contents with PII, temporary file paths with session IDs and more. Consider using the [`data_privacy`](https://crates.io/crates/data_privacy) crate for consistent redaction. ### Further Reading diff --git a/src/guidelines/universal/M-STATIC-VERIFICATION.md b/src/guidelines/universal/M-STATIC-VERIFICATION.md index 5328880..4ae45a8 100644 --- a/src/guidelines/universal/M-STATIC-VERIFICATION.md +++ b/src/guidelines/universal/M-STATIC-VERIFICATION.md @@ -73,6 +73,9 @@ unnecessary_safety_doc = "warn" unneeded_field_pattern = "warn" unused_result_ok = "warn" +# May cause issues with structured logging otherwise. +literal_string_with_formatting_args = "allow" + # Define custom opt outs here # ... ``` From e78f39d1cbe79050221a0404e34355038f835f5a Mon Sep 17 00:00:00 2001 From: Ralf Biedert Date: Fri, 31 Oct 2025 15:42:49 +0100 Subject: [PATCH 13/13] Disable annoying lint. --- .markdownlint.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.markdownlint.json b/.markdownlint.json index ab69aae..2b1559c 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -1,7 +1,5 @@ { - "MD013": { - "line_length": 160 - }, + "MD013": false, "MD033": false, "MD041": false } \ No newline at end of file