Skip to content

RHINENG-28312: Implement OpenTelemetry - #2311

Open
MichaelMraka wants to merge 10 commits into
RedHatInsights:masterfrom
MichaelMraka:pr2
Open

RHINENG-28312: Implement OpenTelemetry#2311
MichaelMraka wants to merge 10 commits into
RedHatInsights:masterfrom
MichaelMraka:pr2

Conversation

@MichaelMraka

@MichaelMraka MichaelMraka commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Secure Coding Practices Checklist GitHub Link

Secure Coding Checklist

  • Input Validation
  • Output Encoding
  • Authentication and Password Management
  • Session Management
  • Access Control
  • Cryptographic Practices
  • Error Handling and Logging
  • Data Protection
  • Communication Security
  • System Configuration
  • Database Security
  • File Management
  • Memory Management
  • General Coding Practices

Summary by Sourcery

Enable configurable OpenTelemetry observability across the service and preserve distributed trace context across HTTP, database, Kafka, evaluation, and logging workflows.

New Features:

  • Add configurable OpenTelemetry tracing across HTTP servers and clients, PostgreSQL, and Kafka producers and consumers.
  • Propagate trace context and Red Hat request and organization attributes through Kafka events, evaluations, logs, and outbound processing.

Enhancements:

  • Preserve tracing context through event handlers and database operations, including per-inventory evaluation spans and links to originating events.
  • Add centralized telemetry initialization, sampling, span limits, OTLP exporting, graceful shutdown, and health or metrics endpoint filtering.

Build:

  • Add OpenTelemetry and SQL instrumentation dependencies.

Deployment:

  • Configure OpenTelemetry settings and service names for application components and jobs in the deployment manifest.

Tests:

  • Add coverage for OpenTelemetry initialization, sampling, resource attributes, HTTP filtering, Kafka propagation, span relationships, logging context, and event traceparent preservation.

Chores:

  • Update Kafka message handler interfaces to carry contexts throughout event processing.

…ntBased sampler

Disabled by default. When enabled, uses OTLP/HTTP, BatchSpanProcessor,
service.version from IMAGE_TAG, and rh.service span attributes.
…ume and item links

Inventory consume uses extracted traceparent as parent. Bulk produce/item
spans use span links so many-to-one batches do not steal a single parent.
Message handlers receive the extracted consumer context. Writes inject
W3C traceparent into kafka-go headers so downstream services continue
the bulk job trace.
Listener flush starts a new producer span with links to each buffered
host span and injects that producer context into Kafka headers.
…st traces

The Kafka consumer span is the bulk job parent. Each system evaluation
is a child with a span link to the Listener/HBI SpanContext from the
payload traceparents array.
…correlation

Inbound otelhttp skips probes and metrics. otelsql and otelhttp
transport create child spans when request context is passed through.
Tracing stays off until OTEL_ENABLED is true per environment. IMAGE_TAG
is injected so service.version is populated on the OTel resource.
@MichaelMraka
MichaelMraka requested a review from a team as a code owner August 20, 2026 12:47
@sourcery-ai

sourcery-ai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Reviewer's Guide

Implements OpenTelemetry-based observability across the service: initializes a configurable OTEL tracer provider, instruments HTTP, Kafka, SQL, and logging, propagates trace context through platform events and evaluators, and wires deployment env vars for per-service telemetry control.

File-Level Changes

Change Details Files
Introduce telemetry package and OTEL tracer initialization, including resource, sampler, span processor, and environment-driven configuration.
  • Add telemetry.Init/Shutdown, tracer provider setup with OTLP HTTP exporter, resource attributes, and sampling configuration
  • Implement RHAttributeSpanProcessor to tag spans with rh.service and propagate rh.org_id/rh.request_id from parent spans
  • Provide helpers for duration/env parsing, attribute formatting, and test exporters for unit tests
base/telemetry/init.go
base/telemetry/config.go
base/telemetry/processor.go
base/telemetry/init_test.go
base/telemetry/processor_test.go
Instrument inbound and outbound HTTP with OpenTelemetry and attach RH attributes from request headers.
  • Wrap HTTP servers via utils.InstrumentHTTPHandler and telemetry.InstrumentHandler using otelhttp.NewHandler with health/metrics path filtering
  • Instrument HTTP clients via telemetry.InstrumentHTTPClient for outbound tracing
  • Add gin middleware RHHTTPAttributes to set rh.request_id and rh.org_id on current span from headers
base/utils/gin.go
base/telemetry/http.go
base/telemetry/http_test.go
manager/manager.go
base/api/client.go
Instrument Kafka consumption and production, including context propagation via headers and span links.
  • Replace Kafka MessageHandler signature to accept context and propagate it through MakeRetryingHandler and HandleMessages
  • Implement headerCarrier and telemetry.Extract/Inject/EncodeTraceparent/ContextFromTraceparent/LinksFromTraceparents for trace context in Kafka headers
  • Add ConsumerContext and ProducerContext helpers to create messaging spans, plus ItemContext and End helpers for per-item spans and error recording
  • Use telemetry.ConsumerContext/ProducerContext in kafkaGo reader/writer and event buffers to create spans for processing and sending evaluator messages
base/mqueue/mqueue.go
base/mqueue/mqueue_impl_gokafka.go
base/mqueue/mqueue_test.go
base/mqueue/platform_event.go
base/mqueue/platform_event_test.go
base/telemetry/kafka.go
base/telemetry/kafka_test.go
listener/event_buffers.go
aggregator/events.go
aggregator/events_test.go
evaluator/advisory_update_test.go
evaluator/evaluate.go
evaluator/evaluate_test.go
evaluator/notifications_test.go
listener/events.go
listener/events_test.go
listener/templates.go
listener/template_advisories.go
listener/template_test.go
listener/upload.go
listener/upload_test.go
Propagate trace context through evaluation pipeline, platform events, and payload tracker, including per-system traceparents.
  • Extend PlatformEvent and EvalData with Traceparents/Traceparent fields and group traceparents per account when building events
  • Ensure WriteEvents preserves traceparents alongside request IDs and add tests verifying ordering
  • In listener upload path, encode current traceparent into EvalData, and in evaluator, derive system IDs/traceparents for bulk vs single evaluation, creating item spans and linking to original upload spans
  • Use telemetry.SetRHAttributes to tag spans in evaluator and inventory listener based on org and request ID
base/mqueue/platform_event.go
base/mqueue/platform_event_test.go
listener/event_buffers.go
evaluator/evaluate.go
evaluator/evaluate_test.go
evaluator/template_advisory_e2e_test.go
listener/events.go
Instrument SQL via otelsql when enabled and adjust DB usage to honor request contexts.
  • Wrap PostgreSQL driver with otelsql and DBSystemPostgreSQL semantic attributes when OTEL SQL is enabled, otherwise fall back to normal gorm Open
  • Switch several database operations in evaluator and listener to use DB.WithContext(ctx) for request-scoped spans
  • Add SQLEnabled helper and tests to ensure it is true after telemetry init when OTEL_ENABLED is set
base/database/setup.go
base/telemetry/config.go
base/telemetry/init_test.go
evaluator/evaluate.go
listener/events.go
listener/upload.go
Integrate tracing with logging and manager middleware to include trace/span ids and RH attributes on logs.
  • Allow log.Log* functions to accept optional leading context and, when span is valid, emit trace_id/span_id fields
  • Update manager RequestResponseLogger to pass gin request context into log calls so HTTP logs carry trace metadata
  • Add tests to verify log entries include well-formed trace_id/span_id when called with a context that has an active span
base/utils/log.go
base/utils/log_test.go
manager/middlewares/logger.go
Wire OpenTelemetry configuration into application startup and Kubernetes deployment.
  • Introduce initObservability in base/core/config to configure logging and telemetry.Init, and call from ConfigureApp/ConfigureAdminApp
  • Ensure telemetry.Shutdown is called on signal handling before process exit
  • Add OTEL-related environment variables and defaults to clowdapp.yaml for all services and jobs, including per-service OTEL_SERVICE_NAME
  • Update go.mod/go.sum to add otel, otelhttp, otelsql, and related dependencies
base/core/config.go
base/base.go
deploy/clowdapp.yaml
go.mod
go.sum

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • In deploy/clowdapp.yaml under the account-advisory-backfill job, OTEL_SPAN_LINK_COUNT_LIMIT is defined twice (once inside env[] and once as a stray line); the second definition should be removed to avoid YAML/env confusion.
  • In listener.event_buffers.flushEvalEvents, the evaluator events are sent with a traced ProducerContext while payload-tracker messages still use base.Context; consider using a similarly instrumented context for payload-tracker sends so those flows participate in the same trace.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In deploy/clowdapp.yaml under the account-advisory-backfill job, OTEL_SPAN_LINK_COUNT_LIMIT is defined twice (once inside env[] and once as a stray line); the second definition should be removed to avoid YAML/env confusion.
- In listener.event_buffers.flushEvalEvents, the evaluator events are sent with a traced ProducerContext while payload-tracker messages still use base.Context; consider using a similarly instrumented context for payload-tracker sends so those flows participate in the same trace.

## Individual Comments

### Comment 1
<location path="deploy/clowdapp.yaml" line_range="64" />
<code_context>
+        - {name: OTEL_BSP_EXPORT_TIMEOUT, value: '${OTEL_BSP_EXPORT_TIMEOUT}'}
+        - {name: OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, value: '${OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT}'}
+        - {name: OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT, value: '${OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT}'}
+        - {name: OTEL_SPAN_LINK_COUNT_LIMIT, value: '${OTEL_SPAN_LINK_COUNT_LIMIT}'}
         resources:
           limits: {cpu: '${CPU_LIMIT_ADMIN}', memory: '${MEM_LIMIT_ADMIN}'}
</code_context>
<issue_to_address>
**issue (bug_risk):** Duplicate OTEL_SPAN_LINK_COUNT_LIMIT entry with mismatched indentation is likely to break the YAML structure.

In `account-advisory-backfill`, `OTEL_SPAN_LINK_COUNT_LIMIT` is defined twice: once correctly in the container `env` list and again at the same level as `containers`, which is not valid in the ClowdApp spec. Please remove the mis-indented duplicate and keep only the `env` entry under the container to prevent deploy/parsing issues.
</issue_to_address>

### Comment 2
<location path="base/mqueue/mqueue_test.go" line_range="64-68" />
<code_context>
+	assert.NoError(t, MakeRetryingHandler(handler)(context.Background(), msg))
+}
+
+func TestWriteMessagesInjectsTraceparent(t *testing.T) {
+	// WriteMessages requires a Kafka broker; inject coverage lives in
+	// telemetry.Inject / TestProducerContextLinksOriginalsAndInjectsOwnTraceparent.
+	t.Skip("no broker-free WriteMessages path; covered by telemetry.Inject tests")
 }
</code_context>
<issue_to_address>
**suggestion (testing):** Re-evaluate the skipped test for WriteMessages traceparent injection to avoid confusion

This skipped test serves only as a note that `WriteMessages` traceparent behavior is covered via `telemetry.Inject` tests, but appearing as a skipped test can confuse future readers and tooling by implying missing coverage. If feasible, either:
- Implement a real test that verifies header injection without a broker (e.g., using a `kafkaGoWriterImpl` with a dummy `Writer` and checking the headers), or
- Replace the function with a code comment explaining why coverage lives elsewhere.

This will keep the test suite clearer and avoid carrying a permanently skipped, redundant test.

```suggestion
/*
WriteMessages traceparent injection behavior is covered indirectly via telemetry.Inject
tests (e.g., TestProducerContextLinksOriginalsAndInjectsOwnTraceparent in the telemetry
package). The mqueue layer delegates header injection to telemetry.Inject, so adding a
broker-free test here would only duplicate that coverage.

If WriteMessages gains a broker-independent path or local header-injection logic in the
future, consider adding a focused test in this file that exercises those code paths
directly instead of relying on telemetry.Inject.
*/
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread deploy/clowdapp.yaml
Comment on lines +64 to 68
func TestWriteMessagesInjectsTraceparent(t *testing.T) {
// WriteMessages requires a Kafka broker; inject coverage lives in
// telemetry.Inject / TestProducerContextLinksOriginalsAndInjectsOwnTraceparent.
t.Skip("no broker-free WriteMessages path; covered by telemetry.Inject tests")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Re-evaluate the skipped test for WriteMessages traceparent injection to avoid confusion

This skipped test serves only as a note that WriteMessages traceparent behavior is covered via telemetry.Inject tests, but appearing as a skipped test can confuse future readers and tooling by implying missing coverage. If feasible, either:

  • Implement a real test that verifies header injection without a broker (e.g., using a kafkaGoWriterImpl with a dummy Writer and checking the headers), or
  • Replace the function with a code comment explaining why coverage lives elsewhere.

This will keep the test suite clearer and avoid carrying a permanently skipped, redundant test.

Suggested change
func TestWriteMessagesInjectsTraceparent(t *testing.T) {
// WriteMessages requires a Kafka broker; inject coverage lives in
// telemetry.Inject / TestProducerContextLinksOriginalsAndInjectsOwnTraceparent.
t.Skip("no broker-free WriteMessages path; covered by telemetry.Inject tests")
}
/*
WriteMessages traceparent injection behavior is covered indirectly via telemetry.Inject
tests (e.g., TestProducerContextLinksOriginalsAndInjectsOwnTraceparent in the telemetry
package). The mqueue layer delegates header injection to telemetry.Inject, so adding a
broker-free test here would only duplicate that coverage.
If WriteMessages gains a broker-independent path or local header-injection logic in the
future, consider adding a focused test in this file that exercises those code paths
directly instead of relying on telemetry.Inject.
*/

@codecov-commenter

codecov-commenter commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 68.76640% with 119 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.09%. Comparing base (d10dbcc) to head (71f5843).

Files with missing lines Patch % Lines
base/telemetry/http.go 18.91% 29 Missing and 1 partial ⚠️
base/telemetry/kafka.go 68.53% 22 Missing and 6 partials ⚠️
base/telemetry/init.go 72.63% 21 Missing and 5 partials ⚠️
base/telemetry/config.go 58.33% 7 Missing and 3 partials ⚠️
base/database/setup.go 45.45% 5 Missing and 1 partial ⚠️
listener/events.go 50.00% 4 Missing ⚠️
base/api/client.go 0.00% 3 Missing ⚠️
base/core/config.go 50.00% 2 Missing and 1 partial ⚠️
base/telemetry/processor.go 88.88% 1 Missing and 1 partial ⚠️
listener/event_buffers.go 81.81% 1 Missing and 1 partial ⚠️
... and 4 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2311      +/-   ##
==========================================
+ Coverage   58.82%   59.09%   +0.26%     
==========================================
  Files         150      155       +5     
  Lines        9604     9932     +328     
==========================================
+ Hits         5650     5869     +219     
- Misses       3360     3451      +91     
- Partials      594      612      +18     
Flag Coverage Δ
unittests 59.09% <68.76%> (+0.26%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@TenSt TenSt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@TenSt TenSt self-assigned this Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants