0
0
mirror of https://github.com/PostHog/posthog.git synced 2024-11-24 00:47:50 +01:00

fix(err): structured context, liveness often (#26275)

This commit is contained in:
Oliver Browne 2024-11-19 13:16:47 +02:00 committed by GitHub
parent 40995e96a3
commit ff4ec0aeb4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 67 additions and 28 deletions

View File

@ -68,7 +68,20 @@ pub struct Frame {
// it should never go in clickhouse / be queried over, but we do store it in PG for
// use in the frontend
#[serde(skip)]
pub context: Option<String>,
pub context: Option<Context>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub struct Context {
pub before: Vec<ContextLine>,
pub line: ContextLine,
pub after: Vec<ContextLine>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub struct ContextLine {
number: u32,
line: String,
}
impl Frame {
@ -98,3 +111,12 @@ impl Frame {
h.update(self.lang.as_bytes());
}
}
impl ContextLine {
pub fn new(number: u32, line: impl ToString) -> Self {
Self {
number,
line: line.to_string(),
}
}
}

View File

@ -6,7 +6,7 @@ use uuid::Uuid;
use crate::error::UnhandledError;
use super::Frame;
use super::{Context, Frame};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ErrorTrackingStackFrame {
@ -16,7 +16,7 @@ pub struct ErrorTrackingStackFrame {
pub symbol_set_id: Option<Uuid>,
pub contents: Frame,
pub resolved: bool,
pub context: Option<String>,
pub context: Option<Context>,
}
impl ErrorTrackingStackFrame {
@ -26,7 +26,7 @@ impl ErrorTrackingStackFrame {
symbol_set_id: Option<Uuid>,
contents: Frame,
resolved: bool,
context: Option<String>,
context: Option<Context>,
) -> Self {
Self {
raw_id,
@ -61,7 +61,7 @@ impl ErrorTrackingStackFrame {
serde_json::to_value(&self.contents)?,
self.resolved,
Uuid::now_v7(),
self.context
serde_json::to_string(&self.context)?
).execute(e).await?;
Ok(())
}
@ -103,9 +103,16 @@ impl ErrorTrackingStackFrame {
// We don't serialise frame contexts on the Frame itself, but save it on the frame record,
// and so when we load a frame record we need to patch back up the context onto the frame,
// since we dropped it when we serialised the frame during saving.
let mut frame: Frame = serde_json::from_value(found.contents)?;
frame.context = found.context.clone();
let context = if let Some(context) = found.context.as_ref() {
// We serialise the frame context as a json string, but it's a structure we have to manually
// deserialise back into the frame.
Some(serde_json::from_str(context)?)
} else {
None
};
frame.context = context.clone();
Ok(Some(Self {
raw_id: found.raw_id,
@ -114,7 +121,7 @@ impl ErrorTrackingStackFrame {
symbol_set_id: found.symbol_set_id,
contents: frame,
resolved: found.resolved,
context: found.context,
context,
}))
}
}

View File

@ -1,5 +1,3 @@
use std::cmp::min;
use reqwest::Url;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha512};
@ -7,7 +5,7 @@ use sourcemap::{SourceMap, Token};
use crate::{
error::{Error, FrameError, JsResolveErr, UnhandledError},
frames::Frame,
frames::{Context, ContextLine, Frame},
metric_consts::{FRAME_NOT_RESOLVED, FRAME_RESOLVED},
symbol_store::SymbolCatalog,
};
@ -160,28 +158,37 @@ impl From<(&RawJSFrame, JsResolveErr)> for Frame {
}
}
fn get_context(token: &Token) -> Option<String> {
fn get_context(token: &Token) -> Option<Context> {
let sv = token.get_source_view()?;
let token_line = token.get_src_line();
let start_line = token_line.saturating_sub(5);
let end_line = min(token_line.saturating_add(5) as usize, sv.line_count()) as u32;
let token_line_num = token.get_src_line();
// Rough guess on capacity here
let mut context = String::with_capacity(((end_line - start_line) * 100) as usize);
let token_line = sv.get_line(token_line_num)?;
for line in start_line..end_line {
if let Some(l) = sv.get_line(line) {
context.push_str(l);
context.push('\n');
let mut before = Vec::new();
let mut i = token_line_num;
while before.len() < 5 && i > 0 {
i -= 1;
if let Some(line) = sv.get_line(i) {
before.push(ContextLine::new(i, line));
}
}
before.reverse();
let mut after = Vec::new();
let mut i = token_line_num;
while after.len() < 5 && i < sv.line_count() as u32 {
i += 1;
if let Some(line) = sv.get_line(i) {
after.push(ContextLine::new(i, line));
}
}
if !context.is_empty() {
Some(context)
} else {
None
}
Some(Context {
before,
line: ContextLine::new(token_line_num, token_line),
after,
})
}
#[cfg(test)]

View File

@ -108,10 +108,13 @@ async fn process_exception(
// process those groups in-order (but the individual frames in them can still be
// thrown at the wall), with some cross-group concurrency.
handles.push(tokio::spawn(async move {
context
context.worker_liveness.report_healthy().await;
let res = context
.resolver
.resolve(&frame, team_id, &context.pool, &context.catalog)
.await
.await;
context.worker_liveness.report_healthy().await;
res
}));
}