Skip to content

Commit 4553e2e

Browse files
authored
refactor(logs): cache default attributes and add OS attributes (#842)
1 parent 34db51d commit 4553e2e

File tree

2 files changed

+75
-48
lines changed

2 files changed

+75
-48
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
_ => LogFilter::Log,
3232
});
3333
```
34+
- refactor(logs): cache default attributes and add OS attributes (#842) by @lcian
35+
- `os.name` and `os.version` are now being attached to logs as default attributes.
3436

3537
### Fixes
3638

sentry-core/src/client.rs

Lines changed: 73 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::any::TypeId;
22
use std::borrow::Cow;
3+
#[cfg(feature = "logs")]
4+
use std::collections::BTreeMap;
35
use std::fmt;
46
use std::panic::RefUnwindSafe;
57
use std::sync::{Arc, RwLock};
@@ -21,6 +23,8 @@ use crate::types::{Dsn, Uuid};
2123
use crate::SessionMode;
2224
use crate::{ClientOptions, Envelope, Hub, Integration, Scope, Transport};
2325
#[cfg(feature = "logs")]
26+
use sentry_types::protocol::v7::Context;
27+
#[cfg(feature = "logs")]
2428
use sentry_types::protocol::v7::{Log, LogAttribute};
2529

2630
impl<T: Into<ClientOptions>> From<T> for Client {
@@ -55,6 +59,8 @@ pub struct Client {
5559
session_flusher: RwLock<Option<SessionFlusher>>,
5660
#[cfg(feature = "logs")]
5761
logs_batcher: RwLock<Option<LogsBatcher>>,
62+
#[cfg(feature = "logs")]
63+
default_log_attributes: Option<BTreeMap<String, LogAttribute>>,
5864
integrations: Vec<(TypeId, Arc<dyn Integration>)>,
5965
pub(crate) sdk_info: ClientSdkInfo,
6066
}
@@ -92,6 +98,8 @@ impl Clone for Client {
9298
session_flusher,
9399
#[cfg(feature = "logs")]
94100
logs_batcher,
101+
#[cfg(feature = "logs")]
102+
default_log_attributes: self.default_log_attributes.clone(),
95103
integrations: self.integrations.clone(),
96104
sdk_info: self.sdk_info.clone(),
97105
}
@@ -168,16 +176,75 @@ impl Client {
168176
None
169177
});
170178

171-
Client {
179+
#[allow(unused_mut)]
180+
let mut client = Client {
172181
options,
173182
transport,
174183
#[cfg(feature = "release-health")]
175184
session_flusher,
176185
#[cfg(feature = "logs")]
177186
logs_batcher,
187+
#[cfg(feature = "logs")]
188+
default_log_attributes: None,
178189
integrations,
179190
sdk_info,
191+
};
192+
193+
#[cfg(feature = "logs")]
194+
client.cache_default_log_attributes();
195+
196+
client
197+
}
198+
199+
#[cfg(feature = "logs")]
200+
fn cache_default_log_attributes(&mut self) {
201+
let mut attributes = BTreeMap::new();
202+
203+
if let Some(environment) = self.options.environment.as_ref() {
204+
attributes.insert("sentry.environment".to_owned(), environment.clone().into());
205+
}
206+
207+
if let Some(release) = self.options.release.as_ref() {
208+
attributes.insert("sentry.release".to_owned(), release.clone().into());
180209
}
210+
211+
attributes.insert(
212+
"sentry.sdk.name".to_owned(),
213+
self.sdk_info.name.to_owned().into(),
214+
);
215+
216+
attributes.insert(
217+
"sentry.sdk.version".to_owned(),
218+
self.sdk_info.version.to_owned().into(),
219+
);
220+
221+
// Process a fake event through integrations, so that `ContextIntegration` (if available)
222+
// provides the OS Context.
223+
// This is needed as that integration adds the OS Context to events using an event
224+
// processor, which logs don't go through.
225+
// We cannot get the `ContextIntegration` directly, as its type lives in `sentry-contexts`,
226+
// which `sentry-core` doesn't depend on.
227+
let mut fake_event = Event::default();
228+
for (_, integration) in self.integrations.iter() {
229+
if let Some(res) = integration.process_event(fake_event.clone(), &self.options) {
230+
fake_event = res;
231+
}
232+
}
233+
234+
if let Some(Context::Os(os)) = fake_event.contexts.get("os") {
235+
if let Some(name) = os.name.as_ref() {
236+
attributes.insert("os.name".to_owned(), name.to_owned().into());
237+
}
238+
if let Some(version) = os.version.as_ref() {
239+
attributes.insert("os.version".to_owned(), version.to_owned().into());
240+
}
241+
}
242+
243+
if let Some(server) = &self.options.server_name {
244+
attributes.insert("server.address".to_owned(), server.clone().into());
245+
}
246+
247+
self.default_log_attributes = Some(attributes);
181248
}
182249

183250
pub(crate) fn get_integration<I>(&self) -> Option<&I>
@@ -413,60 +480,18 @@ impl Client {
413480
fn prepare_log(&self, mut log: Log, scope: &Scope) -> Option<Log> {
414481
scope.apply_to_log(&mut log);
415482

416-
self.set_log_default_attributes(&mut log);
483+
if let Some(default_attributes) = self.default_log_attributes.as_ref() {
484+
for (key, val) in default_attributes.iter() {
485+
log.attributes.entry(key.to_owned()).or_insert(val.clone());
486+
}
487+
}
417488

418489
if let Some(ref func) = self.options.before_send_log {
419490
log = func(log)?;
420491
}
421492

422493
Some(log)
423494
}
424-
425-
#[cfg(feature = "logs")]
426-
fn set_log_default_attributes(&self, log: &mut Log) {
427-
if !log.attributes.contains_key("sentry.environment") {
428-
if let Some(environment) = self.options.environment.as_ref() {
429-
log.attributes.insert(
430-
"sentry.environment".to_owned(),
431-
LogAttribute(environment.clone().into()),
432-
);
433-
}
434-
}
435-
436-
if !log.attributes.contains_key("sentry.release") {
437-
if let Some(release) = self.options.release.as_ref() {
438-
log.attributes.insert(
439-
"sentry.release".to_owned(),
440-
LogAttribute(release.clone().into()),
441-
);
442-
}
443-
}
444-
445-
if !log.attributes.contains_key("sentry.sdk.name") {
446-
log.attributes.insert(
447-
"sentry.sdk.name".to_owned(),
448-
LogAttribute(self.sdk_info.name.to_owned().into()),
449-
);
450-
}
451-
452-
if !log.attributes.contains_key("sentry.sdk.version") {
453-
log.attributes.insert(
454-
"sentry.sdk.version".to_owned(),
455-
LogAttribute(self.sdk_info.version.to_owned().into()),
456-
);
457-
}
458-
459-
// TODO: set OS (and Rust?) context
460-
461-
if !log.attributes.contains_key("server.address") {
462-
if let Some(server) = &self.options.server_name {
463-
log.attributes.insert(
464-
"server.address".to_owned(),
465-
LogAttribute(server.clone().into()),
466-
);
467-
}
468-
}
469-
}
470495
}
471496

472497
// Make this unwind safe. It's not out of the box because of the

0 commit comments

Comments
 (0)