Skip to content

Commit

Permalink
feat(spans): Reintroduce OTLP endpoint (#4223)
Browse files Browse the repository at this point in the history
Restore the OTLP endpoint that was removed in
#3973.

This PR moves the parsing of the trace data to the processor to ensure
fast response times.

I also renamed the endpoint from `/spans/` to `/otlp/v1/traces/` to be
consistent with
https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/#otel_exporter_otlp_endpoint.
  • Loading branch information
jjbayer authored Nov 19, 2024
1 parent 46f9894 commit 1c16ca3
Show file tree
Hide file tree
Showing 20 changed files with 839 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
- Feature flags of graduated features are now hard-coded in Relay so they can be removed from Sentry. ([#4076](https://github.com/getsentry/relay/pull/4076), [#4080](https://github.com/getsentry/relay/pull/4080))
- Add parallelization in Redis commands. ([#4118](https://github.com/getsentry/relay/pull/4118))
- Extract user ip for spans. ([#4144](https://github.com/getsentry/relay/pull/4144))
- Add support for an experimental OTLP `/v1/traces/` endpoint. The endpoint is disabled by default. ([#4223](https://github.com/getsentry/relay/pull/4223))

## 24.9.0

Expand Down
101 changes: 83 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ pin-project-lite = "0.2.12"
pretty-hex = "0.4.1"
priority-queue = "2.0.3"
proc-macro2 = "1.0.8"
prost = "0.13.3"
psl = "2.1.33"
quote = "1.0.2"
r2d2 = "0.8.10"
Expand Down
2 changes: 1 addition & 1 deletion relay-dynamic-config/src/feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub enum Feature {
/// Serialized as `organizations:standalone-span-ingestion`.
#[serde(rename = "organizations:standalone-span-ingestion")]
StandaloneSpanIngestion,
/// Enable standalone span ingestion via the `/spans/` OTel endpoint.
/// Enable standalone span ingestion via the `/traces/` OTel endpoint.
///
/// Serialized as `projects:relay-otel-endpoint`.
#[serde(rename = "projects:relay-otel-endpoint")]
Expand Down
1 change: 1 addition & 0 deletions relay-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ once_cell = { workspace = true }
papaya = { workspace = true }
pin-project-lite = { workspace = true }
priority-queue = { workspace = true }
prost = { workspace = true }
rand = { workspace = true }
rayon = { workspace = true }
regex = { workspace = true }
Expand Down
2 changes: 2 additions & 0 deletions relay-server/src/endpoints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod public_keys;
mod security_report;
mod statics;
mod store;
mod traces;
mod unreal;

use axum::extract::DefaultBodyLimit;
Expand Down Expand Up @@ -74,6 +75,7 @@ pub fn routes(config: &Config) -> Router<ServiceState>{
.route("/api/:project_id/minidump/", minidump::route(config))
.route("/api/:project_id/events/:event_id/attachments/", post(attachments::handle))
.route("/api/:project_id/unreal/:sentry_key/", unreal::route(config))
.route("/api/:project_id/otlp/v1/traces/", traces::route(config))
// NOTE: If you add a new (non-experimental) route here, please also list it in
// https://github.com/getsentry/sentry-docs/blob/master/docs/product/relay/operating-guidelines.mdx
.route_layer(middlewares::cors());
Expand Down
43 changes: 43 additions & 0 deletions relay-server/src/endpoints/traces.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use axum::extract::{DefaultBodyLimit, Request};
use axum::http::StatusCode;
use axum::response::IntoResponse;
use axum::routing::{post, MethodRouter};
use axum::RequestExt;
use bytes::Bytes;
use relay_config::Config;
use relay_dynamic_config::Feature;

use crate::endpoints::common;
use crate::envelope::{ContentType, Envelope, Item, ItemType};
use crate::extractors::{RawContentType, RequestMeta};
use crate::service::ServiceState;

async fn handle(
state: ServiceState,
content_type: RawContentType,
meta: RequestMeta,
request: Request,
) -> axum::response::Result<impl IntoResponse> {
let content_type @ (ContentType::Json | ContentType::Protobuf) =
ContentType::from(content_type.as_ref())
else {
return Ok(StatusCode::UNSUPPORTED_MEDIA_TYPE);
};
let payload: Bytes = request.extract().await?;
let mut envelope = Envelope::from_request(None, meta);
envelope.require_feature(Feature::OtelEndpoint);

envelope.add_item({
let mut item = Item::new(ItemType::OtelTracesData);
item.set_payload(content_type, payload);
item
});

common::handle_envelope(&state, envelope).await?;

Ok(StatusCode::ACCEPTED)
}

pub fn route(config: &Config) -> MethodRouter<ServiceState> {
post(handle).route_layer(DefaultBodyLimit::max(config.max_envelope_size()))
}
Loading

0 comments on commit 1c16ca3

Please sign in to comment.