diff --git a/CHANGELOG.md b/CHANGELOG.md index f6ac90b6a..620ddad30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Fixes +- The SDK's build logs when targeting Android are not a lot less noisy. The SDK will also no longer omit the sentry-cli logs from the gradle build output. ([#1995](https://github.com/getsentry/sentry-unity/pull/1995)) - When targeting iOS and disabling native support, the SDK no longer causes builds to fail with an `Undefined symbol: _SentryNativeBridgeIsEnabled` error. ([#1983](https://github.com/getsentry/sentry-unity/pull/1983)) ### Dependencies diff --git a/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs b/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs index bacab1b88..19b5bbfaf 100644 --- a/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs +++ b/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs @@ -96,6 +96,15 @@ public void OnPostGenerateGradleAndroidProject(string basePath) CopyAndroidSdkToGradleProject(unityProjectPath, gradleProjectPath); AddAndroidSdkDependencies(gradleProjectPath); + + if (_sentryCliOptions?.IgnoreCliErrors is true) + { + _logger.LogWarning("Sentry CLI errors will be ignored during build. BE AWARE you might have " + + "unminified/unsymbolicated crashes in production if the debug symbol upload fails. " + + "When using this flag, you should store built sourcemaps and debug files, to re-run the " + + "upload symbols command at a later point."); + } + SetupSymbolsUpload(unityProjectPath, gradleProjectPath); SetupProguard(gradleProjectPath); } diff --git a/src/Sentry.Unity.Editor/Android/DebugSymbolUpload.cs b/src/Sentry.Unity.Editor/Android/DebugSymbolUpload.cs index bd798d954..b5d58ed91 100644 --- a/src/Sentry.Unity.Editor/Android/DebugSymbolUpload.cs +++ b/src/Sentry.Unity.Editor/Android/DebugSymbolUpload.cs @@ -25,7 +25,6 @@ internal class DebugSymbolUpload private readonly string _gradleScriptPath; private readonly bool _isExporting; private readonly bool _isMinifyEnabled; - private readonly bool _ignoreCliErrors; private readonly SentryCliOptions? _cliOptions; private readonly List _symbolUploadPaths; @@ -35,7 +34,7 @@ internal class DebugSymbolUpload private const string SymbolUploadTaskEndComment = "// Autogenerated Sentry symbol upload task [end]"; private const string SentryCliMarker = "SENTRY_CLI"; private const string UploadArgsMarker = "UPLOAD_ARGS"; - private const string MappingPathMarker = "MAPPING_PATH"; + private const string ProguardArgsMarker = "PROGUARD_ARGS"; private string SymbolUploadTaskFormat { @@ -46,22 +45,14 @@ private string SymbolUploadTaskFormat stringBuilder.AppendLine("afterEvaluate {"); stringBuilder.AppendLine("task sentryUploadSymbols {"); stringBuilder.AppendLine(" doLast {"); - if (_isExporting) - { - stringBuilder.AppendLine(" println 'Uploading symbols to Sentry.'"); - } - else - { - var logsDir = $"{ConvertSlashes(_unityProjectPath)}/Logs"; - Directory.CreateDirectory(logsDir); - stringBuilder.AppendLine(" println 'Uploading symbols to Sentry. You can find the full log in ./Logs/sentry-symbols-upload.log (the file content may not be strictly sequential because it\\'s a merge of two streams).'"); - stringBuilder.AppendLine($" def logFilePath = '{logsDir}/{SymbolUploadLogName}'"); - stringBuilder.AppendLine(" def sentryLogFile = new FileOutputStream(logFilePath)"); - if (_ignoreCliErrors) - { - stringBuilder.AppendLine(" try {"); - } - } + stringBuilder.AppendLine(" println 'Uploading symbols to Sentry.'"); + + var logsDir = $"{ConvertSlashes(_unityProjectPath)}/Logs"; + Directory.CreateDirectory(logsDir); + stringBuilder.AppendLine($" def logFilePath = '{logsDir}/{SymbolUploadLogName}'"); + stringBuilder.AppendLine(" def sentryLogFile = new FileOutputStream(logFilePath)"); + stringBuilder.AppendLine(" def outputStream = new org.apache.tools.ant.util.TeeOutputStream(System.out, sentryLogFile)"); + stringBuilder.AppendLine(" def errorStream = new org.apache.tools.ant.util.TeeOutputStream(System.err, sentryLogFile)"); stringBuilder.AppendLine(" exec {"); stringBuilder.AppendLine(" environment 'SENTRY_PROPERTIES', './sentry.properties'"); @@ -69,18 +60,11 @@ private string SymbolUploadTaskFormat stringBuilder.AppendLine($" args = ['debug-files', 'upload'{UploadArgsMarker}]"); if (!_isExporting) { - stringBuilder.AppendLine(" standardOutput sentryLogFile"); - stringBuilder.AppendLine(" errorOutput sentryLogFile"); + stringBuilder.AppendLine(" standardOutput outputStream"); + stringBuilder.AppendLine(" errorOutput errorStream"); } - stringBuilder.AppendLine(" }"); - if (!_isExporting && _ignoreCliErrors) - { - stringBuilder.AppendLine(" } catch (exception) {"); - stringBuilder.AppendLine(" def file = new File(logFilePath)"); - stringBuilder.AppendLine(" file.append('===ERROR===' + exception)"); - stringBuilder.AppendLine(" }"); - } + CheckMapping(stringBuilder); stringBuilder.AppendLine(" }"); stringBuilder.AppendLine("}"); @@ -110,7 +94,6 @@ public DebugSymbolUpload(IDiagnosticLogger logger, _gradleScriptPath = Path.Combine(_gradleProjectPath, "launcher/build.gradle"); _isExporting = isExporting; _isMinifyEnabled = minifyEnabled; - _ignoreCliErrors = cliOptions != null && cliOptions.IgnoreCliErrors; _cliOptions = cliOptions; _symbolUploadPaths = GetSymbolUploadPaths(application); @@ -130,11 +113,16 @@ public void AppendUploadToGradleFile(string sentryCliPath) } var uploadDifArguments = ", '--il2cpp-mapping'"; - if (_cliOptions != null && _cliOptions.UploadSources) + if (_cliOptions?.UploadSources == true) { uploadDifArguments += ", '--include-sources'"; } + if (_cliOptions?.IgnoreCliErrors == true) + { + uploadDifArguments += ", '--allow-failure'"; + } + if (_isExporting) { _logger.LogInfo("Project is exporting. Setting upload-dif to 'project.rootDir'"); @@ -142,11 +130,12 @@ public void AppendUploadToGradleFile(string sentryCliPath) uploadDifArguments += ", project.rootDir"; sentryCliPath = $"./{Path.GetFileName(sentryCliPath)}"; } - else + else if (_symbolUploadPaths.Count > 0) { + _logger.LogInfo("Setting upload-dif paths"); + foreach (var symbolUploadPath in _symbolUploadPaths) { - _logger.LogInfo("Setting upload-dif paths"); if (Directory.Exists(symbolUploadPath)) { _logger.LogDebug("Adding '{0}'", symbolUploadPath); @@ -159,11 +148,19 @@ public void AppendUploadToGradleFile(string sentryCliPath) } } + var uploadProguardArguments = string.Empty; + if (_cliOptions?.IgnoreCliErrors == true) + { + uploadProguardArguments += ", '--allow-failure'"; + } + + uploadProguardArguments += $", '{_mappingFilePath}'"; + var symbolUploadText = SymbolUploadTaskFormat; symbolUploadText = symbolUploadText.Trim(); symbolUploadText = symbolUploadText.Replace(SentryCliMarker, sentryCliPath); symbolUploadText = symbolUploadText.Replace(UploadArgsMarker, uploadDifArguments); - symbolUploadText = symbolUploadText.Replace(MappingPathMarker, _mappingFilePath); + symbolUploadText = symbolUploadText.Replace(ProguardArgsMarker, uploadProguardArguments); using var streamWriter = File.AppendText(_gradleScriptPath); streamWriter.WriteLine(SymbolUploadTaskStartComment); @@ -263,29 +260,20 @@ private void CheckMapping(StringBuilder stringBuilder) Directory.CreateDirectory(logsDir); stringBuilder.AppendLine($" def mappingLogFilePath = '{logsDir}/{MappingUploadLogName}'"); stringBuilder.AppendLine($" def mappingLogFile = new FileOutputStream(mappingLogFilePath)"); - if (!_isExporting && _ignoreCliErrors) - { - stringBuilder.AppendLine(" try {"); - } + stringBuilder.AppendLine(" def mappingOutputStream = new org.apache.tools.ant.util.TeeOutputStream(System.out, mappingLogFile)"); + stringBuilder.AppendLine(" def mappingErrorStream = new org.apache.tools.ant.util.TeeOutputStream(System.err, mappingLogFile)"); } stringBuilder.AppendLine(" exec {"); stringBuilder.AppendLine(" environment 'SENTRY_PROPERTIES', './sentry.properties'"); stringBuilder.AppendLine($" executable '{SentryCliMarker}'"); - stringBuilder.AppendLine($" args = ['upload-proguard', {MappingPathMarker}]"); + stringBuilder.AppendLine($" args = ['upload-proguard'{ProguardArgsMarker}]"); + // stringBuilder.AppendLine($" args = ['debug-files', 'upload'{UploadArgsMarker}]"); if (!_isExporting) { - stringBuilder.AppendLine(" standardOutput mappingLogFile"); - stringBuilder.AppendLine(" errorOutput mappingLogFile"); + stringBuilder.AppendLine(" standardOutput mappingOutputStream"); + stringBuilder.AppendLine(" errorOutput mappingErrorStream"); } - stringBuilder.AppendLine(" }"); - if (!_isExporting && _ignoreCliErrors) - { - stringBuilder.AppendLine(" } catch (exception) {"); - stringBuilder.AppendLine(" def file = new File(mappingLogFilePath)"); - stringBuilder.AppendLine(" file.append('===ERROR===' + exception)"); - stringBuilder.AppendLine(" }"); - } } private string GetMappingFilePath(IApplication? application) @@ -305,7 +293,6 @@ private string GetMappingFilePath(IApplication? application) { var gradleProjectPath = Path.Combine(_unityProjectPath, gradleRelativePath); mappingPathFormat = Path.Combine(gradleProjectPath, "launcher/build/outputs/mapping/{0}/mapping.txt"); - mappingPathFormat = $"'{mappingPathFormat}'"; } var mappingPath = mappingPathFormat.Replace("{0}", buildType); diff --git a/src/Sentry.Unity.Editor/Android/PostBuildCheck.cs b/src/Sentry.Unity.Editor/Android/PostBuildCheck.cs deleted file mode 100644 index 374cf7c2e..000000000 --- a/src/Sentry.Unity.Editor/Android/PostBuildCheck.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System; -using System.IO; -using Sentry.Extensibility; -using UnityEditor; -using UnityEditor.Build; -using UnityEditor.Build.Reporting; -using UnityEngine; - -namespace Sentry.Unity.Editor.Android; - -public class PostBuildCheck : IPostprocessBuildWithReport -{ - public int callbackOrder { get; } = 117; - - public void OnPostprocessBuild(BuildReport report) - { - var checker = new UploadTaskChecker(SentryScriptableObject.ConfiguredBuildTimeOptions); - checker.CheckUploadTaskResult(); - } -} - -internal class UploadTaskChecker -{ - private readonly SentryUnityOptions? _options; - private readonly SentryCliOptions? _sentryCliOptions; - private readonly IDiagnosticLogger _logger; - - internal UploadTaskChecker(Func<(SentryUnityOptions?, SentryCliOptions?)> getOptions) - { - (_options, _sentryCliOptions) = getOptions(); - _logger = _options?.DiagnosticLogger ?? new UnityLogger(_options ?? new SentryUnityOptions()); - } - - internal void CheckUploadTaskResult() - { - if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android) - { - _logger.LogDebug("Target platform is not Android. Will not validate the upload task."); - return; - } - - if (EditorUserBuildSettings.exportAsGoogleAndroidProject) - { - _logger.LogDebug("The task is not executed during export. Will not validate the upload task."); - return; - } - - // ReSharper disable once Unity.NoNullPropagation - if (!(_sentryCliOptions?.UploadSymbols ?? false)) - { - _logger.LogDebug("Symbol Upload is disabled. Will not validate the upload task."); - return; - } - - var projectDir = Directory.GetParent(Application.dataPath); - if (projectDir == null) - { - _logger.LogDebug("Could not find Unity Project path. Will not check upload symbols task result."); - return; - } - - var unityProjectPath = projectDir.FullName; - CheckUploadSymbolLogs(unityProjectPath); - CheckUploadMappingLogs(unityProjectPath); - } - - private void CheckUploadSymbolLogs(string unityProjectPath) - { - var symbolUploadLogPath = Path.Combine(unityProjectPath, "Logs", DebugSymbolUpload.SymbolUploadLogName); - var hasSymbolError = HasError(symbolUploadLogPath, out var symbolError, out var symbolLog); - if (hasSymbolError) - { - _logger.LogWarning($"Symbol upload task error: {symbolError}"); - } - - LogFileContent("Symbol upload log file content:", symbolLog, hasSymbolError); - File.WriteAllText(symbolUploadLogPath, symbolLog); // Clean up the log file - } - - private void CheckUploadMappingLogs(string unityProjectPath) - { - if (!AndroidUtils.ShouldUploadMapping()) - { - _logger.LogDebug("Minification is disabled. Will not check upload mapping task result."); - return; - } - - var mappingUploadLogPath = Path.Combine(unityProjectPath, "Logs", DebugSymbolUpload.MappingUploadLogName); - var hasMappingError = HasError(mappingUploadLogPath, out var mappingError, out var mappingLog); - if (hasMappingError) - { - _logger.LogWarning($"Mapping upload task error: {mappingError}"); - } - - LogFileContent("Mapping upload log file content:", mappingLog, hasMappingError); - File.WriteAllText(mappingUploadLogPath, mappingLog); // Clean up the log file - } - - private bool HasError(string filePath, out string error, out string fileContent) - { - fileContent = error = string.Empty; - const string errorMarker = "===ERROR==="; - if (!File.Exists(filePath)) - { - return false; - } - - var text = File.ReadAllText(filePath); - if (!text.Contains(errorMarker)) - { - fileContent = text; - return false; - } - - var index = text.IndexOf(errorMarker, StringComparison.InvariantCulture); - if (index < 0) - { - return false; - } - - fileContent = text.Substring(0, index); - error = text.Substring(index + errorMarker.Length); - return !string.IsNullOrEmpty(error); - } - - private void LogFileContent(string title, string fileContent, bool hasError) - { - var logFunction = new Action(message => - { - if (hasError) - { - Debug.LogWarning(message); - } - else - { - Debug.Log(message); - } - }); - - logFunction(title); - - const int maxLogLength = 8192; - if (fileContent.Length < maxLogLength) - { - logFunction(fileContent); - return; - } - - for (var i = 0; i < fileContent.Length; i += maxLogLength) - { - var chunkLength = maxLogLength + i > fileContent.Length ? fileContent.Length - i : maxLogLength; - logFunction(fileContent.Substring(i, chunkLength)); - } - } -} diff --git a/test/Sentry.Unity.Editor.Tests/Android/DebugSymbolUploadTests.cs b/test/Sentry.Unity.Editor.Tests/Android/DebugSymbolUploadTests.cs index 4c9650422..c19f327cb 100644 --- a/test/Sentry.Unity.Editor.Tests/Android/DebugSymbolUploadTests.cs +++ b/test/Sentry.Unity.Editor.Tests/Android/DebugSymbolUploadTests.cs @@ -155,13 +155,12 @@ public void AppendUploadToGradleFile_AllRequirementsMet_AppendsUploadTask(bool i if (!isExporting) { - keywords.Add("logFilePath"); + keywords.Add("standardOutput outputStream"); } - if (!isExporting && ignoreCliErrors) + if (ignoreCliErrors) { - keywords.Add("try {"); - keywords.Add("} catch"); + keywords.Add("--allow-failure"); } if (addMapping) @@ -169,7 +168,7 @@ public void AppendUploadToGradleFile_AllRequirementsMet_AppendsUploadTask(bool i keywords.Add("args = ['upload-proguard'"); if (!isExporting) { - keywords.Add("mappingLogFile"); + keywords.Add("standardOutput mappingOutputStream"); } }