Skip to content

Commit

Permalink
ref: Move Contexts out of core (#210)
Browse files Browse the repository at this point in the history
This moves the os, rust and device contexts and associated features into a separate crate which is configurable.
  • Loading branch information
Swatinem committed May 14, 2020
1 parent dbd3987 commit 788e6ab
Show file tree
Hide file tree
Showing 16 changed files with 336 additions and 361 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ members = [
"sentry",
"sentry-actix",
"sentry-backtrace",
"sentry-contexts",
"sentry-core",
"sentry-error-chain",
"sentry-failure",
Expand Down
2 changes: 0 additions & 2 deletions sentry-actix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ with_sentry_default = [
"sentry/with_client_implementation",
"sentry/with_default_transport",
"sentry/with_panic",
"sentry/with_device_info",
"sentry/with_rust_info",
"sentry/with_native_tls"
]

Expand Down
30 changes: 30 additions & 0 deletions sentry-contexts/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "sentry-contexts"
version = "0.18.0"
authors = ["Sentry <hello@sentry.io>"]
license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/getsentry/sentry-rust"
homepage = "https://github.com/getsentry/sentry-rust"
documentation = "https://getsentry.github.io/sentry-rust"
description = """
Sentry integration for rust and device contexts
"""
build = "build.rs"
edition = "2018"

[dependencies]
sentry-core = { version = "0.18.0", path = "../sentry-core" }
libc = "0.2.66"
hostname = "0.3.0"
regex = "1.3.4"
lazy_static = "1.4.0"

[target."cfg(not(windows))".dependencies]
uname = "0.1.1"

[build-dependencies]
rustc_version = "0.2.3"

[dev-dependencies]
sentry = { version = "0.18.0", path = "../sentry" }
67 changes: 67 additions & 0 deletions sentry-contexts/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

use rustc_version::{version, version_meta, Channel};

fn main() -> Result<(), Box<dyn std::error::Error>> {
let out_dir = env::var("OUT_DIR")?;
let dest_path = Path::new(&out_dir).join("constants.gen.rs");
let mut f = File::create(&dest_path)?;

let target = env::var("TARGET")?;
let mut target_bits = target.split('-');
// `NoneError` does not implement `std::error::Error`
// See https://github.com/rust-lang/rust/issues/46871
let arch = target_bits.next().unwrap();
target_bits.next();
let platform = target_bits.next().unwrap();

writeln!(
f,
"/// The rustc version that was used to compile this crate."
)?;
writeln!(
f,
"pub const RUSTC_VERSION: Option<&'static str> = {};",
if let Ok(version) = version() {
format!("Some(\"{}\")", version)
} else {
"None".into()
}
)?;
writeln!(
f,
"/// The rustc release channel that was used to compile this crate."
)?;
writeln!(
f,
"pub const RUSTC_CHANNEL: Option<&'static str> = {};",
if let Ok(version_meta) = version_meta() {
let chan = match version_meta.channel {
Channel::Dev => "dev",
Channel::Nightly => "nightly",
Channel::Beta => "beta",
Channel::Stable => "stable",
};
format!("Some(\"{}\")", chan)
} else {
"None".into()
}
)?;

writeln!(f, "/// The platform identifier.")?;
writeln!(
f,
"#[allow(unused)] pub const PLATFORM: &str = \"{}\";",
platform
)?;
writeln!(f, "/// The CPU architecture identifier.")?;
writeln!(f, "pub const ARCH: &str = \"{}\";", arch)?;

println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=Cargo.toml");

Ok(())
}
76 changes: 76 additions & 0 deletions sentry-contexts/src/integration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use std::borrow::Cow;

use sentry_core::protocol::map::Entry;
use sentry_core::protocol::Event;
use sentry_core::{ClientOptions, Integration};

use crate::utils::{device_context, os_context, rust_context, server_name};

/// Adds Contexts to Sentry Events.
///
/// See https://develop.sentry.dev/sdk/event-payloads/contexts/
pub struct ContextIntegration {
/// Add `os` context, enabled by default.
pub add_os: bool,
/// Add `rust` context, enabled by default.
pub add_rust: bool,
/// Add `device` context, enabled by default.
pub add_device: bool,
}

impl Default for ContextIntegration {
fn default() -> Self {
Self {
add_os: true,
add_rust: true,
add_device: true,
}
}
}

impl ContextIntegration {
/// Create a new Context Integration.
pub fn new() -> Self {
Self::default()
}
}

impl Integration for ContextIntegration {
fn name(&self) -> &'static str {
"contexts"
}

fn setup(&self, options: &mut ClientOptions) {
if options.server_name.is_none() {
options.server_name = server_name().map(Cow::Owned);
}
}

fn process_event(
&self,
mut event: Event<'static>,
_cfg: &ClientOptions,
) -> Option<Event<'static>> {
if self.add_os {
if let Entry::Vacant(entry) = event.contexts.entry("os".to_string()) {
if let Some(os) = os_context() {
entry.insert(os);
}
}
}
if self.add_rust {
event
.contexts
.entry("rust".to_string())
.or_insert_with(rust_context);
}
if self.add_device {
event
.contexts
.entry("device".to_string())
.or_insert_with(device_context);
}

Some(event)
}
}
25 changes: 25 additions & 0 deletions sentry-contexts/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! Adds Contexts to Sentry Events
//!
//! This integration is enabled by default in `sentry` and adds `device`, `os`
//! and `rust` contexts to Events, as well as sets a `server_name` if not
//! already defined.
//!
//! See https://develop.sentry.dev/sdk/event-payloads/contexts/
//!
//! # Examples
//!
//! ```
//! let integration = sentry_contexts::ContextIntegration {
//! add_os: false,
//! ..Default::default()
//! };
//! let _sentry = sentry::init(sentry::ClientOptions::default()
//! .add_integration(integration));
//! ```

#![deny(missing_docs)]

mod integration;
mod utils;

pub use integration::ContextIntegration;
125 changes: 125 additions & 0 deletions sentry-contexts/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use sentry_core::protocol::{Context, DeviceContext, Map, OsContext, RuntimeContext};

include!(concat!(env!("OUT_DIR"), "/constants.gen.rs"));

#[cfg(target_os = "macos")]
mod model_support {
use libc::c_void;
use regex::Regex;
use std::ptr;

lazy_static::lazy_static! {
static ref FAMILY_RE: Regex = Regex::new(r#"([a-zA-Z]+)\d"#).unwrap();
}

pub fn get_model() -> Option<String> {
unsafe {
let mut size = 0;
libc::sysctlbyname(
"hw.model\x00".as_ptr() as *const i8,
ptr::null_mut(),
&mut size,
ptr::null_mut(),
0,
);
let mut buf = vec![0u8; size as usize];
libc::sysctlbyname(
"hw.model\x00".as_ptr() as *const i8,
buf.as_mut_ptr() as *mut c_void,
&mut size,
ptr::null_mut(),
0,
);
Some(
String::from_utf8_lossy(if buf.ends_with(b"\x00") {
&buf[..size - 1]
} else {
&buf
})
.to_string(),
)
}
}

pub fn get_family() -> Option<String> {
get_model()
.as_ref()
.and_then(|model| FAMILY_RE.captures(model))
.and_then(|m| m.get(1))
.map(|group| group.as_str().to_string())
}
}

#[cfg(not(target_os = "macos"))]
mod model_support {
pub fn get_model() -> Option<String> {
None
}

pub fn get_family() -> Option<String> {
None
}
}

/// Returns the server name (hostname) if available.
pub fn server_name() -> Option<String> {
hostname::get().ok().and_then(|s| s.into_string().ok())
}

/// Returns the OS context
pub fn os_context() -> Option<Context> {
#[cfg(not(windows))]
{
use uname::uname;
if let Ok(info) = uname() {
Some(
OsContext {
name: Some(info.sysname),
kernel_version: Some(info.version),
version: Some(info.release),
..Default::default()
}
.into(),
)
} else {
None
}
}
#[cfg(windows)]
{
Some(
OsContext {
name: Some(PLATFORM.into()),
..Default::default()
}
.into(),
)
}
}

/// Returns the rust info.
pub fn rust_context() -> Context {
RuntimeContext {
name: Some("rustc".into()),
version: RUSTC_VERSION.map(|x| x.into()),
other: {
let mut map = Map::default();
if let Some(channel) = RUSTC_CHANNEL {
map.insert("channel".to_string(), channel.into());
}
map
},
}
.into()
}

/// Returns the device context.
pub fn device_context() -> Context {
DeviceContext {
model: model_support::get_model(),
family: model_support::get_family(),
arch: Some(ARCH.into()),
..Default::default()
}
.into()
}
13 changes: 1 addition & 12 deletions sentry-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,15 @@ documentation = "https://getsentry.github.io/sentry-rust"
description = """
Core sentry library used for instrumentation and integration development.
"""
build = "build.rs"
edition = "2018"

[package.metadata.docs.rs]
all-features = true

[features]
default = ["with_client_implementation", "with_device_info", "with_rust_info"]
default = ["with_client_implementation"]
with_client_implementation = ["im", "url", "rand"]
with_debug_to_log = ["log"]
with_device_info = ["libc", "hostname", "uname", "regex", "with_client_implementation"]
with_rust_info = ["rustc_version", "with_client_implementation"]
with_debug_meta = ["findshlibs", "with_client_implementation"]
with_test_support = []

Expand All @@ -32,18 +29,10 @@ sentry-types = { path = "../sentry-types", version = "0.15.0" }
env_logger = { version = "0.7.1", optional = true }
lazy_static = "1.4.0"
im = { version = "14.2.0", optional = true }
libc = { version = "0.2.66", optional = true }
hostname = { version = "0.3.0", optional = true }
findshlibs = { version = "0.7.0", optional = true }
rand = { version = "0.7.3", optional = true }
regex = { version = "1.3.4", optional = true }

[target."cfg(not(windows))".dependencies]
uname = { version = "0.1.1", optional = true }

[build-dependencies]
rustc_version = { version = "0.2.3", optional = true }

[dev-dependencies]
pretty_env_logger = "0.4.0"
sentry-failure = { version = "0.18.0", path = "../sentry-failure" }

0 comments on commit 788e6ab

Please sign in to comment.