Skip to content

Commit

Permalink
Improve support for sentry-java (#357)
Browse files Browse the repository at this point in the history
* Improve support for sentry-java

* Add changeset

* Address PR feedback

* Add java txn fixture envelope

* Move message to CommonEventAttrs
  • Loading branch information
markushi authored Feb 20, 2024
1 parent ea666ac commit 2d37041
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/heavy-berries-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@spotlightjs/overlay': minor
---

Add support for message events and transactions without spans
3 changes: 3 additions & 0 deletions packages/overlay/_fixtures/envelope_java.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{"event_id":"dad187904fee477e9aa75429a1eda314","sdk":{"name":"sentry.java.spring-boot.jakarta","version":"7.3.0","packages":[{"name":"maven:io.sentry:sentry","version":"7.3.0"},{"name":"maven:io.sentry:sentry-spring-boot-starter-jakarta","version":"7.3.0"},{"name":"maven:io.sentry:sentry-jdbc","version":"7.3.0"},{"name":"maven:io.sentry:sentry-graphql","version":"7.3.0"},{"name":"maven:io.sentry:sentry-quartz","version":"7.3.0"},{"name":"maven:io.sentry:sentry-logback","version":"7.3.0"}],"integrations":["SpringBoot3","UncaughtExceptionHandler","ShutdownHook","JDBC","Spring6GrahQLWebMVC","GraphQL","Quartz","Logback"]},"trace":{"trace_id":"00bd13c1652f4f8e8e8570ba8cb0127b","public_key":"502f25099c204a2fbf4cb16edc5975d1","environment":"production","sample_rate":"1","sampled":"true"},"sent_at":"2024-02-19T08:57:42.882Z"}
{"content_type":"application/json","type":"transaction","length":3501}
{"transaction":"POST /person/","start_timestamp":1708333062.041582,"timestamp":1708333062.258721,"spans":[{"start_timestamp":1708333062.238941,"timestamp":1708333062.246714,"trace_id":"00bd13c1652f4f8e8e8570ba8cb0127b","span_id":"fc55571d1fee46f1","parent_span_id":"85b838c8f8004fb9","op":"PersonService.create","status":"ok","origin":"auto.function.spring_jakarta.advice","data":{"thread.name":"http-nio-8080-exec-1","thread.id":"47"}},{"start_timestamp":1708333062.244611,"timestamp":1708333062.245301,"trace_id":"00bd13c1652f4f8e8e8570ba8cb0127b","span_id":"5ffb3e08ca624077","parent_span_id":"fc55571d1fee46f1","op":"db.query","description":"insert into person (firstName, lastName) values (?, ?)","status":"ok","origin":"auto.db.jdbc","data":{"db.system":"hsqldb","thread.name":"http-nio-8080-exec-1","thread.id":"47","db.name":"testdb"}}],"type":"transaction","measurements":{"create_count":{"value":1}},"transaction_info":{"source":"route"},"event_id":"dad187904fee477e9aa75429a1eda314","contexts":{"runtime":{"name":"Azul Systems, Inc.","version":"17.0.5"},"trace":{"trace_id":"00bd13c1652f4f8e8e8570ba8cb0127b","span_id":"85b838c8f8004fb9","op":"http.server","status":"ok","origin":"auto.http.spring_jakarta.webmvc"}},"sdk":{"name":"sentry.java.spring-boot.jakarta","version":"7.3.0","packages":[{"name":"maven:io.sentry:sentry","version":"7.3.0"},{"name":"maven:io.sentry:sentry-spring-boot-starter-jakarta","version":"7.3.0"},{"name":"maven:io.sentry:sentry-jdbc","version":"7.3.0"},{"name":"maven:io.sentry:sentry-graphql","version":"7.3.0"},{"name":"maven:io.sentry:sentry-quartz","version":"7.3.0"},{"name":"maven:io.sentry:sentry-logback","version":"7.3.0"}],"integrations":["SpringBoot3","UncaughtExceptionHandler","ShutdownHook","JDBC","Spring6GrahQLWebMVC","GraphQL","Quartz","Logback"]},"request":{"url":"http://localhost:8080/person/","method":"POST","data":"{\"firstName\":\"John\",\"lastName\":\"a\"}","cookies":"","headers":{"authorization":"Basic dXNlcjpwYXNzd29yZA==","content-length":"35","host":"localhost:8080","content-type":"application/json","user-agent":"curl/8.4.0","accept":"*/*"}},"environment":"production","platform":"java","user":{"username":"user","ip_address":"0:0:0:0:0:0:0:1"},"server_name":"192.168.68.51","breadcrumbs":[{"timestamp":"2024-02-19T08:56:16.860Z","message":"Started SentryDemoApplication in 2.602 seconds (process running for 2.787)","data":{},"category":"io.sentry.samples.spring.boot.jakarta.SentryDemoApplication","level":"info"},{"timestamp":"2024-02-19T08:57:42.033Z","message":"Initializing Spring DispatcherServlet 'dispatcherServlet'","data":{},"category":"org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]","level":"info"},{"timestamp":"2024-02-19T08:57:42.033Z","message":"Initializing Servlet 'dispatcherServlet'","data":{},"category":"org.springframework.web.servlet.DispatcherServlet","level":"info"},{"timestamp":"2024-02-19T08:57:42.035Z","message":"Completed initialization in 1 ms","data":{},"category":"org.springframework.web.servlet.DispatcherServlet","level":"info"},{"timestamp":"2024-02-19T08:57:42.039Z","type":"http","data":{"method":"POST","url":"/person/"},"category":"http"},{"timestamp":"2024-02-19T08:57:42.050Z","message":"Cache miss for REQUEST dispatch to '/person/' (previous null). Performing CorsConfiguration lookup. This is logged once only at WARN level, and every time at TRACE.","data":{},"category":"org.springframework.web.servlet.handler.HandlerMappingIntrospector","level":"warning"}]}
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
import { SentryErrorEvent, SentryEvent } from '../../types';
import { SentryEvent } from '../../types';
import { Error, ErrorSummary, ErrorTitle } from './Error';

export function EventTitle({ event }: { event: SentryErrorEvent | SentryEvent }) {
function getEventMessage(event: SentryEvent) {
if (typeof event.message === 'string') {
return event.message;
} else if (event.message !== undefined && typeof event.message.formatted === 'string') {
return event.message.formatted;
} else {
return '';
}
}

export function EventTitle({ event }: { event: SentryEvent }) {
if ('exception' in event) {
return <ErrorTitle event={event} />;
}

return (
<>
<strong className="font-bold">{event.message}</strong>
<strong className="font-bold">{getEventMessage(event)}</strong>
</>
);
}

export function EventSummary({ event }: { event: SentryErrorEvent | SentryEvent }) {
export function EventSummary({ event }: { event: SentryEvent }) {
if ('exception' in event) {
return <ErrorSummary event={event} />;
}
return (
<div className="space-y-4 font-mono">
<h3 className="flex flex-col">
<strong className="text-xl">{event.message}</strong>
<strong className="text-xl">{getEventMessage(event)}</strong>
</h3>
</div>
);
}

export default function Event({ event }: { event: SentryErrorEvent | SentryEvent }) {
export default function Event({ event }: { event: SentryEvent }) {
if ('exception' in event) {
return <Error event={event} />;
}

return (
<h3 className="bg-primary-950 flex flex-col">
<strong className="text-xl">Message:</strong>
<pre>{event.message}</pre>
<pre>{getEventMessage(event)}</pre>
</h3>
);
}
33 changes: 18 additions & 15 deletions packages/overlay/src/integrations/sentry/data/sentryDataCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,23 +124,26 @@ class SentryDataCache {
trace.transactions.sort((a, b) => a.start_timestamp - b.start_timestamp);

// recompute tree as we might have txn out of order
// XXX: we're trusting timestamps, wihch are not trustworthy
// XXX: we're trusting timestamps, which are not trustworthy
const allSpans: Span[] = [];
trace.transactions.forEach(txn => {
allSpans.push(
{
...txn.contexts.trace,
start_timestamp: txn.start_timestamp,
timestamp: txn.timestamp,
description: traceCtx.description || txn.transaction,
transaction: txn,
},
...txn.spans.map(s => ({
...s,
timestamp: toTimestamp(s.timestamp),
start_timestamp: toTimestamp(s.start_timestamp),
})),
);
allSpans.push({
...txn.contexts.trace,
start_timestamp: txn.start_timestamp,
timestamp: txn.timestamp,
description: traceCtx.description || txn.transaction,
transaction: txn,
});

if (txn.spans) {
allSpans.push(
...txn.spans.map(s => ({
...s,
timestamp: toTimestamp(s.timestamp),
start_timestamp: toTimestamp(s.start_timestamp),
})),
);
}
});
trace.spans = allSpans;
trace.spanTree = groupSpans(trace.spans);
Expand Down
13 changes: 10 additions & 3 deletions packages/overlay/src/integrations/sentry/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type CommonEventAttrs = {
// not always present, but we are forcing it in EventCache
event_id: string;
timestamp: number;
message?: string;
message?: SentryFormattedMessage;
breadcrumbs?: Breadcrumb[] | { values: Breadcrumb[] };
transaction?: string;
environment?: string;
Expand Down Expand Up @@ -87,8 +87,15 @@ export type Tags = {
[key: string]: string;
};

export type SentryFormattedMessage =
| string
| {
formatted: string;
params?: [];
};

export type SentryErrorEvent = CommonEventAttrs & {
type?: 'error' | 'event' | 'default';
type?: 'error' | 'event' | 'message' | 'default';
exception: EventException;
};

Expand All @@ -109,7 +116,7 @@ export type Span = {

export type SentryTransactionEvent = CommonEventAttrs & {
type: 'transaction';
spans: Span[];
spans?: Span[];
start_timestamp: string;
contexts: Contexts & {
trace: TraceContext;
Expand Down
7 changes: 7 additions & 0 deletions packages/overlay/test/integrations/sentry/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ describe('Sentry Integration', () => {
expect((processedEnvelope.event[1][0][1] as any).type).toEqual('transaction');
});

test('Process Java Transaction Envelope', () => {
const envelope = fs.readFileSync('./_fixtures/envelope_java.txt', 'utf-8');
const processedEnvelope = processEnvelope({ data: envelope, contentType: 'test' });
expect(processedEnvelope).not.toBe(undefined);
expect((processedEnvelope.event[1][0][1] as any).type).toEqual('transaction');
});

test('Process Astro SSR pageload (BE -> FE) trace', () => {
const nodeEnvelope = fs.readFileSync('./_fixtures/envelope_astro_ssr_node.txt', 'utf-8');
const processedNodeEnvelope = processEnvelope({ data: nodeEnvelope, contentType: 'test' });
Expand Down

0 comments on commit 2d37041

Please sign in to comment.