feat: add multiline log collection support for stack traces #691
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem Statement
When collecting logs from Java/Spring Boot applications (or any application that produces multi-line log entries like stack traces), each line of a stack trace is currently collected as a separate log entry in Dash0. This makes it difficult to:
Example: Before (Current Behavior)
With the current operator, a Java exception with a stack trace appears as multiple separate log entries:
Each line of the stack trace appears as its own log record, making it hard to see the full context of the error.
Proposed Solution
I've implemented support for configuring multiline log collection in the
Dash0MonitoringCRD. This allows users to specify a regex pattern that identifies the start (or end) of a new log entry, enabling the OpenTelemetry collector to combine continuation lines into a single log record.How It Works
The implementation uses the OpenTelemetry
recombineoperator (not themultilineconfig on the filelog receiver itself, which doesn't work well with container log parsing which has its own timestamp). Therecombineoperator runs after the container parser extracts the log body, allowing it to match against the actual application log content rather than the raw container log format.Key implementation details:
multiline.lineStartPatternandmultiline.lineEndPatterntospec.logCollectionrecombineoperator withis_first_entryoris_last_entryexpressionslineStartPatternorlineEndPatternis specified and validates regex syntaxExample: After (With Multiline Support)
With multiline log collection enabled, the entire stack trace is collected as a single log entry:
The full stack trace is now visible as a single log record, making debugging much easier.
API Changes
New CRD Schema
The
Dash0MonitoringCRD'sspec.logCollectionnow supports an optionalmultilineconfiguration:Validation Rules
lineStartPatternorlineEndPatterncan be specified (not both)multilineis presentGenerated OpenTelemetry Collector Configuration
When multiline is configured, the operator generates the following configuration in the filelog receiver:
Note: The regex pattern is automatically escaped for OTTL expressions (backslashes are doubled).
My Specific Use Case
Application Log Format
I have a Java Spring Boot application that logs in the following format:
My Regex Pattern
To properly collect these logs with stack traces as single entries, I use:
This pattern matches the timestamp and log level at the start of each new log entry. Lines that don't match (like
java.lang.RuntimeException:...orat org.example...) are combined with the previous log entry.Dash0Monitoring Configuration
Files Changed
api/operator/common/common_monitoring_types.go- AddedMultilineConfigstructapi/operator/common/zz_generated.deepcopy.go- Generated deepcopy methodsconfig/crd/bases/operator.dash0.com_dash0monitorings.yaml- Updated CRD schemahelm-chart/dash0-operator/templates/operator/deployment-and-webhooks.yaml- Helm chart CRDinternal/collectors/otelcolresources/collector_config_maps.go- Added template function and typesinternal/collectors/otelcolresources/collector_config_maps_test.go- Fixed testsinternal/collectors/otelcolresources/daemonset.config.yaml.template- Added recombine operatorinternal/collectors/otelcolresources/desired_state.go- Namespace grouping by multiline configinternal/webhooks/monitoring_validation_webhook.go- Added validationQuestions for the Team
I'm happy to iterate on this implementation based on your feedback, or hand it off to someone on the team who is better at Golang than I am. As I said this was entirely vibe coded with Claude Opus 4.5, so having a real programmer take this moving forward would probably be good. Looking forward to hearing your thoughts!