diff --git a/crates/symbolicator-service/src/types.rs b/crates/symbolicator-service/src/types.rs index 1ac4c82cc..c9ee2d266 100644 --- a/crates/symbolicator-service/src/types.rs +++ b/crates/symbolicator-service/src/types.rs @@ -172,3 +172,113 @@ impl ObjectFileStatus { } } } + +/// Possible values for the platform of a native event. +/// +/// This corresponds to `NATIVE_PLATFORMS` in Sentry. +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)] +#[serde(rename_all = "lowercase")] +pub enum NativePlatform { + ObjC, + Cocoa, + Swift, + Native, + C, + CSharp, +} + +impl fmt::Display for NativePlatform { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + NativePlatform::ObjC => write!(f, "objc"), + NativePlatform::Cocoa => write!(f, "cocoa"), + NativePlatform::Swift => write!(f, "swift"), + NativePlatform::Native => write!(f, "native"), + NativePlatform::C => write!(f, "c"), + NativePlatform::CSharp => write!(f, "csharp"), + } + } +} + +/// Possible values for the platform of a JavaScript event. +/// +/// This corresponds to the platforms listed in `is_js_event` in Sentry. +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)] +#[serde(rename_all = "lowercase")] +pub enum JsPlatform { + Node, + JavaScript, +} + +impl fmt::Display for JsPlatform { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + JsPlatform::Node => write!(f, "node"), + JsPlatform::JavaScript => write!(f, "javascript"), + } + } +} + +/// Possible values for the platform of a JVM event. +/// +/// This corresponds to the platforms listed in `java.processing._handles_frame` in Sentry. +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)] +#[serde(rename_all = "lowercase")] +pub enum JvmPlatform { + Java, +} + +impl fmt::Display for JvmPlatform { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + JvmPlatform::Java => write!(f, "java"), + } + } +} + +/// Possible values for the platform of an event. +/// +/// In addition to the native, JS, and JVM cases this also has a catch-all variant for +/// otherwise unrecognized platforms. +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)] +#[serde(untagged)] +pub enum Platform { + Native(NativePlatform), + Js(JsPlatform), + Jvm(JvmPlatform), + Other(String), +} + +impl Platform { + /// Returns `true` if this is a native platform. + pub fn is_native(&self) -> bool { + matches!(self, Self::Native(_)) + } + + /// Returns `true` if this is a JS platform. + pub fn is_js(&self) -> bool { + matches!(self, Self::Js(_)) + } + + /// Returns `true` if this is a JVM platform. + pub fn is_jvm(&self) -> bool { + matches!(self, Self::Jvm(_)) + } +} + +impl Default for Platform { + fn default() -> Self { + Self::Other("unknown".to_owned()) + } +} + +impl fmt::Display for Platform { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Platform::Native(p) => p.fmt(f), + Platform::Js(p) => p.fmt(f), + Platform::Jvm(p) => p.fmt(f), + Platform::Other(p) => p.fmt(f), + } + } +} diff --git a/crates/symbolicli/src/main.rs b/crates/symbolicli/src/main.rs index 2e1cc48c9..d2091e210 100644 --- a/crates/symbolicli/src/main.rs +++ b/crates/symbolicli/src/main.rs @@ -1,5 +1,5 @@ use std::io::{Read, Seek}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{fmt, io}; @@ -10,6 +10,7 @@ use remote::EventKey; use settings::Mode; use symbolicator_js::SourceMapService; use symbolicator_native::SymbolicationActor; +use symbolicator_service::config::Config; use symbolicator_service::services::SharedServices; use symbolicator_service::types::Scope; use symbolicator_sources::{ @@ -100,7 +101,7 @@ async fn main() -> Result<()> { }; let res = match payload { - Payload::Event(event) if event.is_js() => { + Payload::Event(event) if event.platform.is_js() => { let Mode::Online { ref org, ref project, @@ -128,62 +129,28 @@ async fn main() -> Result<()> { CompletedResponse::JsSymbolication(js.symbolicate_js(request).await) } - _ => { - let mut dsym_sources = vec![]; - if let Mode::Online { - ref org, - ref project, - ref base_url, - ref auth_token, - .. - } = mode - { - let project_source = SourceConfig::Sentry(Arc::new(SentrySourceConfig { - id: SourceId::new("sentry:project"), - token: auth_token.clone(), - url: base_url - .join(&format!("projects/{org}/{project}/files/dsyms/")) - .unwrap(), - })); - - dsym_sources.push(project_source); - } - - dsym_sources.extend(symbolicator_config.sources.iter().cloned()); - if let Some(path) = symbols { - let local_source = FilesystemSourceConfig { - id: SourceId::new("local:cli"), - path, - files: CommonSourceConfig { - filters: Default::default(), - layout: DirectoryLayout { - ty: DirectoryLayoutType::Unified, - casing: Default::default(), - }, - is_public: false, - }, - }; - dsym_sources.push(SourceConfig::Filesystem(local_source.into())); - } - let dsym_sources = Arc::from(dsym_sources.into_boxed_slice()); - - CompletedResponse::NativeSymbolication(match payload { - Payload::Event(event) => { - let request = create_native_symbolication_request(scope, dsym_sources, event) - .context("Event cannot be symbolicated")?; + Payload::Event(event) if event.platform.is_native() => { + let dsym_sources = prepare_dsym_sources(mode, &symbolicator_config, symbols); + let request = create_native_symbolication_request(scope, dsym_sources, event) + .context("Event cannot be symbolicated")?; - tracing::info!("symbolicating event"); + tracing::info!("symbolicating event"); - native.symbolicate(request).await? - } - Payload::Minidump(minidump_path) => { - tracing::info!("symbolicating minidump"); - native - .process_minidump(scope, minidump_path, dsym_sources, Default::default()) - .await? - } - }) + let res = native.symbolicate(request).await?; + CompletedResponse::NativeSymbolication(res) + } + Payload::Minidump(minidump_path) => { + let dsym_sources = prepare_dsym_sources(mode, &symbolicator_config, symbols); + tracing::info!("symbolicating minidump"); + let res = native + .process_minidump(scope, minidump_path, dsym_sources, Default::default()) + .await?; + CompletedResponse::NativeSymbolication(res) } + Payload::Event(event) => anyhow::bail!( + "Cannot symbolicate event: invalid platform {}", + event.platform + ), }; match output_format { @@ -202,6 +169,50 @@ async fn main() -> Result<()> { Ok(()) } +fn prepare_dsym_sources( + mode: Mode, + symbolicator_config: &Config, + local_symbols: Option, +) -> Arc<[SourceConfig]> { + let mut dsym_sources = vec![]; + if let Mode::Online { + ref org, + ref project, + ref base_url, + ref auth_token, + .. + } = mode + { + let project_source = SourceConfig::Sentry(Arc::new(SentrySourceConfig { + id: SourceId::new("sentry:project"), + token: auth_token.clone(), + url: base_url + .join(&format!("projects/{org}/{project}/files/dsyms/")) + .unwrap(), + })); + + dsym_sources.push(project_source); + } + + dsym_sources.extend(symbolicator_config.sources.iter().cloned()); + if let Some(path) = local_symbols { + let local_source = FilesystemSourceConfig { + id: SourceId::new("local:cli"), + path, + files: CommonSourceConfig { + filters: Default::default(), + layout: DirectoryLayout { + ty: DirectoryLayoutType::Unified, + casing: Default::default(), + }, + is_public: false, + }, + }; + dsym_sources.push(SourceConfig::Filesystem(local_source.into())); + } + Arc::from(dsym_sources.into_boxed_slice()) +} + #[derive(Debug)] enum Payload { Event(event::Event), @@ -414,7 +425,7 @@ mod event { AddrMode, CompleteObjectInfo, FrameTrust, RawFrame, RawStacktrace, Signal, StacktraceOrigin, SymbolicateStacktraces, }; - use symbolicator_service::types::{RawObjectInfo, Scope, ScrapingConfig}; + use symbolicator_service::types::{Platform, RawObjectInfo, Scope, ScrapingConfig}; use symbolicator_service::utils::hex::HexValue; use symbolicator_sources::{SentrySourceConfig, SourceConfig}; @@ -548,21 +559,10 @@ mod event { }) } - #[derive(Debug, Clone, Copy, Deserialize, Default, PartialEq, Eq)] - #[serde(rename_all = "snake_case")] - enum Platform { - #[default] - Native, - Javascript, - Node, - Csharp, - Cocoa, - } - #[derive(Debug, Deserialize)] pub struct Event { #[serde(default)] - platform: Platform, + pub platform: Platform, #[serde(default)] debug_meta: DebugMeta, exception: Option, @@ -572,12 +572,6 @@ mod event { dist: Option, } - impl Event { - pub fn is_js(&self) -> bool { - matches!(self.platform, Platform::Javascript | Platform::Node) - } - } - #[derive(Debug, Deserialize, Default)] struct DebugMeta { images: Vec,