Skip to content

Commit cb7fc81

Browse files
authored
feat(logs): send logs in batches (#831)
1 parent 5912203 commit cb7fc81

File tree

12 files changed

+269
-44
lines changed

12 files changed

+269
-44
lines changed

CHANGELOG.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@
22

33
## Unreleased
44

5-
### Breaking changes
5+
### Features
66

7-
- refactor: remove `debug-logs` feature (#820) by @lcian
8-
- The deprecated `debug-logs` feature of the `sentry` crate, used for the SDK's own internal logging, has been removed.
7+
Support for [Sentry structured logs](https://docs.sentry.io/product/explore/logs/) has been added to the SDK.
8+
- To set up logs, enable the `logs` feature of the `sentry` crate and set `enable_logs` to `true` in your client options.
9+
- Then, use the `logger_trace!`, `logger_debug!`, `logger_info!`, `logger_warn!`, `logger_error!` and `logger_fatal!` macros to capture logs.
10+
- To filter or update logs before they are sent, you can use the `before_send_log` client option.
11+
- Please note that breaking changes could occur until the API is finalized.
12+
13+
- feat(logs): add log protocol types (#821) by @lcian
14+
- feat(logs): add ability to capture and send logs (#823) by @lcian & @Swatinem
15+
- feat(logs): add macro-based API (#827) by @lcian & @szokeasaurusrex
16+
- feat(logs): send logs in batches (#831) by @lcian
917

1018
### Behavioral changes
1119

@@ -14,15 +22,10 @@
1422
- This information is used as a fallback when capturing an event with tracing disabled or otherwise no ongoing span, to still allow related events to be linked by a trace.
1523
- A new API `Scope::iter_trace_propagation_headers` has been provided that will use the fallback tracing information if there is no current `Span` on the `Scope`.
1624

17-
### Features
25+
### Breaking changes
1826

19-
- feat(logs): add log protocol types (#821) by @lcian
20-
- feat(logs): add ability to capture and send logs (#823) by @lcian & @Swatinem
21-
- feat(logs): add macro-based API (#827) by @lcian & @szokeasaurusrex
22-
- Support for [Sentry structured logs](https://docs.sentry.io/product/explore/logs/) has been added.
23-
- To enable logs, enable the `UNSTABLE_logs` feature of the `sentry` crate and set `enable_logs` to `true` in your client options.
24-
- Then, use the `logger_trace!`, `logger_debug!`, `logger_info!`, `logger_warn!`, `logger_error!` and `logger_fatal!` macros to capture logs.
25-
- Please note that breaking changes could occur until the API is finalized.
27+
- refactor: remove `debug-logs` feature (#820) by @lcian
28+
- The deprecated `debug-logs` feature of the `sentry` crate, used for the SDK's own internal logging, has been removed.
2629

2730
## 0.38.1
2831

sentry-core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ default = []
2424
client = ["rand"]
2525
test = ["client", "release-health"]
2626
release-health = []
27-
UNSTABLE_logs = []
27+
logs = []
2828

2929
[dependencies]
3030
log = { version = "0.4.8", optional = true, features = ["std"] }

sentry-core/src/client.rs

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@ use std::panic::RefUnwindSafe;
55
use std::sync::{Arc, RwLock};
66
use std::time::Duration;
77

8-
#[cfg(feature = "UNSTABLE_logs")]
9-
use crate::protocol::EnvelopeItem;
108
#[cfg(feature = "release-health")]
119
use crate::protocol::SessionUpdate;
1210
use rand::random;
1311
use sentry_types::random_uuid;
1412

1513
use crate::constants::SDK_INFO;
14+
#[cfg(feature = "logs")]
15+
use crate::logs::LogsBatcher;
1616
use crate::protocol::{ClientSdkInfo, Event};
1717
#[cfg(feature = "release-health")]
1818
use crate::session::SessionFlusher;
1919
use crate::types::{Dsn, Uuid};
2020
#[cfg(feature = "release-health")]
2121
use crate::SessionMode;
2222
use crate::{ClientOptions, Envelope, Hub, Integration, Scope, Transport};
23-
#[cfg(feature = "UNSTABLE_logs")]
23+
#[cfg(feature = "logs")]
2424
use sentry_types::protocol::v7::{Log, LogAttribute};
2525

2626
impl<T: Into<ClientOptions>> From<T> for Client {
@@ -53,6 +53,8 @@ pub struct Client {
5353
transport: TransportArc,
5454
#[cfg(feature = "release-health")]
5555
session_flusher: RwLock<Option<SessionFlusher>>,
56+
#[cfg(feature = "logs")]
57+
logs_batcher: RwLock<Option<LogsBatcher>>,
5658
integrations: Vec<(TypeId, Arc<dyn Integration>)>,
5759
pub(crate) sdk_info: ClientSdkInfo,
5860
}
@@ -76,11 +78,20 @@ impl Clone for Client {
7678
self.options.session_mode,
7779
)));
7880

81+
#[cfg(feature = "logs")]
82+
let logs_batcher = RwLock::new(if self.options.enable_logs {
83+
Some(LogsBatcher::new(transport.clone()))
84+
} else {
85+
None
86+
});
87+
7988
Client {
8089
options: self.options.clone(),
8190
transport,
8291
#[cfg(feature = "release-health")]
8392
session_flusher,
93+
#[cfg(feature = "logs")]
94+
logs_batcher,
8495
integrations: self.integrations.clone(),
8596
sdk_info: self.sdk_info.clone(),
8697
}
@@ -150,11 +161,20 @@ impl Client {
150161
options.session_mode,
151162
)));
152163

164+
#[cfg(feature = "logs")]
165+
let logs_batcher = RwLock::new(if options.enable_logs {
166+
Some(LogsBatcher::new(transport.clone()))
167+
} else {
168+
None
169+
});
170+
153171
Client {
154172
options,
155173
transport,
156174
#[cfg(feature = "release-health")]
157175
session_flusher,
176+
#[cfg(feature = "logs")]
177+
logs_batcher,
158178
integrations,
159179
sdk_info,
160180
}
@@ -329,6 +349,10 @@ impl Client {
329349
if let Some(ref flusher) = *self.session_flusher.read().unwrap() {
330350
flusher.flush();
331351
}
352+
#[cfg(feature = "logs")]
353+
if let Some(ref batcher) = *self.logs_batcher.read().unwrap() {
354+
batcher.flush();
355+
}
332356
if let Some(ref transport) = *self.transport.read().unwrap() {
333357
transport.flush(timeout.unwrap_or(self.options.shutdown_timeout))
334358
} else {
@@ -346,6 +370,8 @@ impl Client {
346370
pub fn close(&self, timeout: Option<Duration>) -> bool {
347371
#[cfg(feature = "release-health")]
348372
drop(self.session_flusher.write().unwrap().take());
373+
#[cfg(feature = "logs")]
374+
drop(self.logs_batcher.write().unwrap().take());
349375
let transport_opt = self.transport.write().unwrap().take();
350376
if let Some(transport) = transport_opt {
351377
sentry_debug!("client close; request transport to shut down");
@@ -369,24 +395,21 @@ impl Client {
369395
}
370396

371397
/// Captures a log and sends it to Sentry.
372-
#[cfg(feature = "UNSTABLE_logs")]
398+
#[cfg(feature = "logs")]
373399
pub fn capture_log(&self, log: Log, scope: &Scope) {
374400
if !self.options().enable_logs {
375401
return;
376402
}
377-
if let Some(ref transport) = *self.transport.read().unwrap() {
378-
if let Some(log) = self.prepare_log(log, scope) {
379-
let mut envelope = Envelope::new();
380-
let logs: EnvelopeItem = vec![log].into();
381-
envelope.add_item(logs);
382-
transport.send_envelope(envelope);
403+
if let Some(log) = self.prepare_log(log, scope) {
404+
if let Some(ref batcher) = *self.logs_batcher.read().unwrap() {
405+
batcher.enqueue(log);
383406
}
384407
}
385408
}
386409

387410
/// Prepares a log to be sent, setting the `trace_id` and other default attributes, and
388411
/// processing it through `before_send_log`.
389-
#[cfg(feature = "UNSTABLE_logs")]
412+
#[cfg(feature = "logs")]
390413
fn prepare_log(&self, mut log: Log, scope: &Scope) -> Option<Log> {
391414
scope.apply_to_log(&mut log, self.options.send_default_pii);
392415

@@ -399,7 +422,7 @@ impl Client {
399422
Some(log)
400423
}
401424

402-
#[cfg(feature = "UNSTABLE_logs")]
425+
#[cfg(feature = "logs")]
403426
fn set_log_default_attributes(&self, log: &mut Log) {
404427
if !log.attributes.contains_key("sentry.environment") {
405428
if let Some(environment) = self.options.environment.as_ref() {

sentry-core/src/clientoptions.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::time::Duration;
55

66
use crate::constants::USER_AGENT;
77
use crate::performance::TracesSampler;
8-
#[cfg(feature = "UNSTABLE_logs")]
8+
#[cfg(feature = "logs")]
99
use crate::protocol::Log;
1010
use crate::protocol::{Breadcrumb, Event};
1111
use crate::types::Dsn;
@@ -147,7 +147,7 @@ pub struct ClientOptions {
147147
/// Callback that is executed for each Breadcrumb being added.
148148
pub before_breadcrumb: Option<BeforeCallback<Breadcrumb>>,
149149
/// Callback that is executed for each Log being added.
150-
#[cfg(feature = "UNSTABLE_logs")]
150+
#[cfg(feature = "logs")]
151151
pub before_send_log: Option<BeforeCallback<Log>>,
152152
// Transport options
153153
/// The transport to use.
@@ -171,7 +171,7 @@ pub struct ClientOptions {
171171
/// server integrations. Needs `send_default_pii` to be enabled to have any effect.
172172
pub max_request_body_size: MaxRequestBodySize,
173173
/// Determines whether captured structured logs should be sent to Sentry (defaults to false).
174-
#[cfg(feature = "UNSTABLE_logs")]
174+
#[cfg(feature = "logs")]
175175
pub enable_logs: bool,
176176
// Other options not documented in Unified API
177177
/// Disable SSL verification.
@@ -232,7 +232,7 @@ impl fmt::Debug for ClientOptions {
232232
#[derive(Debug)]
233233
struct BeforeBreadcrumb;
234234
let before_breadcrumb = self.before_breadcrumb.as_ref().map(|_| BeforeBreadcrumb);
235-
#[cfg(feature = "UNSTABLE_logs")]
235+
#[cfg(feature = "logs")]
236236
let before_send_log = {
237237
#[derive(Debug)]
238238
struct BeforeSendLog;
@@ -279,7 +279,7 @@ impl fmt::Debug for ClientOptions {
279279
.field("auto_session_tracking", &self.auto_session_tracking)
280280
.field("session_mode", &self.session_mode);
281281

282-
#[cfg(feature = "UNSTABLE_logs")]
282+
#[cfg(feature = "logs")]
283283
debug_struct
284284
.field("enable_logs", &self.enable_logs)
285285
.field("before_send_log", &before_send_log);
@@ -325,9 +325,9 @@ impl Default for ClientOptions {
325325
trim_backtraces: true,
326326
user_agent: Cow::Borrowed(USER_AGENT),
327327
max_request_body_size: MaxRequestBodySize::Medium,
328-
#[cfg(feature = "UNSTABLE_logs")]
328+
#[cfg(feature = "logs")]
329329
enable_logs: false,
330-
#[cfg(feature = "UNSTABLE_logs")]
330+
#[cfg(feature = "logs")]
331331
before_send_log: None,
332332
}
333333
}

sentry-core/src/hub.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ impl Hub {
247247
}
248248

249249
/// Captures a structured log.
250-
#[cfg(feature = "UNSTABLE_logs")]
250+
#[cfg(feature = "logs")]
251251
pub fn capture_log(&self, log: Log) {
252252
with_client_impl! {{
253253
let top = self.inner.with(|stack| stack.top().clone());

sentry-core/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,16 @@ pub use crate::intodsn::IntoDsn;
132132
pub use crate::performance::*;
133133
pub use crate::scope::{Scope, ScopeGuard};
134134
pub use crate::transport::{Transport, TransportFactory};
135-
#[cfg(feature = "UNSTABLE_logs")]
135+
#[cfg(feature = "logs")]
136136
mod logger; // structured logging macros exported with `#[macro_export]`
137137

138138
// client feature
139139
#[cfg(feature = "client")]
140140
mod client;
141141
#[cfg(feature = "client")]
142142
mod hub_impl;
143+
#[cfg(all(feature = "client", feature = "logs"))]
144+
mod logs;
143145
#[cfg(feature = "client")]
144146
mod session;
145147

0 commit comments

Comments
 (0)