getsentry / sentry-unity

Development of Sentry SDK for Unity
https://docs.sentry.io/platforms/unity/
MIT License
192 stars 50 forks source link

Transaction cannot be started from native layer before .Net SDK initialized for Android and iOS #1609

Open pavlo-supenko opened 1 month ago

pavlo-supenko commented 1 month ago

Environment

We are using:

The issue is presenting on iOS and Android devices and cant be checked in Editor because it's connected with native tracking before the engine start.

Steps to Reproduce

Android

  1. Create empty Android project.
  2. Import Sentry package.
  3. (optional I think) Enable Il2cpp backend.
  4. Enable using of custom android manifest to use custom activity.
  5. Create activity class and start transaction in OnCreate method override.
package com.unity3d.player;

import android.os.Bundle;
import android.util.Log;

import io.sentry.ISpan;
import io.sentry.ITransaction;
import io.sentry.Sentry;
import io.sentry.SpanStatus;

public class SentryCustomActivity extends UnityPlayerActivity
{

    @Override protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        Log.d("SentryCustomActivity", "Custom activity started");
        ITransaction activityTransaction = Sentry.startTransaction("Unity start", "activity creation");
        Log.d("SentryCustomActivity", "Transaction created");
        ISpan argumentsSpan = activityTransaction.startChild("cmd args processing");
        Log.d("SentryCustomActivity", "Span started");

        Log.d("SentryCustomActivity", "Super method invoked");

        argumentsSpan.finish(SpanStatus.OK);
        Log.d("SentryCustomActivity", "Span finished");
        activityTransaction.finish(SpanStatus.OK);
        Log.d("SentryCustomActivity", "Custom activity finished");
    }
}
  1. Create built-time and run-time Sentry configurators and enable tracing in them.
public class SentryRuntimeConfiguration : Sentry.Unity.SentryRuntimeOptionsConfiguration
{
    public override void Configure(SentryUnityOptions options)
    {
        options.EnableTracing = true;
        options.TracesSampleRate = 1f;
    }
}

public class SentryBuildTimeConfiguration : Sentry.Unity.SentryBuildTimeOptionsConfiguration
{
    public override void Configure(SentryUnityOptions options, SentryCliOptions cliOptions)
    {
        options.EnableTracing = true;
        options.TracesSampleRate = 1f;
    }
}
  1. Enable debug mode not only for editor.
  2. Build and run. Check logcat.

iOS

  1. The same steps as in Android project to create it, import Sentry, and modify build- and run-time configurators.
  2. Build project.
  3. Modify main.m file and start transaction after SentrySDK is initialized by adding lines 7, 20, 23-26.
#include <Sentry/Sentry.h>
#include "SentryOptions.m"
#include <UnityFramework/UnityFramework.h>

UnityFramework* UnityFrameworkLoad()
{
    id<SentrySpan> transaction = [SentrySDK startTransactionWithName:@"Unity start" operation:@"main"];

    NSString* bundlePath = nil;
    bundlePath = [[NSBundle mainBundle] bundlePath];
    bundlePath = [bundlePath stringByAppendingString: @"/Frameworks/UnityFramework.framework"];

    NSBundle* bundle = [NSBundle bundleWithPath: bundlePath];
    if ([bundle isLoaded] == false) [bundle load];

    UnityFramework* ufw = [bundle.principalClass getInstance];
    if (![ufw appController])
    {
        // unity is not initialized
        [transaction finishWithStatus:kSentrySpanStatusInternalError];
        [ufw setExecuteHeader: &_mh_execute_header];
    }
    else
    {
        [transaction finishWithStatus:kSentrySpanStatusOk];
    }

    return ufw;
}

int main(int argc, char* argv[])
{
    @autoreleasepool
    {
        SentryOptions* options = getSentryOptions();
        if(options != nil)
        {
            [SentrySDK startWithOptions:options];
        }

        id ufw = UnityFrameworkLoad();
        [ufw runUIApplicationMainWithArgc: argc argv: argv];
        return 0;
    }
}

Expected Result

Expect that any transactions started from native layer before .Net SDK initialized will work and all transactions appear on Sentry console.

Actual Result

Android

Transaction start operation said that Tracing is disabled but it is in build- and run-time configurators.

2024-04-08 12:23:16.020 20985-20985 SentryCustomActivity    com.teachdraw.tk.sandbox             D  Custom activity started
2024-04-08 12:23:16.021 20985-20985 Sentry                  com.teachdraw.tk.sandbox             I  Tracing is disabled and this 'startTransaction' returns a no-op.
2024-04-08 12:23:16.021 20985-20985 SentryCustomActivity    com.teachdraw.tk.sandbox             D  Transaction created
2024-04-08 12:23:16.021 20985-20985 SentryCustomActivity    com.teachdraw.tk.sandbox             D  Span started
2024-04-08 12:23:16.021 20985-20985 SentryCustomActivity    com.teachdraw.tk.sandbox             D  Super method invoked
2024-04-08 12:23:16.022 20985-20985 SentryCustomActivity    com.teachdraw.tk.sandbox             D  Span finished
2024-04-08 12:23:16.022 20985-20985 SentryCustomActivity    com.teachdraw.tk.sandbox             D  Custom activity finished

iOS

On iOS case transaction started as I see but it's not finishing because of internal_error

default 13:48:57.262723+0300    Template    [Sentry] [debug] [SentryTransactionContext:147] Created transaction context with name Unity start
default 13:48:57.262789+0300    Template    [Sentry] [debug] [SentrySpanContext:93] Created span context with trace ID 2af73caa97e647f6ba390b8b3a0add91; span ID 9b797e29c3ba4190; parent span ID (null); operation main
default 13:48:57.262845+0300    Template    [Sentry] [debug] [SentryFramesTracker:79] Initialized frame tracker <SentryFramesTracker: 0x280db2450>
default 13:48:57.264883+0300    Template    [Sentry] [debug] [SentryTracer:203] Started tracer with id: 2af73caa97e647f6ba390b8b3a0add91
default 13:48:57.265038+0300    Template    [Sentry] [debug] [SentryLaunchProfiling:157] No launch tracer present to stop.
default 13:48:57.265075+0300    Template    [Sentry] [debug] [SentryLaunchProfiling:45] Won't profile next launch due to specified options configuration: options.enableAppLaunchProfiling: 0; options.enableTracing: 0
default 13:48:57.265130+0300    Template    [Sentry] [debug] [SentryFileManager:51] No file to delete at /var/mobile/Containers/Data/Application/EF35AB1F-318A-4BF7-AFFE-90B9951F0B0B/Library/Application Support/io.sentry/profileLaunch
default 13:48:57.498689+0300    Template    [Sentry] [debug] [SentryReachability:138] SentryConnectivityCallback called with target: <SCNetworkReachability 0x102c07240 [0x1f5f00190]> {name = sentry.io (complete, 35.186.247.156), flags = 0x00000003, if_index = 9}; flags: 3
default 13:48:57.498735+0300    Template    [Sentry] [debug] [SentryReachability:103] Entered synchronized region of SentryConnectivityCallback with flags: 3
default 13:48:57.498760+0300    Template    [Sentry] [debug] [SentryReachability:119] Notifying observers...
default 13:48:57.498886+0300    Template    [Sentry] [debug] [SentryReachability:121] Notifying <SentryBreadcrumbTracker: 0x2824a8920>
default 13:48:57.498907+0300    Template    [Sentry] [debug] [SentryScope:122] Add breadcrumb: <SentryBreadcrumb: 0x2833a2ac0, {
    category = "device.connectivity";
    data =     {
        connectivity = wifi;
    };
    level = info;
    timestamp = "2024-04-08T10:48:57.492Z";
    type = connectivity;
}>
default 13:48:57.498928+0300    Template    [Sentry] [debug] [SentryReachability:121] Notifying <SentryHttpTransport: 0x2802a4660>
default 13:48:57.498948+0300    Template    [Sentry] [debug] [SentryHttpTransport:106] Internet connection is back.
default 13:48:57.498967+0300    Template    [Sentry] [debug] [SentryHttpTransport:268] sendAllCachedEnvelopes start.
default 13:48:57.499013+0300    Template    [Sentry] [debug] [SentryHttpTransport:280] No envelopes left to send.
default 13:48:57.499037+0300    Template    [Sentry] [debug] [SentryHttpTransport:362] Finished sending.
default 13:48:57.499062+0300    Template    [Sentry] [debug] [SentryReachability:125] Finished notifying observers.
default 13:48:57.764524+0300    Template    [Sentry] [debug] [SentryTracer:452] Finished trace with traceID: (null) and status: internal_error

Logs or screenshots

Android

Full log from app start

sentry-android-activity-transaction-all.log

The same log but filtered with Sentry

sentry-android-activity-transaction-filtered.log

iOS

sentry-ios-main-transaction-all.log

Project I used for test

unity-sentry-test.zip

bitsandfoxes commented 1 month ago

Thanks for the detailed issue! One thing to be aware of and to manage expectations: Currently, there is no mechanism to sync transactions and spans between the native and the managed layer. So you'd be "stuck" with native transaction - for now (tm)

pavlo-supenko commented 1 month ago

Currently, there is no mechanism to sync transactions and spans between the native and the managed layer. So you'd be "stuck" with native transaction - for now (tm)

But it should work if I start and finish some transactions only on native layer and some another only on managed ? Am I understand correctly (that means that problem I described is valid) ?

bitsandfoxes commented 1 month ago

You can start and finish things on the same layer. But there is no passing of ID happening. So the spans and transactions will be disconnected from each other based on their layer.

pavlo-supenko commented 1 month ago

Yes, that would be great, in my case I need to track some native work we do before Unity starts separately from something inside engine, without blending Sentry layers.