Skip to content

Commit b770e71

Browse files
authored
feat(ourlog): Add vercel log drain endpoint (#5212)
resolves https://linear.app/getsentry/issue/LOGS-389/add-vercel-log-drain-endpoint-to-relay Building on top of the vercel log transform added in #5209, this PR adds an endpoint for the vercel log drain. This endpoint is featured flagged, you can see the options automator PR here: getsentry/sentry-options-automator#5367
1 parent 7eec940 commit b770e71

File tree

13 files changed

+391
-2
lines changed

13 files changed

+391
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
- Add `otp` and `two[-_]factor` to default scrubbing rules. ([#5250](https://github.com/getsentry/relay/pull/5250))
2222
- Add event merging logic for Playstation crashes. ([#5228](https://github.com/getsentry/relay/pull/5228))
2323
- Implement PII scrubbing for V2 spans. ([#5168](https://github.com/getsentry/relay/pull/5168))
24+
- Add vercel log drain endpoint. ([#5212](https://github.com/getsentry/relay/pull/5212))
2425

2526
**Bug Fixes**:
2627

relay-ourlogs/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ mod vercel_to_sentry;
1212

1313
pub use self::otel_to_sentry::otel_to_sentry_log;
1414
pub use self::size::calculate_size;
15-
pub use self::vercel_to_sentry::vercel_log_to_sentry_log;
15+
pub use self::vercel_to_sentry::{VercelLog, vercel_log_to_sentry_log};
1616

1717
pub use opentelemetry_proto::tonic::logs::v1 as otel_logs;

relay-ourlogs/src/vercel_to_sentry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub struct VercelLog {
2424
pub timestamp: i64,
2525
/// Identifier for the Vercel project.
2626
pub project_id: String,
27-
// Log severity level.
27+
/// Log severity level.
2828
pub level: VercelLogLevel,
2929
/// Log message content (may be truncated if over 256 KB).
3030
pub message: Option<String>,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pub mod otlp;
2+
pub mod vercel;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use axum::extract::DefaultBodyLimit;
2+
use axum::http::StatusCode;
3+
use axum::response::IntoResponse;
4+
use axum::routing::{MethodRouter, post};
5+
use relay_config::Config;
6+
use relay_dynamic_config::Feature;
7+
8+
use crate::endpoints::common;
9+
use crate::envelope::ContentType;
10+
use crate::extractors::{IntegrationBuilder, RawContentType};
11+
use crate::integrations::{LogsIntegration, VercelLogDrainFormat};
12+
use crate::service::ServiceState;
13+
14+
/// All routes configured for the Vercel integration.
15+
///
16+
/// The integration currently supports the following endpoints:
17+
/// - Vercel Log Drain
18+
pub fn routes(config: &Config) -> axum::Router<ServiceState> {
19+
axum::Router::new()
20+
.route("/logs", logs::route(config))
21+
.route("/logs/", logs::route(config))
22+
}
23+
24+
mod logs {
25+
use super::*;
26+
27+
async fn handle(
28+
content_type: RawContentType,
29+
state: ServiceState,
30+
builder: IntegrationBuilder,
31+
) -> axum::response::Result<impl IntoResponse> {
32+
let format = match ContentType::from(content_type.as_ref()) {
33+
ContentType::Json => VercelLogDrainFormat::Json,
34+
ContentType::NdJson => VercelLogDrainFormat::NdJson,
35+
_ => return Ok(StatusCode::UNSUPPORTED_MEDIA_TYPE),
36+
};
37+
38+
let envelope = builder
39+
.with_type(LogsIntegration::VercelDrainLog { format })
40+
.with_required_feature(Feature::VercelLogDrainEndpoint)
41+
.build();
42+
43+
common::handle_envelope(&state, envelope).await?;
44+
45+
Ok(StatusCode::ACCEPTED)
46+
}
47+
48+
pub fn route(config: &Config) -> MethodRouter<ServiceState> {
49+
post(handle).route_layer(DefaultBodyLimit::max(config.max_envelope_size()))
50+
}
51+
}

relay-server/src/endpoints/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ pub fn routes(config: &Config) -> Router<ServiceState>{
8787
// configured by users or protocols may force a specific variant.
8888
let integration_routes = Router::new()
8989
.nest("/api/{project_id}/integration/otlp", integrations::otlp::routes(config))
90+
.nest("/api/{project_id}/integration/vercel", integrations::vercel::routes(config))
9091
.route_layer(middlewares::cors());
9192

9293
// NOTE: If you add a new (non-experimental) route here, please also list it in

relay-server/src/envelope/content_type.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ pub enum ContentType {
1515
Text,
1616
/// `application/json`
1717
Json,
18+
/// `application/x-ndjson`
19+
NdJson,
1820
/// `application/x-msgpack`
1921
MsgPack,
2022
/// `application/octet-stream`
@@ -45,6 +47,7 @@ impl ContentType {
4547
match self {
4648
Self::Text => "text/plain",
4749
Self::Json => "application/json",
50+
Self::NdJson => "application/x-ndjson",
4851
Self::MsgPack => "application/x-msgpack",
4952
Self::OctetStream => "application/octet-stream",
5053
Self::Minidump => "application/x-dmp",
@@ -74,6 +77,8 @@ impl ContentType {
7477
Some(Self::Text)
7578
} else if ct.eq_ignore_ascii_case(Self::Json.as_str()) {
7679
Some(Self::Json)
80+
} else if ct.eq_ignore_ascii_case(Self::NdJson.as_str()) {
81+
Some(Self::NdJson)
7782
} else if ct.eq_ignore_ascii_case(Self::MsgPack.as_str()) {
7883
Some(Self::MsgPack)
7984
} else if ct.eq_ignore_ascii_case(Self::OctetStream.as_str()) {

relay-server/src/envelope/item.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ impl Item {
160160
(DataCategory::LogByte, self.len().max(1)),
161161
(DataCategory::LogItem, item_count),
162162
],
163+
Some(Integration::Logs(LogsIntegration::VercelDrainLog { .. })) => smallvec![
164+
(DataCategory::LogByte, self.len().max(1)),
165+
(DataCategory::LogItem, item_count),
166+
],
163167
Some(Integration::Spans(SpansIntegration::OtelV1 { .. })) => {
164168
smallvec![
165169
(DataCategory::Span, item_count),

relay-server/src/integrations/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ define_integrations!(
4242
"application/vnd.sentry.integration.otel.logs+protobuf" => Integration::Logs(LogsIntegration::OtelV1 { format: OtelFormat::Protobuf }),
4343
"application/vnd.sentry.integration.otel.spans+json" => Integration::Spans(SpansIntegration::OtelV1 { format: OtelFormat::Json }),
4444
"application/vnd.sentry.integration.otel.spans+protobuf" => Integration::Spans(SpansIntegration::OtelV1 { format: OtelFormat::Protobuf }),
45+
"application/vnd.sentry.integration.vercel.logs+json" => Integration::Logs(LogsIntegration::VercelDrainLog { format: VercelLogDrainFormat::Json }),
46+
"application/vnd.sentry.integration.vercel.logs+ndjson" => Integration::Logs(LogsIntegration::VercelDrainLog { format: VercelLogDrainFormat::NdJson }),
4547
);
4648

4749
/// An exhaustive list of all integrations supported by Relay.
@@ -74,6 +76,10 @@ pub enum LogsIntegration {
7476
///
7577
/// Supports OTeL's [`LogsData`](opentelemetry_proto::tonic::logs::v1::LogsData).
7678
OtelV1 { format: OtelFormat },
79+
/// The Vercel Log Drain integration.
80+
///
81+
/// Supports the [`relay_ourlogs::VercelLog`] format.
82+
VercelDrainLog { format: VercelLogDrainFormat },
7783
}
7884

7985
/// All span integrations supported by Relay.
@@ -93,3 +99,11 @@ pub enum OtelFormat {
9399
/// OTeL data in a JSON container.
94100
Json,
95101
}
102+
103+
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
104+
pub enum VercelLogDrainFormat {
105+
// Vercel Log Drain data in a JSON array payload
106+
Json,
107+
// Vercel Log Drain data in a newline delimited JSON payload
108+
NdJson,
109+
}

relay-server/src/processing/logs/integrations/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::integrations::{Integration, LogsIntegration};
66
use crate::managed::RecordKeeper;
77

88
mod otel;
9+
mod vercel;
910

1011
/// Expands a list of [`Integration`] items into `result`.
1112
///
@@ -43,6 +44,7 @@ pub fn expand_into(
4344

4445
let result = match integration {
4546
LogsIntegration::OtelV1 { format } => otel::expand(format, &payload, produce),
47+
LogsIntegration::VercelDrainLog { format } => vercel::expand(format, &payload, produce),
4648
};
4749

4850
match result {

0 commit comments

Comments
 (0)