26
26
#include " Convenience/SentryInclude.h"
27
27
#include " Convenience/SentryMacro.h"
28
28
29
+ #include " Utils/SentryFileUtils.h"
30
+ #include " Utils/SentryLogUtils.h"
31
+
29
32
#include " GenericPlatform/GenericPlatformOutputDevices.h"
30
33
#include " HAL/FileManager.h"
31
34
#include " HAL/PlatformSentryAttachment.h"
34
37
#include " Misc/Paths.h"
35
38
#include " UObject/GarbageCollection.h"
36
39
#include " UObject/UObjectThreadContext.h"
37
- #include " Utils/SentryLogUtils.h"
38
40
39
41
void FAppleSentrySubsystem::InitWithSettings (const USentrySettings* settings, USentryBeforeSendHandler* beforeSendHandler, USentryBeforeBreadcrumbHandler* beforeBreadcrumbHandler, USentryTraceSampler* traceSampler)
40
42
{
43
+ isScreenshotAttachmentEnabled = settings->AttachScreenshot ;
44
+ isGameLogAttachmentEnabled = settings->EnableAutoLogAttachment ;
45
+
41
46
[SENTRY_APPLE_CLASS (PrivateSentrySDKOnly) setSdkName:@" sentry.cocoa.unreal" ];
42
47
43
48
dispatch_group_t sentryDispatchGroup = dispatch_group_create ();
@@ -65,24 +70,18 @@ void FAppleSentrySubsystem::InitWithSettings(const USentrySettings* settings, US
65
70
#if SENTRY_UIKIT_AVAILABLE
66
71
options.attachScreenshot = settings->AttachScreenshot ;
67
72
#endif
68
- options.initialScope = ^(SentryScope* scope) {
69
- if (settings->EnableAutoLogAttachment ) {
70
- const FString logFilePath = IFileManager::Get ().ConvertToAbsolutePathForExternalAppForRead (*FGenericPlatformOutputDevices::GetAbsoluteLogFilename ());
71
- SentryAttachment* logAttachment = [[SENTRY_APPLE_CLASS (SentryAttachment) alloc] initWithPath:logFilePath.GetNSString ()];
72
- [scope addAttachment:logAttachment];
73
- }
74
- return scope;
75
- };
76
73
options.onCrashedLastRun = ^(SentryEvent* event) {
77
74
if (settings->AttachScreenshot )
78
75
{
79
76
// If a screenshot was captured during assertion/crash in the previous app run
80
77
// find the most recent one and upload it to Sentry.
81
- const FString& screenshotPath = GetLatestScreenshot ();
82
- if (!screenshotPath.IsEmpty ())
83
- {
84
- UploadScreenshotForEvent (MakeShareable (new SentryIdApple (event.eventId )), screenshotPath);
85
- }
78
+ UploadScreenshotForEvent (MakeShareable (new SentryIdApple (event.eventId )), GetLatestScreenshot ());
79
+ }
80
+ if (settings->EnableAutoLogAttachment )
81
+ {
82
+ // Unreal creates game log backups automatically on every app run. If logging is enabled for current configuration, SDK can
83
+ // find the most recent one and upload it to Sentry.
84
+ UploadGameLogForEvent (MakeShareable (new SentryIdApple (event.eventId )), GetLatestGameLog ());
86
85
}
87
86
};
88
87
options.beforeSend = ^SentryEvent* (SentryEvent* event) {
@@ -206,40 +205,49 @@ void FAppleSentrySubsystem::ClearBreadcrumbs()
206
205
207
206
TSharedPtr<ISentryId> FAppleSentrySubsystem::CaptureMessage (const FString& message, ESentryLevel level)
208
207
{
209
- SentryId* id = [SENTRY_APPLE_CLASS (SentrySDK) captureMessage:message.GetNSString () withScopeBlock:^(SentryScope* scope){
210
- [scope setLevel:SentryConvertersApple::SentryLevelToNative (level)];
211
- }];
212
-
213
- return MakeShareable (new SentryIdApple (id));
208
+ FSentryScopeDelegate onConfigureScope;
209
+ return CaptureMessageWithScope (message, onConfigureScope, level);
214
210
}
215
211
216
212
TSharedPtr<ISentryId> FAppleSentrySubsystem::CaptureMessageWithScope (const FString& message, const FSentryScopeDelegate& onConfigureScope, ESentryLevel level)
217
213
{
218
- SentryId* id = [SENTRY_APPLE_CLASS (SentrySDK) captureMessage:message.GetNSString () withScopeBlock:^(SentryScope* scope){
214
+ SentryId* nativeId = [SENTRY_APPLE_CLASS (SentrySDK) captureMessage:message.GetNSString () withScopeBlock:^(SentryScope* scope){
219
215
[scope setLevel:SentryConvertersApple::SentryLevelToNative (level)];
220
216
onConfigureScope.ExecuteIfBound (MakeShareable (new SentryScopeApple (scope)));
221
217
}];
222
218
223
- return MakeShareable (new SentryIdApple (id));
219
+ TSharedPtr<ISentryId> id = MakeShareable (new SentryIdApple (nativeId));
220
+
221
+ if (isGameLogAttachmentEnabled)
222
+ {
223
+ UploadGameLogForEvent (id, GetGameLogPath ());
224
+ }
225
+
226
+ return id;
224
227
}
225
228
226
229
TSharedPtr<ISentryId> FAppleSentrySubsystem::CaptureEvent (TSharedPtr<ISentryEvent> event)
227
230
{
228
- TSharedPtr<SentryEventApple> eventIOS = StaticCastSharedPtr<SentryEventApple>(event);
229
-
230
- SentryId* id = [SENTRY_APPLE_CLASS (SentrySDK) captureEvent:eventIOS->GetNativeObject ()];
231
- return MakeShareable (new SentryIdApple (id));
231
+ FSentryScopeDelegate onConfigureScope;
232
+ return CaptureEventWithScope (event, onConfigureScope);
232
233
}
233
234
234
235
TSharedPtr<ISentryId> FAppleSentrySubsystem::CaptureEventWithScope (TSharedPtr<ISentryEvent> event, const FSentryScopeDelegate& onConfigureScope)
235
236
{
236
- TSharedPtr<SentryEventApple> eventIOS = StaticCastSharedPtr<SentryEventApple>(event);
237
+ TSharedPtr<SentryEventApple> eventApple = StaticCastSharedPtr<SentryEventApple>(event);
237
238
238
- SentryId* id = [SENTRY_APPLE_CLASS (SentrySDK) captureEvent:eventIOS ->GetNativeObject () withScopeBlock:^(SentryScope* scope) {
239
+ SentryId* nativeId = [SENTRY_APPLE_CLASS (SentrySDK) captureEvent:eventApple ->GetNativeObject () withScopeBlock:^(SentryScope* scope) {
239
240
onConfigureScope.ExecuteIfBound (MakeShareable (new SentryScopeApple (scope)));
240
241
}];
241
242
242
- return MakeShareable (new SentryIdApple (id));
243
+ TSharedPtr<ISentryId> id = MakeShareable (new SentryIdApple (nativeId));
244
+
245
+ if (isGameLogAttachmentEnabled)
246
+ {
247
+ UploadGameLogForEvent (id, GetGameLogPath ());
248
+ }
249
+
250
+ return id;
243
251
}
244
252
245
253
TSharedPtr<ISentryId> FAppleSentrySubsystem::CaptureEnsure (const FString& type, const FString& message)
@@ -251,8 +259,16 @@ TSharedPtr<ISentryId> FAppleSentrySubsystem::CaptureEnsure(const FString& type,
251
259
SentryEvent *exceptionEvent = [[SENTRY_APPLE_CLASS (SentryEvent) alloc] init];
252
260
exceptionEvent.exceptions = nativeExceptionArray;
253
261
254
- SentryId* id = [SENTRY_APPLE_CLASS (SentrySDK) captureEvent:exceptionEvent];
255
- return MakeShareable (new SentryIdApple (id));
262
+ SentryId* nativeId = [SENTRY_APPLE_CLASS (SentrySDK) captureEvent:exceptionEvent];
263
+
264
+ TSharedPtr<ISentryId> id = MakeShareable (new SentryIdApple (nativeId));
265
+
266
+ if (isGameLogAttachmentEnabled)
267
+ {
268
+ UploadGameLogForEvent (id, GetGameLogPath ());
269
+ }
270
+
271
+ return id;
256
272
}
257
273
258
274
@@ -389,37 +405,60 @@ TSharedPtr<ISentryTransactionContext> FAppleSentrySubsystem::ContinueTrace(const
389
405
return MakeShareable (new SentryTransactionContextApple (transactionContext));
390
406
}
391
407
392
- void FAppleSentrySubsystem::UploadScreenshotForEvent (TSharedPtr<ISentryId> eventId, const FString& screenshotPath ) const
408
+ void FAppleSentrySubsystem::UploadAttachmentForEvent (TSharedPtr<ISentryId> eventId, const FString& filePath, const FString& name, bool deleteAfterUpload ) const
393
409
{
394
410
IFileManager& fileManager = IFileManager::Get ();
395
- if (!fileManager.FileExists (*screenshotPath ))
411
+ if (!fileManager.FileExists (*filePath ))
396
412
{
397
- UE_LOG (LogSentrySdk, Error, TEXT (" Failed to upload screenshot - path provided did not exist: %s" ), *screenshotPath );
413
+ UE_LOG (LogSentrySdk, Error, TEXT (" Failed to upload attachment - file path provided did not exist: %s" ), *filePath );
398
414
return ;
399
415
}
400
416
401
- const FString& screenshotFilePathExt = fileManager.ConvertToAbsolutePathForExternalAppForRead (*screenshotPath );
417
+ const FString& filePathExt = fileManager.ConvertToAbsolutePathForExternalAppForRead (*filePath );
402
418
403
- SentryAttachment* screenshotAttachment = [[SENTRY_APPLE_CLASS (SentryAttachment) alloc] initWithPath:screenshotFilePathExt .GetNSString () filename:@ " screenshot.png " ];
419
+ SentryAttachment* attachment = [[SENTRY_APPLE_CLASS (SentryAttachment) alloc] initWithPath:filePathExt .GetNSString () filename:name. GetNSString () ];
404
420
405
421
SentryOptions* options = [SENTRY_APPLE_CLASS (PrivateSentrySDKOnly) options];
406
422
int32 size = options.maxAttachmentSize ;
407
423
408
- SentryEnvelopeItem* envelopeItem = [[SENTRY_APPLE_CLASS (SentryEnvelopeItem) alloc] initWithAttachment:screenshotAttachment maxAttachmentSize:size];
424
+ SentryEnvelopeItem* envelopeItem = [[SENTRY_APPLE_CLASS (SentryEnvelopeItem) alloc] initWithAttachment:attachment maxAttachmentSize:size];
409
425
410
426
SentryId* id = StaticCastSharedPtr<SentryIdApple>(eventId)->GetNativeObject ();
411
427
412
428
SentryEnvelope* envelope = [[SENTRY_APPLE_CLASS (SentryEnvelope) alloc] initWithId:id singleItem:envelopeItem];
413
429
414
430
[SENTRY_APPLE_CLASS (PrivateSentrySDKOnly) captureEnvelope:envelope];
415
431
416
- // After uploading screenshot it's no longer needed so delete
417
- if (!fileManager.Delete (*screenshotPath))
432
+ if (deleteAfterUpload)
418
433
{
419
- UE_LOG (LogSentrySdk, Error, TEXT (" Failed to delete screenshot: %s" ), *screenshotPath);
434
+ if (!fileManager.Delete (*filePath))
435
+ {
436
+ UE_LOG (LogSentrySdk, Error, TEXT (" Failed to delete file attachment after upload: %s" ), *filePath);
437
+ }
420
438
}
421
439
}
422
440
441
+ void FAppleSentrySubsystem::UploadScreenshotForEvent (TSharedPtr<ISentryId> eventId, const FString& screenshotPath) const
442
+ {
443
+ if (screenshotPath.IsEmpty ())
444
+ {
445
+ // Screenshot capturing is a best-effort solution so if one wasn't captured (path is empty) skip the upload
446
+ return ;
447
+ }
448
+
449
+ UploadAttachmentForEvent (eventId, screenshotPath, TEXT (" screenshot.png" ), true );
450
+ }
451
+
452
+ void FAppleSentrySubsystem::UploadGameLogForEvent (TSharedPtr<ISentryId> eventId, const FString& logFilePath) const
453
+ {
454
+ #if NO_LOGGING
455
+ // If writing logs to a file is disabled (i.e. default behavior for Shipping builds) skip the upload
456
+ return ;
457
+ #endif
458
+
459
+ UploadAttachmentForEvent (eventId, logFilePath, SentryFileUtils::GetGameLogName ());
460
+ }
461
+
423
462
FString FAppleSentrySubsystem::GetScreenshotPath () const
424
463
{
425
464
return FPaths::Combine (FPaths::ProjectSavedDir (), TEXT (" SentryScreenshots" ), FString::Printf (TEXT (" screenshot-%s.png" ), *FDateTime::Now ().ToString ()));
0 commit comments