diff --git a/src/Sentry.Android.AssemblyReader/AndroidAssemblyReaderFactory.cs b/src/Sentry.Android.AssemblyReader/AndroidAssemblyReaderFactory.cs index 62670899a9..e111a46f71 100644 --- a/src/Sentry.Android.AssemblyReader/AndroidAssemblyReaderFactory.cs +++ b/src/Sentry.Android.AssemblyReader/AndroidAssemblyReaderFactory.cs @@ -17,29 +17,29 @@ public static class AndroidAssemblyReaderFactory /// The reader public static IAndroidAssemblyReader Open(string apkPath, IList supportedAbis, DebugLogger? logger = null) { - logger?.Invoke("Opening APK: {0}", apkPath); + logger?.Invoke(DebugLoggerLevel.Debug, "Opening APK: {0}", apkPath); #if NET9_0 - logger?.Invoke("Reading files using V2 APK layout."); + logger?.Invoke(DebugLoggerLevel.Debug, "Reading files using V2 APK layout."); if (AndroidAssemblyStoreReaderV2.TryReadStore(apkPath, supportedAbis, logger, out var readerV2)) { - logger?.Invoke("APK uses AssemblyStore V2"); + logger?.Invoke(DebugLoggerLevel.Debug, "APK uses AssemblyStore V2"); return readerV2; } - logger?.Invoke("APK doesn't use AssemblyStore"); + logger?.Invoke(DebugLoggerLevel.Debug, "APK doesn't use AssemblyStore"); return new AndroidAssemblyDirectoryReaderV2(apkPath, supportedAbis, logger); #else - logger?.Invoke("Reading files using V1 APK layout."); + logger?.Invoke(DebugLoggerLevel.Debug, "Reading files using V1 APK layout."); var zipArchive = ZipFile.OpenRead(apkPath); if (zipArchive.GetEntry("assemblies/assemblies.manifest") is not null) { - logger?.Invoke("APK uses AssemblyStore V1"); + logger?.Invoke(DebugLoggerLevel.Debug, "APK uses AssemblyStore V1"); return new AndroidAssemblyStoreReaderV1(zipArchive, supportedAbis, logger); } - logger?.Invoke("APK doesn't use AssemblyStore"); + logger?.Invoke(DebugLoggerLevel.Debug, "APK doesn't use AssemblyStore"); return new AndroidAssemblyDirectoryReaderV1(zipArchive, supportedAbis, logger); #endif } diff --git a/src/Sentry.Android.AssemblyReader/ArchiveUtils.cs b/src/Sentry.Android.AssemblyReader/ArchiveUtils.cs index 0613eed1f9..d3b2f53e46 100644 --- a/src/Sentry.Android.AssemblyReader/ArchiveUtils.cs +++ b/src/Sentry.Android.AssemblyReader/ArchiveUtils.cs @@ -43,7 +43,7 @@ internal static MemoryStream Extract(this ZipArchiveEntry zipEntry) Debug.Assert(inputStream.Position == payloadOffset); var inputLength = (int)(inputStream.Length - payloadOffset); - logger?.Invoke("Decompressing assembly ({0} bytes uncompressed) using LZ4", decompressedLength); + logger?.Invoke(DebugLoggerLevel.Debug, "Decompressing assembly ({0} bytes uncompressed) using LZ4", decompressedLength); var outputStream = new MemoryStream(decompressedLength); diff --git a/src/Sentry.Android.AssemblyReader/DebugLogger.cs b/src/Sentry.Android.AssemblyReader/DebugLogger.cs index aff0db80ca..d1835c55fa 100644 --- a/src/Sentry.Android.AssemblyReader/DebugLogger.cs +++ b/src/Sentry.Android.AssemblyReader/DebugLogger.cs @@ -3,6 +3,7 @@ namespace Sentry.Android.AssemblyReader; /// /// Writes a log message for debugging. /// +/// The debug log level. /// The message string to write. /// Arguments for the formatted message string. -public delegate void DebugLogger(string message, params object?[] args); +public delegate void DebugLogger(DebugLoggerLevel level, string message, params object?[] args); diff --git a/src/Sentry.Android.AssemblyReader/DebugLoggerLevel.cs b/src/Sentry.Android.AssemblyReader/DebugLoggerLevel.cs new file mode 100644 index 0000000000..886bafdc57 --- /dev/null +++ b/src/Sentry.Android.AssemblyReader/DebugLoggerLevel.cs @@ -0,0 +1,32 @@ +namespace Sentry.Android.AssemblyReader; + +/// +/// Represents the level of debug logging. +/// +public enum DebugLoggerLevel : short +{ + /// + /// Debug level logging. + /// + Debug, + + /// + /// Information level logging. + /// + Info, + + /// + /// Warning level logging. + /// + Warning, + + /// + /// Error level logging. + /// + Error, + + /// + /// Fatal level logging. + /// + Fatal +} diff --git a/src/Sentry.Android.AssemblyReader/V1/AndroidAssemblyDirectoryReaderV1.cs b/src/Sentry.Android.AssemblyReader/V1/AndroidAssemblyDirectoryReaderV1.cs index 30314a5546..7b5e1c1a7e 100644 --- a/src/Sentry.Android.AssemblyReader/V1/AndroidAssemblyDirectoryReaderV1.cs +++ b/src/Sentry.Android.AssemblyReader/V1/AndroidAssemblyDirectoryReaderV1.cs @@ -18,11 +18,11 @@ public AndroidAssemblyDirectoryReaderV1(ZipArchive zip, IList supportedA var zipEntry = FindAssembly(name); if (zipEntry is null) { - Logger?.Invoke("Couldn't find assembly {0} in the APK", name); + Logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't find assembly {0} in the APK", name); return null; } - Logger?.Invoke("Resolved assembly {0} in the APK at {1}", name, zipEntry.FullName); + Logger?.Invoke(DebugLoggerLevel.Debug, "Resolved assembly {0} in the APK at {1}", name, zipEntry.FullName); // We need a seekable stream for the PEReader (or even to check whether the DLL is compressed), so make a copy. var memStream = zipEntry.Extract(); diff --git a/src/Sentry.Android.AssemblyReader/V1/AndroidAssemblyStoreReaderV1.cs b/src/Sentry.Android.AssemblyReader/V1/AndroidAssemblyStoreReaderV1.cs index 3073cc2095..60c947b23e 100644 --- a/src/Sentry.Android.AssemblyReader/V1/AndroidAssemblyStoreReaderV1.cs +++ b/src/Sentry.Android.AssemblyReader/V1/AndroidAssemblyStoreReaderV1.cs @@ -16,16 +16,16 @@ public AndroidAssemblyStoreReaderV1(ZipArchive zip, IList supportedAbis, var assembly = TryFindAssembly(name); if (assembly is null) { - Logger?.Invoke("Couldn't find assembly {0} in the APK AssemblyStore", name); + Logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't find assembly {0} in the APK AssemblyStore", name); return null; } - Logger?.Invoke("Resolved assembly {0} in the APK {1} AssemblyStore", name, assembly.Store.Arch); + Logger?.Invoke(DebugLoggerLevel.Debug, "Resolved assembly {0} in the APK {1} AssemblyStore", name, assembly.Store.Arch); var stream = assembly.GetImage(); if (stream is null) { - Logger?.Invoke("Couldn't access assembly {0} image stream", name); + Logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't access assembly {0} image stream", name); return null; } @@ -119,7 +119,7 @@ private void ProcessStores() assembly.Hash64 = he.Hash; if (assembly.RuntimeIndex != he.MappingIndex) { - _logger?.Invoke( + _logger?.Invoke(DebugLoggerLevel.Debug, $"assembly with hashes 0x{assembly.Hash32} and 0x{assembly.Hash64} has a different 32-bit runtime index ({assembly.RuntimeIndex}) than the 64-bit runtime index({he.MappingIndex})"); } @@ -127,18 +127,18 @@ private void ProcessStores() { if (string.IsNullOrEmpty(assembly.Name)) { - _logger?.Invoke( + _logger?.Invoke(DebugLoggerLevel.Debug, $"32-bit hash 0x{assembly.Hash32:x} did not match any assembly name in the manifest"); assembly.Name = me.Name; if (string.IsNullOrEmpty(assembly.Name)) { - _logger?.Invoke( + _logger?.Invoke(DebugLoggerLevel.Debug, $"64-bit hash 0x{assembly.Hash64:x} did not match any assembly name in the manifest"); } } else if (!string.Equals(assembly.Name, me.Name, StringComparison.Ordinal)) { - _logger?.Invoke( + _logger?.Invoke(DebugLoggerLevel.Debug, $"32-bit hash 0x{assembly.Hash32:x} maps to assembly name '{assembly.Name}', however 64-bit hash 0x{assembly.Hash64:x} for the same entry matches assembly name '{me.Name}'"); } } @@ -176,7 +176,7 @@ void ProcessIndex(List index, string bitness, { if (!Stores.TryGetValue(he.StoreId, out var storeList)) { - _logger?.Invoke($"store with id {he.StoreId} not part of the set"); + _logger?.Invoke(DebugLoggerLevel.Debug, $"store with id {he.StoreId} not part of the set"); continue; } @@ -184,7 +184,7 @@ void ProcessIndex(List index, string bitness, { if (he.LocalStoreIndex >= (uint)store.Assemblies.Count) { - _logger?.Invoke( + _logger?.Invoke(DebugLoggerLevel.Debug, $"{bitness}-bit index entry with hash 0x{he.Hash:x} has invalid store {store.StoreId} index {he.LocalStoreIndex} (maximum allowed is {store.Assemblies.Count})"); continue; } diff --git a/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyDirectoryReaderV2.cs b/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyDirectoryReaderV2.cs index 7c92c70a26..b250640d1f 100644 --- a/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyDirectoryReaderV2.cs +++ b/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyDirectoryReaderV2.cs @@ -12,7 +12,7 @@ public AndroidAssemblyDirectoryReaderV2(string apkPath, IList supportedA Logger = logger; foreach (var abi in supportedAbis) { - logger?.Invoke("Adding {0} to supported architectures for Directory Reader", abi); + logger?.Invoke(DebugLoggerLevel.Debug, "Adding {0} to supported architectures for Directory Reader", abi); SupportedArchitectures.Add(abi.AbiToDeviceArchitecture()); } _archiveAssemblyHelper = new ArchiveAssemblyHelper(apkPath, logger, supportedAbis); @@ -26,21 +26,21 @@ public AndroidAssemblyDirectoryReaderV2(string apkPath, IList supportedA var stream = File.OpenRead(name); return new PEReader(stream); } - Logger?.Invoke("File {0} does not exist in the APK", name); + Logger?.Invoke(DebugLoggerLevel.Debug, "File {0} does not exist in the APK", name); foreach (var arch in SupportedArchitectures) { if (_archiveAssemblyHelper.ReadEntry($"assemblies/{name}", arch) is not { } memStream) { - Logger?.Invoke("Couldn't find entry {0} in the APK for the {1} architecture", name, arch); + Logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't find entry {0} in the APK for the {1} architecture", name, arch); continue; } - Logger?.Invoke("Resolved assembly {0} in the APK", name); + Logger?.Invoke(DebugLoggerLevel.Debug, "Resolved assembly {0} in the APK", name); return ArchiveUtils.CreatePEReader(name, memStream, Logger); } - Logger?.Invoke("Couldn't find assembly {0} in the APK", name); + Logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't find assembly {0} in the APK", name); return null; } @@ -96,11 +96,11 @@ public ArchiveAssemblyHelper(string archivePath, DebugLogger? logger, IList $"Entry '{path}' does not contain the 'payload' section", _ => $"Unknown ELF payload section error for entry '{path}': {error}" }; - _logger?.Invoke(message); + _logger?.Invoke(DebugLoggerLevel.Debug, message); } else { - _logger?.Invoke($"Extracted content from ELF image '{path}'"); + _logger?.Invoke(DebugLoggerLevel.Debug, $"Extracted content from ELF image '{path}'"); } if (elfPayloadOffset == 0) @@ -142,14 +142,14 @@ public ArchiveAssemblyHelper(string archivePath, DebugLogger? logger, IList supportedAbis, D var (explorers, errorMessage) = AssemblyStoreExplorer.Open(inputFile, logger); if (explorers is null) { - logger?.Invoke("Unable to read store information for {0}: {1}", inputFile, errorMessage); + logger?.Invoke(DebugLoggerLevel.Debug, "Unable to read store information for {0}: {1}", inputFile, errorMessage); // Check for assembly stores in any device specific APKs foreach (var supportedAbi in supportedAbis) @@ -27,7 +27,7 @@ public static bool TryReadStore(string inputFile, IList supportedAbis, D var splitFilePath = inputFile.GetArchivePathForAbi(supportedAbi, logger); if (!File.Exists(splitFilePath)) { - logger?.Invoke("No split config detected at: '{0}'", splitFilePath); + logger?.Invoke(DebugLoggerLevel.Debug, "No split config detected at: '{0}'", splitFilePath); continue; } (explorers, errorMessage) = AssemblyStoreExplorer.Open(splitFilePath, logger); @@ -37,7 +37,7 @@ public static bool TryReadStore(string inputFile, IList supportedAbis, D } else { - logger?.Invoke("Unable to read store information for {0}: {1}", splitFilePath, errorMessage); + logger?.Invoke(DebugLoggerLevel.Debug, "Unable to read store information for {0}: {1}", splitFilePath, errorMessage); } } } @@ -62,7 +62,7 @@ public static bool TryReadStore(string inputFile, IList supportedAbis, D if (supportedExplorers.Count == 0) { - logger?.Invoke("Could not find V2 AssemblyStoreExplorer for the supported ABIs: {0}", string.Join(", ", supportedAbis)); + logger?.Invoke(DebugLoggerLevel.Debug, "Could not find V2 AssemblyStoreExplorer for the supported ABIs: {0}", string.Join(", ", supportedAbis)); reader = null; return false; } @@ -76,17 +76,17 @@ public static bool TryReadStore(string inputFile, IList supportedAbis, D var explorerAssembly = TryFindAssembly(name); if (explorerAssembly is null) { - _logger?.Invoke("Couldn't find assembly {0} in the APK AssemblyStore", name); + _logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't find assembly {0} in the APK AssemblyStore", name); return null; } var (explorer, storeItem) = explorerAssembly; - _logger?.Invoke("Resolved assembly {0} in the APK {1} AssemblyStore", name, storeItem.TargetArch); + _logger?.Invoke(DebugLoggerLevel.Debug, "Resolved assembly {0} in the APK {1} AssemblyStore", name, storeItem.TargetArch); var stream = explorer.ReadImageData(storeItem, false); if (stream is null) { - _logger?.Invoke("Couldn't access assembly {0} image stream", name); + _logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't access assembly {0} image stream", name); return null; } @@ -127,12 +127,12 @@ private bool FindBestAssembly(string name, out ExplorerStoreItem? explorerAssemb { if (explorer.AssembliesByName?.TryGetValue(name, out var assembly) is true) { - _logger?.Invoke("Found best assembly {0} in APK AssemblyStore for target arch {1}", name, explorer.TargetArch); + _logger?.Invoke(DebugLoggerLevel.Debug, "Found best assembly {0} in APK AssemblyStore for target arch {1}", name, explorer.TargetArch); explorerAssembly = new(explorer, assembly); return true; } } - _logger?.Invoke("No best assembly for {0} in APK AssemblyStore", name); + _logger?.Invoke(DebugLoggerLevel.Warning, "No best assembly for {0} in APK AssemblyStore", name); explorerAssembly = null; return false; } diff --git a/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs b/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs index 424109bcee..0ab9c04e2e 100644 --- a/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs +++ b/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs @@ -33,7 +33,7 @@ private AssemblyStoreExplorer(Stream storeStream, string path, DebugLogger? logg { foreach (var item in Assemblies) { - logger?.Invoke("Assembly {0} indexed from AssemblyStore {1}", item.Name, path); + logger?.Invoke(DebugLoggerLevel.Debug, "Assembly {0} indexed from AssemblyStore {1}", item.Name, path); dict.Add(item.Name, item); } } diff --git a/src/Sentry.Android.AssemblyReader/V2/StoreReaderV2.cs b/src/Sentry.Android.AssemblyReader/V2/StoreReaderV2.cs index 6a40e05bc0..97bac95694 100644 --- a/src/Sentry.Android.AssemblyReader/V2/StoreReaderV2.cs +++ b/src/Sentry.Android.AssemblyReader/V2/StoreReaderV2.cs @@ -106,7 +106,7 @@ protected override bool IsSupported() ELFPayloadError.NoPayloadSection => $"Store '{StorePath}' does not contain the 'payload' section", _ => $"Unknown ELF payload section error for store '{StorePath}': {error}" }; - Logger?.Invoke(message); + Logger?.Invoke(DebugLoggerLevel.Debug, message); // Was originally: // ``` // } else if (elfOffset >= 0) { @@ -122,14 +122,14 @@ protected override bool IsSupported() if (magic != Utils.AssemblyStoreMagic) { - Logger?.Invoke("Store '{0}' has invalid header magic number.", StorePath); + Logger?.Invoke(DebugLoggerLevel.Debug, "Store '{0}' has invalid header magic number.", StorePath); return false; } uint version = reader.ReadUInt32(); if (!supportedVersions.Contains(version)) { - Logger?.Invoke("Store '{0}' has unsupported version 0x{1:x}", StorePath, version); + Logger?.Invoke(DebugLoggerLevel.Debug, "Store '{0}' has unsupported version 0x{1:x}", StorePath, version); return false; } diff --git a/src/Sentry/Platforms/Android/AndroidHelpers.cs b/src/Sentry/Platforms/Android/AndroidHelpers.cs index c33d404e08..41fa2c8b1f 100644 --- a/src/Sentry/Platforms/Android/AndroidHelpers.cs +++ b/src/Sentry/Platforms/Android/AndroidHelpers.cs @@ -44,7 +44,7 @@ public static IList GetSupportedAbis() { var supportedAbis = GetSupportedAbis(); return AndroidAssemblyReaderFactory.Open(apkPath, supportedAbis, - logger: (message, args) => logger?.Log(SentryLevel.Debug, message, args: args)); + logger: (level, message, args) => logger?.Log((SentryLevel)level, message, args: args)); } catch (Exception ex) { diff --git a/test/Sentry.Android.AssemblyReader.Tests/AndroidAssemblyReaderTests.cs b/test/Sentry.Android.AssemblyReader.Tests/AndroidAssemblyReaderTests.cs index 4a9985f827..24344f2edd 100644 --- a/test/Sentry.Android.AssemblyReader.Tests/AndroidAssemblyReaderTests.cs +++ b/test/Sentry.Android.AssemblyReader.Tests/AndroidAssemblyReaderTests.cs @@ -39,7 +39,7 @@ private IAndroidAssemblyReader GetSut(bool isAot, bool isAssemblyStore, bool isC // Note: This needs to match the RID used when publishing the test APK string[] supportedAbis = { "x86_64" }; return AndroidAssemblyReaderFactory.Open(apkPath, supportedAbis, - logger: (message, args) => _output.WriteLine(message, args)); + logger: (_, message, args) => _output.WriteLine(message, args)); #endif } diff --git a/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index 42c0fac236..67bbca78b3 100644 --- a/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt +++ b/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -4,7 +4,15 @@ { public static Sentry.Android.AssemblyReader.IAndroidAssemblyReader Open(string apkPath, System.Collections.Generic.IList supportedAbis, Sentry.Android.AssemblyReader.DebugLogger? logger = null) { } } - public delegate void DebugLogger(string message, params object?[] args); + public delegate void DebugLogger(Sentry.Android.AssemblyReader.DebugLoggerLevel level, string message, params object?[] args); + public enum DebugLoggerLevel : short + { + Debug = 0, + Info = 1, + Warning = 2, + Error = 3, + Fatal = 4, + } public interface IAndroidAssemblyReader : System.IDisposable { System.Reflection.PortableExecutable.PEReader? TryReadAssembly(string name); diff --git a/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt b/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt index 42c0fac236..67bbca78b3 100644 --- a/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt +++ b/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt @@ -4,7 +4,15 @@ { public static Sentry.Android.AssemblyReader.IAndroidAssemblyReader Open(string apkPath, System.Collections.Generic.IList supportedAbis, Sentry.Android.AssemblyReader.DebugLogger? logger = null) { } } - public delegate void DebugLogger(string message, params object?[] args); + public delegate void DebugLogger(Sentry.Android.AssemblyReader.DebugLoggerLevel level, string message, params object?[] args); + public enum DebugLoggerLevel : short + { + Debug = 0, + Info = 1, + Warning = 2, + Error = 3, + Fatal = 4, + } public interface IAndroidAssemblyReader : System.IDisposable { System.Reflection.PortableExecutable.PEReader? TryReadAssembly(string name);