Skip to content

Commit 73c675b

Browse files
authored
[crashtracker] Log errors in crashtracker receiver (#1395)
First commit First pass logger component Lets just reuse telemetry crash uploader move logging into one helper Co-authored-by: gyuheon.oh <[email protected]>
1 parent 5c4a024 commit 73c675b

File tree

4 files changed

+221
-48
lines changed

4 files changed

+221
-48
lines changed

libdd-crashtracker/src/crash_info/errors_intake.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ impl ErrorsIntakeUploader {
521521
self.send_payload(&payload).await
522522
}
523523

524-
pub async fn upload_to_errors_intake(&self, crash_info: &CrashInfo) -> anyhow::Result<()> {
524+
pub async fn upload_crash_info(&self, crash_info: &CrashInfo) -> anyhow::Result<()> {
525525
let payload = ErrorsIntakePayload::from_crash_info(crash_info)?;
526526
self.send_payload(&payload).await
527527
}

libdd-crashtracker/src/crash_info/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,14 @@ impl CrashInfo {
154154

155155
async fn upload_to_telemetry(&self, endpoint: &Option<Endpoint>) -> anyhow::Result<()> {
156156
let uploader = TelemetryCrashUploader::new(&self.metadata, endpoint)?;
157-
uploader.upload_to_telemetry(self).await?;
157+
uploader.upload_crash_info(self).await?;
158158
Ok(())
159159
}
160160

161161
async fn upload_to_errors_intake(&self, endpoint: &Option<Endpoint>) -> anyhow::Result<()> {
162162
let uploader = ErrorsIntakeUploader::new(endpoint)?;
163163
if uploader.is_enabled() {
164-
uploader.upload_to_errors_intake(self).await?;
164+
uploader.upload_crash_info(self).await?;
165165
}
166166
Ok(())
167167
}

libdd-crashtracker/src/crash_info/telemetry.rs

Lines changed: 105 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,23 @@ impl TelemetryCrashUploader {
236236
Ok(s)
237237
}
238238

239+
/// Send a general (non crash report, non crash ping) log message to the telemetry log intake.
240+
pub async fn upload_general_log(
241+
&self,
242+
message: String,
243+
tags: String,
244+
level: LogLevel,
245+
) -> anyhow::Result<()> {
246+
let tracer_time = SystemTime::now()
247+
.duration_since(SystemTime::UNIX_EPOCH)
248+
.map(|d| d.as_secs())
249+
.unwrap_or(0);
250+
251+
self.send_log_payload(message, tags, tracer_time, level, false, false)
252+
.await
253+
}
254+
255+
/// Send a crash ping telemetry log to indicate that crash processing has started
239256
pub async fn upload_crash_ping(&self, crash_ping: &CrashPing) -> anyhow::Result<()> {
240257
let tags = self.build_crash_ping_tags(crash_ping.crash_uuid(), crash_ping.siginfo());
241258
let tracer_time = SystemTime::now()
@@ -255,44 +272,8 @@ impl TelemetryCrashUploader {
255272
.await
256273
}
257274

258-
fn build_crash_ping_tags(&self, crash_uuid: &str, sig_info: Option<&SigInfo>) -> String {
259-
let metadata = &self.metadata;
260-
let mut tags = format!(
261-
"uuid:{},is_crash_ping:true,service:{},language_name:{},language_version:{},tracer_version:{}",
262-
crash_uuid,
263-
metadata.application.service_name,
264-
metadata.application.language_name,
265-
metadata.application.language_version,
266-
metadata.application.tracer_version
267-
);
268-
269-
if let Some(sig_info) = sig_info {
270-
tags.push_str(&format!(
271-
",si_code_human_readable:{:?},si_signo:{},si_signo_human_readable:{:?}",
272-
sig_info.si_code_human_readable,
273-
sig_info.si_signo,
274-
sig_info.si_signo_human_readable
275-
));
276-
}
277-
278-
self.append_optional_tags(&mut tags);
279-
tags
280-
}
281-
282-
fn append_optional_tags(&self, tags: &mut String) {
283-
let metadata = &self.metadata;
284-
if let Some(env) = &metadata.application.env {
285-
tags.push_str(&format!(",env:{env}"));
286-
}
287-
if let Some(runtime_name) = &metadata.application.runtime_name {
288-
tags.push_str(&format!(",runtime_name:{runtime_name}"));
289-
}
290-
if let Some(runtime_version) = &metadata.application.runtime_version {
291-
tags.push_str(&format!(",runtime_version:{runtime_version}"));
292-
}
293-
}
294-
295-
pub async fn upload_to_telemetry(&self, crash_info: &CrashInfo) -> anyhow::Result<()> {
275+
/// Send a crash info telemetry log to indicate that crash processing has completed
276+
pub async fn upload_crash_info(&self, crash_info: &CrashInfo) -> anyhow::Result<()> {
296277
let message = serde_json::to_string(crash_info)?;
297278
let tags = extract_crash_info_tags(crash_info).unwrap_or_default();
298279
let tracer_time = crash_info.timestamp.parse::<DateTime<Utc>>().map_or_else(
@@ -316,6 +297,8 @@ impl TelemetryCrashUploader {
316297
.await
317298
}
318299

300+
/// Shared helper that builds `data::Telemetry` payload and calls `send_telemetry_payload`
301+
/// to send the payload to the telemetry log intake.
319302
async fn send_log_payload(
320303
&self,
321304
message: String,
@@ -347,6 +330,7 @@ impl TelemetryCrashUploader {
347330
self.send_telemetry_payload(&payload).await
348331
}
349332

333+
/// Helper to perform actual HTTP (or file) submission via configured telemetry client
350334
async fn send_telemetry_payload(&self, payload: &data::Telemetry<'_>) -> anyhow::Result<()> {
351335
let client = libdd_telemetry::worker::http_client::from_config(&self.cfg);
352336
let req = request_builder(&self.cfg)?
@@ -379,6 +363,43 @@ impl TelemetryCrashUploader {
379363

380364
Ok(())
381365
}
366+
367+
fn build_crash_ping_tags(&self, crash_uuid: &str, sig_info: Option<&SigInfo>) -> String {
368+
let metadata = &self.metadata;
369+
let mut tags = format!(
370+
"uuid:{},is_crash_ping:true,service:{},language_name:{},language_version:{},tracer_version:{}",
371+
crash_uuid,
372+
metadata.application.service_name,
373+
metadata.application.language_name,
374+
metadata.application.language_version,
375+
metadata.application.tracer_version
376+
);
377+
378+
if let Some(sig_info) = sig_info {
379+
tags.push_str(&format!(
380+
",si_code_human_readable:{:?},si_signo:{},si_signo_human_readable:{:?}",
381+
sig_info.si_code_human_readable,
382+
sig_info.si_signo,
383+
sig_info.si_signo_human_readable
384+
));
385+
}
386+
387+
self.append_optional_tags(&mut tags);
388+
tags
389+
}
390+
391+
fn append_optional_tags(&self, tags: &mut String) {
392+
let metadata = &self.metadata;
393+
if let Some(env) = &metadata.application.env {
394+
tags.push_str(&format!(",env:{env}"));
395+
}
396+
if let Some(runtime_name) = &metadata.application.runtime_name {
397+
tags.push_str(&format!(",runtime_name:{runtime_name}"));
398+
}
399+
if let Some(runtime_version) = &metadata.application.runtime_version {
400+
tags.push_str(&format!(",runtime_version:{runtime_version}"));
401+
}
402+
}
382403
}
383404

384405
fn extract_crash_info_tags(crash_info: &CrashInfo) -> anyhow::Result<String> {
@@ -423,6 +444,7 @@ mod tests {
423444
use super::TelemetryCrashUploader;
424445
use crate::crash_info::{test_utils::TestInstance, CrashInfo, CrashInfoBuilder, Metadata};
425446
use libdd_common::Endpoint;
447+
use libdd_telemetry::data::LogLevel;
426448
use std::{collections::HashSet, fs};
427449
use uuid::Uuid;
428450

@@ -469,7 +491,7 @@ mod tests {
469491
.unwrap();
470492
let test_instance = super::CrashInfo::test_instance(seed);
471493

472-
t.upload_to_telemetry(&test_instance).await.unwrap();
494+
t.upload_crash_info(&test_instance).await.unwrap();
473495

474496
let payload: serde_json::value::Value =
475497
serde_json::de::from_str(&fs::read_to_string(&output_filename).unwrap()).unwrap();
@@ -877,4 +899,48 @@ mod tests {
877899
.contains("crash processing started"));
878900
Ok(())
879901
}
902+
903+
#[tokio::test]
904+
#[cfg_attr(miri, ignore)]
905+
async fn test_general_log_upload() -> anyhow::Result<()> {
906+
let tmp = tempfile::tempdir().unwrap();
907+
let output_filename = {
908+
let mut p = tmp.keep();
909+
p.push("general_log_upload");
910+
p
911+
};
912+
913+
let mut uploader = new_test_uploader(7);
914+
uploader
915+
.cfg
916+
.set_host_from_url(&format!("file://{}", output_filename.to_str().unwrap()))?;
917+
918+
uploader
919+
.upload_general_log(
920+
"hello general log".to_string(),
921+
"service:foo,env:bar,crash_uuid:1234567890".to_string(),
922+
LogLevel::Warn,
923+
)
924+
.await?;
925+
926+
let payload: serde_json::value::Value =
927+
serde_json::de::from_str(&fs::read_to_string(&output_filename).unwrap())?;
928+
println!("payload: {:?}", payload.to_string());
929+
930+
assert_eq!(payload["api_version"], "v2");
931+
assert_eq!(payload["request_type"], "logs");
932+
assert_eq!(payload["origin"], "Crashtracker");
933+
934+
let log_entry = &payload["payload"][0];
935+
assert_eq!(log_entry["level"], "WARN");
936+
assert_eq!(log_entry["is_sensitive"], false);
937+
assert_eq!(log_entry["is_crash"], false);
938+
assert_eq!(log_entry["message"], "hello general log");
939+
let tags = log_entry["tags"].as_str().unwrap();
940+
assert!(tags.contains("service:foo"));
941+
assert!(tags.contains("env:bar"));
942+
assert!(tags.contains("crash_uuid:1234567890"));
943+
944+
Ok(())
945+
}
880946
}

0 commit comments

Comments
 (0)