Skip to content

ADR-0019: Observability - Field Naming: snake_case + dot Convention

During incident response, searching Logs for the requestCategory field value found in a Trace Span returned 0 results. Logs recorded the same data as request_category. Metrics used yet a third name, request-category. The same business event was recorded with different field names across each Pillar, making Trace-to-Logs transitions impossible in Grafana, and correlation queries on dashboards required manual field name mapping every time.

A single field naming convention enforced across all 3-Pillars was needed to enable immediate correlation analysis, while being naturally compatible with OpenTelemetry Semantic Conventions.

  • Option 1: camelCase (requestCategoryName, responseStatus)
  • Option 2: kebab-case (request-category-name, response-status)
  • Option 3: snake_case + dot (request.category.name, response.status)
  • Option 4: underscore only (request_category_name, response_status)

Option 3: Adopt the snake_case + dot convention.

Rather than inventing a proprietary convention, the pattern already used by OpenTelemetry Semantic Conventions (http.request.method, db.system, rpc.service) is adopted as-is. When aligned with industry standards, there is no need to separately verify tool compatibility.

The following naming rules apply to all observability fields:

  • Namespace separation: dot (.) expresses hierarchy (e.g., request.category.name, response.status, error.code)
  • Word separation: snake_case (e.g., error.stack_trace, request.content_type)
  • Count field rule: Metric names use .count (dot separator); attributes use _count (underscore separator)
  • Positive: Searching Logs with the error.code field name found in a Trace Span returns results immediately. Grafana’s Trace-to-Logs transitions work without field name mapping. The dot hierarchy enables tree-structured field exploration like request.* and error.* in Grafana and Kibana. The entire team only needs to remember one principle: “follow the OpenTelemetry convention.”
  • Negative: All fields previously recorded in camelCase or underscore must be migrated, and existing dashboard queries must be updated as well. Some tools that do not interpret dot separators as namespaces may require escaping.
  • Verify that all Trace Attributes, Metric Attributes, and Structured Log Properties generated by the framework follow the snake_case + dot convention.
  • Verify that the same field name can be used to correlate Traces and Logs on Grafana dashboards.
  • Verify that count fields correctly use .count for metrics and _count for attributes.
  • Pros: Familiar to C#/JavaScript developers. Matches System.Text.Json’s default policy (JsonNamingPolicy.CamelCase), making serialization convenient.
  • Cons: Misaligned with OpenTelemetry Semantic Conventions (http.request.method), causing framework-generated fields and user-defined fields to have mixed naming. Cannot express hierarchy, so names become long like requestCategoryName, and tree exploration like request.* is impossible in Grafana.
  • Pros: Consistent with URLs and HTTP headers (Content-Type, Accept-Language), offering good readability.
  • Cons: Serilog’s LogContext.PushProperty does not support property names containing hyphens. Cannot be used as C# identifiers, requiring all field names to be managed as string literals with high typo risk. Misaligned with OpenTelemetry conventions.
  • Pros: Fully aligned with OpenTelemetry Semantic Conventions like http.request.method and db.system, so framework fields and user-defined fields follow the same pattern. Dot separation enables request.* and error.* tree exploration in Grafana and automatic field grouping in Elasticsearch. Guarantees identical field names across all 3-Pillars (Trace, Metrics, Logs), enabling immediate correlation query operation.
  • Cons: Dot-containing string constants like "error.stack_trace" must be managed in C# code. Some Elasticsearch configurations may interpret dots as object nesting, causing unintended mappings.
  • Pros: Matches Prometheus naming conventions (http_request_duration_seconds). No dot-related issues. Easy to express as C# const string.
  • Cons: In request_category_name, it is impossible to tell whether request is a namespace or part of a word, losing hierarchical structure. Misaligned with OpenTelemetry Semantic Conventions’ dot hierarchy, mixing framework fields (http.request.method) and user-defined fields (request_category_name). Readability degrades sharply as field names lengthen with consecutive _ characters.