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:
parent
40995e96a3
commit
ff4ec0aeb4
@ -68,7 +68,20 @@ pub struct Frame {
|
|||||||
// it should never go in clickhouse / be queried over, but we do store it in PG for
|
// it should never go in clickhouse / be queried over, but we do store it in PG for
|
||||||
// use in the frontend
|
// use in the frontend
|
||||||
#[serde(skip)]
|
#[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 {
|
impl Frame {
|
||||||
@ -98,3 +111,12 @@ impl Frame {
|
|||||||
h.update(self.lang.as_bytes());
|
h.update(self.lang.as_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ContextLine {
|
||||||
|
pub fn new(number: u32, line: impl ToString) -> Self {
|
||||||
|
Self {
|
||||||
|
number,
|
||||||
|
line: line.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use crate::error::UnhandledError;
|
use crate::error::UnhandledError;
|
||||||
|
|
||||||
use super::Frame;
|
use super::{Context, Frame};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct ErrorTrackingStackFrame {
|
pub struct ErrorTrackingStackFrame {
|
||||||
@ -16,7 +16,7 @@ pub struct ErrorTrackingStackFrame {
|
|||||||
pub symbol_set_id: Option<Uuid>,
|
pub symbol_set_id: Option<Uuid>,
|
||||||
pub contents: Frame,
|
pub contents: Frame,
|
||||||
pub resolved: bool,
|
pub resolved: bool,
|
||||||
pub context: Option<String>,
|
pub context: Option<Context>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorTrackingStackFrame {
|
impl ErrorTrackingStackFrame {
|
||||||
@ -26,7 +26,7 @@ impl ErrorTrackingStackFrame {
|
|||||||
symbol_set_id: Option<Uuid>,
|
symbol_set_id: Option<Uuid>,
|
||||||
contents: Frame,
|
contents: Frame,
|
||||||
resolved: bool,
|
resolved: bool,
|
||||||
context: Option<String>,
|
context: Option<Context>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
raw_id,
|
raw_id,
|
||||||
@ -61,7 +61,7 @@ impl ErrorTrackingStackFrame {
|
|||||||
serde_json::to_value(&self.contents)?,
|
serde_json::to_value(&self.contents)?,
|
||||||
self.resolved,
|
self.resolved,
|
||||||
Uuid::now_v7(),
|
Uuid::now_v7(),
|
||||||
self.context
|
serde_json::to_string(&self.context)?
|
||||||
).execute(e).await?;
|
).execute(e).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -103,9 +103,16 @@ impl ErrorTrackingStackFrame {
|
|||||||
// We don't serialise frame contexts on the Frame itself, but save it on the frame record,
|
// 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,
|
// 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.
|
// since we dropped it when we serialised the frame during saving.
|
||||||
|
|
||||||
let mut frame: Frame = serde_json::from_value(found.contents)?;
|
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 {
|
Ok(Some(Self {
|
||||||
raw_id: found.raw_id,
|
raw_id: found.raw_id,
|
||||||
@ -114,7 +121,7 @@ impl ErrorTrackingStackFrame {
|
|||||||
symbol_set_id: found.symbol_set_id,
|
symbol_set_id: found.symbol_set_id,
|
||||||
contents: frame,
|
contents: frame,
|
||||||
resolved: found.resolved,
|
resolved: found.resolved,
|
||||||
context: found.context,
|
context,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::cmp::min;
|
|
||||||
|
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, Sha512};
|
use sha2::{Digest, Sha512};
|
||||||
@ -7,7 +5,7 @@ use sourcemap::{SourceMap, Token};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, FrameError, JsResolveErr, UnhandledError},
|
error::{Error, FrameError, JsResolveErr, UnhandledError},
|
||||||
frames::Frame,
|
frames::{Context, ContextLine, Frame},
|
||||||
metric_consts::{FRAME_NOT_RESOLVED, FRAME_RESOLVED},
|
metric_consts::{FRAME_NOT_RESOLVED, FRAME_RESOLVED},
|
||||||
symbol_store::SymbolCatalog,
|
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 sv = token.get_source_view()?;
|
||||||
|
|
||||||
let token_line = token.get_src_line();
|
let token_line_num = 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;
|
|
||||||
|
|
||||||
// Rough guess on capacity here
|
let token_line = sv.get_line(token_line_num)?;
|
||||||
let mut context = String::with_capacity(((end_line - start_line) * 100) as usize);
|
|
||||||
|
|
||||||
for line in start_line..end_line {
|
let mut before = Vec::new();
|
||||||
if let Some(l) = sv.get_line(line) {
|
let mut i = token_line_num;
|
||||||
context.push_str(l);
|
while before.len() < 5 && i > 0 {
|
||||||
context.push('\n');
|
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 {
|
||||||
Some(context)
|
before,
|
||||||
} else {
|
line: ContextLine::new(token_line_num, token_line),
|
||||||
None
|
after,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -108,10 +108,13 @@ async fn process_exception(
|
|||||||
// process those groups in-order (but the individual frames in them can still be
|
// process those groups in-order (but the individual frames in them can still be
|
||||||
// thrown at the wall), with some cross-group concurrency.
|
// thrown at the wall), with some cross-group concurrency.
|
||||||
handles.push(tokio::spawn(async move {
|
handles.push(tokio::spawn(async move {
|
||||||
context
|
context.worker_liveness.report_healthy().await;
|
||||||
|
let res = context
|
||||||
.resolver
|
.resolver
|
||||||
.resolve(&frame, team_id, &context.pool, &context.catalog)
|
.resolve(&frame, team_id, &context.pool, &context.catalog)
|
||||||
.await
|
.await;
|
||||||
|
context.worker_liveness.report_healthy().await;
|
||||||
|
res
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user