Skip to content

Conversation

@AbhiPrasad
Copy link
Member

@AbhiPrasad AbhiPrasad commented Sep 10, 2025

resolves #5111

Building on top of #5128, this PR adds an OTLP endpoint for logs. Much of this approach was inspired by #4223.

To use this endpoint, you'll need to provide the following environmental variables (where DSN_PROJECT_ID and DSN_PUBLIC_KEY are grabbed from the DSN) when setting up your OTEL setup. An integration test was added to tests/integration/test_otlp_logs.py to show this working.

OTEL_EXPORTER_OTLP_LOGS_ENDPOINT="https://{HOST}/api/{DSN_PROJECT_ID}/otlp/v1/logs" 
OTEL_EXPORTER_OTLP_HEADERS="x-sentry-auth=sentry sentry_key={DSN_PUBLIC_KEY}"

@AbhiPrasad AbhiPrasad self-assigned this Sep 10, 2025
Copy link
Member

@jjbayer jjbayer left a comment

Choose a reason for hiding this comment

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

Looks good AFAICT. A test case along the lines of

def test_nel_converted_to_logs(mini_sentry, relay):
would be nice.

Base automatically changed from abhi-relay-otel-pkg to master September 11, 2025 11:39
@AbhiPrasad AbhiPrasad force-pushed the abhi-relay-otel-endpoint branch from b044a69 to 9242f66 Compare September 11, 2025 14:12
@AbhiPrasad AbhiPrasad marked this pull request as ready for review September 11, 2025 16:28
@AbhiPrasad AbhiPrasad requested a review from a team as a code owner September 11, 2025 16:28
cursor[bot]

This comment was marked as outdated.

Comment on lines 139 to 142
// NOTE: semantically wrong, but too expensive to parse.
ItemType::OtelLogsData => smallvec![
(DataCategory::LogByte, self.len().max(1)),
(DataCategory::LogItem, item_count)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// NOTE: semantically wrong, but too expensive to parse.
ItemType::OtelLogsData => smallvec![
(DataCategory::LogByte, self.len().max(1)),
(DataCategory::LogItem, item_count)
ItemType::OtelLogsData => smallvec![
(DataCategory::LogByte, self.len().max(1)),
(DataCategory::LogItem, item_count) // NOTE: semantically wrong, but too expensive to parse.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done with 68491f4

mod minidump;
mod monitor;
mod nel;
mod otel_log;
Copy link
Member

Choose a reason for hiding this comment

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

Should we rename this otlp_logs and rename traces to otlp_traces to match the endpoint routes?

Copy link
Member Author

Choose a reason for hiding this comment

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

Agree, done with d30110c

mod event;
mod metrics;
mod nel;
mod otel_log;
Copy link
Member

Choose a reason for hiding this comment

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

I would name the helper module log and rename the function to convert_otel_logs to be consistent with:

span::convert_otel_traces_data(managed_envelope);

Copy link
Member Author

Choose a reason for hiding this comment

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

I went with ourlog, done with cfe9765

Comment on lines 2384 to 2385
// Convert OTLP logs data to individual log items
otel_log::convert_to_logs(&mut managed_envelope);
Copy link
Member

Choose a reason for hiding this comment

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

Question for @Dav1dde for when you're back: Is this something that should move into LogsProcessor::prepare_envelope eventually?

Copy link
Member

@Dav1dde Dav1dde Sep 16, 2025

Choose a reason for hiding this comment

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

Done in #5136.

Maybe we want to refine this in the future, prepare_envelope was meant to be very very very lightweight, no processing at all. So it has to happen in the expansion. But this is good because we will apply everything we can before the expensive expansion (e.g. if we could inbound filters). It also means we don't have to deserialize -> serialize -> deserialize.

Comment on lines 89 to 91
if let Ok(()) = ItemContainer::from(logs).write_to(&mut item) {
envelope.envelope_mut().add_item(item);
}
Copy link
Member

Choose a reason for hiding this comment

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

I see this was copied from nel, but I would do at least .inspect_err() here. See

ItemContainer::from(self.spans)
.write_to(&mut item)
.inspect_err(|err| relay_log::error!("failed to serialize spans: {err}"))?;

Copy link
Member Author

Choose a reason for hiding this comment

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

Good suggestion! I elected to pattern match and track a DiscardReason outcome. 334df53

ItemType::Span => true,
ItemType::OtelSpan => true,
ItemType::OtelTracesData => true,
ItemType::OtelLogsData => true,
Copy link
Member

Choose a reason for hiding this comment

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

I believe this should be false (also OtelTracesData in the line above). The otel types are already custom container types, so I don't believe they will ever be nested within an ItemContainer. cc @Dav1dde

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah I had thought about this too, but I elected to follow the existing pattern with OtelTracesData in case there was some part of the processing pipeline that relied on this (or future work that was planned).

Changed with 8f451d7

Copy link
Member

Choose a reason for hiding this comment

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

Yup correct, this should be false. The otel format is already a container 👍

Copy link
Member

@jjbayer jjbayer left a comment

Choose a reason for hiding this comment

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

Please keep us in the loop when you roll out the feature flag, & check if all the necessary ops changes were made (see traces).

@AbhiPrasad AbhiPrasad added this pull request to the merge queue Sep 15, 2025
Merged via the queue into master with commit 6e360df Sep 15, 2025
28 checks passed
@AbhiPrasad AbhiPrasad deleted the abhi-relay-otel-endpoint branch September 15, 2025 18:48
github-merge-queue bot pushed a commit that referenced this pull request Sep 17, 2025
…rocessor (#5136)

The implementation in #5130 added the expansion right into the processor
service, not the logs processor (e.g. how the old implementation did it
#5082). This not only means we have to serialize and deserialize an
additional time, it also goes against the design where we want to go
towards. This was most likely caused by my 'NEL' hack, which I now also
separated out again. We can implement a proper NEL processor once we
pick up the NEL work again.

The implementation also did not deal with outcomes correctly. This
implementation fixes the issues and also introduces
`RecordKeeper::modify_by` to track changes in outcome quantities
exactly, instead of just `lenient`ly. We can also work towards moving
all occurrences of `lenient` to `modify_by` in follow-up PRs.
github-merge-queue bot pushed a commit that referenced this pull request Sep 24, 2025
This is a sanity check integration test to make sure that we are
recording outcomes properly for otlp logs.

The intial set of integration tests were added in
#5130
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.

Add OTLP logs endpoint

4 participants