11package net .hollowcube .posthog ;
22
3- import com .google .gson .*;
3+ import com .google .gson .Gson ;
4+ import com .google .gson .JsonArray ;
5+ import com .google .gson .JsonElement ;
6+ import com .google .gson .JsonObject ;
47import org .jetbrains .annotations .Blocking ;
58import org .jetbrains .annotations .NotNull ;
69import org .jetbrains .annotations .Nullable ;
@@ -332,8 +335,8 @@ private void loadRemoteFeatureFlags() {
332335 * Deduplicates recently sent distinctId/featureFlagKey combinations, kind of.
333336 *
334337 * <p>This concept comes from posthog-go in its <a href="https://github.com/PostHog/posthog-go/blob/ec95a60c64b0dd335dafa5c72e8a56c4edc0dbbd/posthog.go#L348">
335- * handling of sending feature flag called events.</href></a> I'm not very sure what the point is
336- * especially since the map clear allows two consecutive keys to return true.</p>
338+ * handling of sending feature flag called events.</href></a> I'm not very sure what the point is
339+ * especially since the map clear allows two consecutive keys to return true.</p>
337340 *
338341 * <p>My best guess is that its simply to roughly reduce event volume when evaluating a ton of feature flags.</p>
339342 *
@@ -392,20 +395,25 @@ public void captureException(@NotNull Throwable throwable, @Nullable String dist
392395 }
393396
394397 /**
395- * PostHog uses the <a href="https://develop.sentry.dev/sdk/data-model/event-payloads/exception/">Sentry exception
396- * interface</a> for compatibility reasons, so convert to that.
398+ * Generates the exception object for PostHog. We generate a resolved exception, unlike some of their clients.
397399 *
398- * @return the exception interface as json
400+ * @see <a href="https://github.com/PostHog/posthog/blob/master/rust/cymbal/src/types/mod.rs#L34">sentry type defs</a>
399401 */
400402 private @ NotNull JsonObject buildExceptionInterface (@ NotNull Throwable exc , int parentId ) {
401403 final JsonObject exception = new JsonObject ();
402404 exception .addProperty ("type" , exc .getClass ().getSimpleName ());
403- exception .addProperty ("module" , exc .getClass ().getPackageName ());
405+ String moduleName = exc .getClass ().getPackageName ();
406+ if (exc .getClass ().getModule ().isNamed ())
407+ moduleName = exc .getClass ().getModule ().getName () + "/" + moduleName ;
408+ exception .addProperty ("module" , moduleName );
404409 exception .addProperty ("value" , Objects .requireNonNullElse (exc .getMessage (), "" ));
405410
406411 JsonObject mechanism = new JsonObject ();
407412 mechanism .addProperty ("type" , "generic" );
413+ // We don't currently have a way to indicate this, so just assume yes because the user passed it to us.
408414 mechanism .addProperty ("handled" , true );
415+ // We include exception_id and parent_id because it is part of the Sentry exception interface to indicate
416+ // exception chaining. PostHog does not currently support this as far as I can tell.
409417 mechanism .addProperty ("exception_id" , parentId + 1 );
410418 if (parentId != -1 ) {
411419 mechanism .addProperty ("type" , "chained" );
@@ -415,47 +423,41 @@ public void captureException(@NotNull Throwable throwable, @Nullable String dist
415423
416424 JsonObject stackTrace = new JsonObject ();
417425 stackTrace .add ("frames" , getStackFrames (exc .getStackTrace ()));
418- stackTrace .addProperty ("type" , "raw " );
426+ stackTrace .addProperty ("type" , "resolved " );
419427 exception .add ("stacktrace" , stackTrace );
420428
421429 return exception ;
422430 }
423431
424432 private @ NotNull JsonArray getStackFrames (StackTraceElement [] elements ) {
425433 // Reference: https://github.com/getsentry/sentry-java/blob/9180dc53e73b588db5cb42166e4ee2dc8d3723bc/sentry/src/main/java/io/sentry/SentryStackTraceFactory.java#L30
434+ // Better reference: https://github.com/PostHog/posthog/blob/master/rust/cymbal/src/frames/mod.rs#L81
426435
427436 int startFrame = Math .max (elements .length - STACKTRACE_FRAME_LIMIT , 0 );
428437 JsonArray stackFrames = new JsonArray ();
429438 for (int i = elements .length - 1 ; i >= startFrame ; i --) {
430439 final StackTraceElement element = elements [i ];
431440 if (element == null ) continue ;
432441
442+ // We generate resolved frames for PostHog.
433443 final JsonObject frame = new JsonObject ();
434- // We lie and tell PostHog that this is a Python exception because they don't actually support
435- // Java yet :) As far as i can tell this is only actually used for syntax highlighting in source
436- // code (which we don't send) so this is probably OK for now.
437- frame .addProperty ("platform" , "python" );
444+ frame .addProperty ("resolved" , true );
445+ // We just use a 'random' value for the id because its required
446+ frame .addProperty ("raw_id" , String .valueOf (element .hashCode ()));
447+
448+ frame .addProperty ("mangled_name" , element .getMethodName ());
449+ frame .addProperty ("resolved_name" , element .getMethodName ());
450+ // Protocol doesn't accept negative line numbers which can be used to indicate unknown line no.
451+ if (element .getLineNumber () >= 0 )
452+ frame .addProperty ("line" , element .getLineNumber ());
438453 var fileName = element .getClassName ();
439454 if (element .getModuleName () != null )
440455 fileName = element .getModuleName () + "/" + fileName ;
441- frame .addProperty ("filename" , fileName );
442- frame .addProperty ("abs_path" , element .getFileName ());
443-
444- frame .addProperty ("module" , element .getClassName ());
445- frame .addProperty ("function" , element .getMethodName ());
446-
447- // Protocol doesn't accept negative line numbers.
448- // The runtime seem to use -2 as a way to signal a native method
449- if (element .getLineNumber () >= 0 )
450- frame .addProperty ("lineno" , element .getLineNumber ());
451-
452- // The following is required but we don't have this info in Java
453- frame .add ("pre_context" , new JsonArray ());
454- frame .add ("context_line" , JsonNull .INSTANCE );
455- frame .add ("post_context" , new JsonArray ());
456+ frame .addProperty ("source" , fileName );
456457
457458 // TODO: expand this further to allow user specified in-app filters.
458459 frame .addProperty ("in_app" , element .getModuleName () == null || !element .getModuleName ().startsWith ("java." ));
460+ frame .addProperty ("lang" , "java" );
459461
460462 stackFrames .add (frame );
461463 }
@@ -467,4 +469,5 @@ private void setPropertyIfAbsent(@NotNull JsonObject object, @NotNull String key
467469 object .addProperty (key , value );
468470 }
469471 }
472+
470473}
0 commit comments