Comments (14)
Hi @pierre-galaup , just following up on this.
I added Sentry.NLog
to the sample you provided:
dotnet add package Sentry.NLog -v 4.1.1
Then I hooked this up with Diagnostic logging enabled (that causes Sentry to send it's diagnostic logs to the NLog logger... basically they end up in LogCat):
LogManager.Setup().LoadConfigurationFromAssemblyResource(typeof(App).Assembly);
LogManager.Configuration.AddSentry(o =>
{
o.MinimumBreadcrumbLevel = NLog.LogLevel.Debug;
o.MinimumEventLevel = NLog.LogLevel.Error;
});
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseSentry(options =>
{
options.DiagnosticLevel = SentryLevel.Debug;
With that wired up, I get a bit more information in LogCat even if the debugger won't stay attached to the process that's running in Android:
2024-02-15 14:50:56.008 9130-9159 DOTNET com.companyname.sentrydebughelper I Debug: Android: Serializing object: { "reportType": "SendLogs" }
2024-02-15 14:50:56.010 9130-9209 DOTNET com.companyname.sentrydebughelper I Warning: Failed to serialize envelope item
System.InvalidOperationException: Arg_InvalidOperationException
2024-02-15 14:50:56.010 9130-9209 DOTNET com.companyname.sentrydebughelper I at System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1[[System.Int64, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].GetStatus(Int16 )
at Microsoft.Win32.SafeHandles.SafeFileHandle.ThreadPoolValueTaskSource.GetStatus(Int16 )
at System.IO.Strategies.BufferedFileStreamStrategy.ReadAsync(Byte[] , Int32 , Int32 , CancellationToken )
2024-02-15 14:50:56.010 9130-9209 DOTNET com.companyname.sentrydebughelper I at System.IO.FileStream.ReadAsync(Byte[] , Int32 , Int32 , CancellationToken )
at Sentry.Internal.PartialStream.ReadAsync(Byte[] , Int32 , Int32 , CancellationToken )
2024-02-15 14:50:56.010 9130-9209 DOTNET com.companyname.sentrydebughelper I at System.IO.Stream.<CopyToAsync>g__Core|27_0(Stream , Stream , Int32 , CancellationToken )
at Sentry.Protocol.Envelopes.EnvelopeItem.BufferPayloadAsync(IDiagnosticLogger , CancellationToken )
at Sentry.Protocol.Envelopes.EnvelopeItem.SerializeAsync(Stream , IDiagnosticLogger , CancellationToken )
2024-02-15 14:50:56.010 9130-9209 DOTNET com.companyname.sentrydebughelper I at Sentry.Protocol.Envelopes.Envelope.SerializeAsync(Stream , IDiagnosticLogger , ISystemClock , CancellationToken )
TBH that's not helping a lot. The last thing that happens in the sentry code before the error occurs is here:
sentry-dotnet/src/Sentry/Internal/PartialStream.cs
Lines 63 to 64 in e75d537
Then the FileStream.ReadAsync method throws:
System.InvalidOperationException: Arg_InvalidOperationException
at System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1[[System.Int64, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].GetStatus(Int16 )
at Microsoft.Win32.SafeHandles.SafeFileHandle.ThreadPoolValueTaskSource.GetStatus(Int16 )
at System.IO.Strategies.BufferedFileStreamStrategy.ReadAsync(Byte[] , Int32 , Int32 , CancellationToken )
at System.IO.FileStream.ReadAsync(Byte[] , Int32 , Int32 , CancellationToken )
Following the rabbit hole there goes: FileStream > BufferedFileStreamStrategy > ThreadPoolValueTaskSource > ManualResetValueTaskSourceCore.
I have no idea what's causing that though.
from sentry-dotnet.
I think it's worth opening a ticket on https://github.com/xamarin/xamarin-android about this
from sentry-dotnet.
Hey, sorry to see you run into issues.
Chasing up a bit of what might be going on here it looks to me like the SDK chokes on reading the stream here
Afaik the stream originates from here
How consistently do you encounter this? Could you provide a repro for us to take a deeper look?
from sentry-dotnet.
Hello,
Thank you for your reply.
Unfortunately I don't have an easy repo to provide. I have the impression that it only happens on Android (at least we've never had a problem on iOS) and only in RELEASE. But, I rarely keep logs of several days in DEBUG...
I can give you some more code information, like my Sentry initialization and how I send my logs (which come from NLog).
As I said, it's random and some ZIPs are sent correctly, and others not, in the same envelope.
I'm sure that the files exist on the phone because I also send a file listing the files in the directory and they're in that file.
My sentry options:
.UseSentry(options =>
{
// The DSN is the only required setting.
options.Dsn = Configuration.SentryDsn;
options.Debug = false;
#if IOS
options.iOS.EnableAppHangTracking = false;
#endif
#if ANDROID
options.Android.AnrEnabled = false;
#endif
options.TracesSampleRate = 1.0;
options.IncludeTextInBreadcrumbs = true;
options.IncludeTitleInBreadcrumbs = true;
options.IncludeBackgroundingStateInBreadcrumbs = true;
options.AutoSessionTracking = true;
options.IsGlobalModeEnabled = true;
options.CacheDirectoryPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
options.Environment = Configuration.Environment;
options.SendDefaultPii = false;
})
The code used to send these files:
var directory = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "logs"));
var getFiles = directory.GetFiles();
var attachments = new List<string>();
foreach (var logFile in getFiles)
{
var zipFile = logFile.FullName.Replace($"{logFile.Extension}", ".zip");
attachments.Add(zipFile);
using var zipArchive = new ZipOutputStream(File.Create(zipFile));
zipArchive.SetLevel(9);
var buffer = new byte[102400];
var entry = new ZipEntry(logFile.Name)
{
DateTime = DateTime.Now
};
zipArchive.PutNextEntry(entry);
using var fs = new FileStream(logFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
int sourceBytes;
do
{
sourceBytes = fs.Read(buffer, 0, buffer.Length);
zipArchive.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
zipArchive.Finish();
zipArchive.Close();
}
SentrySdk.CaptureMessage("ErrorReport", scope =>
{
scope.ClearAttachments();
if (attachments != null)
{
foreach (var attachment in attachments)
{
scope.AddAttachment(attachment, AttachmentType.Default, "application/zip");
}
}
scope.SetTag("XXX", XXX);
scope.SetTag("XXX", XXX);
scope.SetTag("XXX", XXX);
scope.SetTag("XXX", XXX);
scope.SetFingerprint("XXXXX");
}, SentryLevel.Debug);
My RELEASE CSPROJ:
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<UseInterpreter>false</UseInterpreter>
<MtouchDebug>False</MtouchDebug>
<AndroidPackageFormat>aab</AndroidPackageFormat>
<AndroidDexTool>d8</AndroidDexTool>
<AndroidLinkTool/>
<AndroidUseAapt2>true</AndroidUseAapt2>
<AndroidEnableMultiDex>false</AndroidEnableMultiDex>
<AndroidStoreUncompressedFileExtensions>.mp3</AndroidStoreUncompressedFileExtensions>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
<Optimize>true</Optimize>
<BundleAssemblies>false</BundleAssemblies>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
<MtouchLink>SdkOnly</MtouchLink>
<MtouchEnableSGenConc>true</MtouchEnableSGenConc>
<DefineConstants/>
<CreatePackage>false</CreatePackage>
<MtouchUseLlvm>true</MtouchUseLlvm>
<EnableCodeSigning>true</EnableCodeSigning>
<MtouchArch>ARM64</MtouchArch>
<RunAOTCompilation>true</RunAOTCompilation>
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
<EnableLLVM>true</EnableLLVM>
<AndroidStripILAfterAOT>true</AndroidStripILAfterAOT>
<CopyDebugSymbolFilesFromPackages>true</CopyDebugSymbolFilesFromPackages>
<CopyDocumentationFilesFromPackages>true</CopyDocumentationFilesFromPackages>
<!-- Sends symbols to Sentry, enabling symbolication of stack traces. -->
<SentryUploadSymbols>true</SentryUploadSymbols>
<!-- Sends sources to Sentry, enabling display of source context. -->
<SentryUploadSources>false</SentryUploadSources>
<!-- If you are targeting Android, sends proguard mapping file to Sentry. -->
<SentryUploadAndroidProguardMapping>true</SentryUploadAndroidProguardMapping>
</PropertyGroup>
from sentry-dotnet.
Could it be there's some other part of the app that does file rotation? Deleting the old one while Sentry is trying to read from it?
It's odd, System.InvalidOperationException: Arg_InvalidOperationException
doesn't give us much and the error is just coming from .NET trying to read from the stream.
Unrelated to this issue but worth noting Sentry gzip's the payload already so no need in gzip the logs yourself. You could attach them as-is.
from sentry-dotnet.
Hello,
I tried to make a copy of each file before zipping it:
if (logFile.Extension == ".csv") // Copy the log
{
logFileToCopy = logFileName = logFileName.Replace(".csv", ".Copy.csv");
using var inputFile = new FileStream(logFile.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var outputFile = new FileStream(logFileName, FileMode.Create);
var buf = new byte[102400];
int bytes;
while ((bytes = inputFile.Read(buf, 0, buf.Length)) > 0)
{
outputFile.Write(buf, 0, bytes);
}
}
But it still happens. I don't think it's the NLOG rotation... My NLog.config
:
<target xsi:type="File" name="logfile"
fileName="${specialfolder:folder=LocalApplicationData}/logs/App.${shortdate}.csv"
keepFileOpen="true"
openFileCacheTimeout="30"
maxArchiveFiles="7"
maxArchiveDays="7"
archiveEvery="Day"
archiveAboveSize="8388608"
archiveFileName="${specialfolder:folder=LocalApplicationData}/logs/App.Archive.{#####}.csv"
archiveNumbering="Date"
archiveDateFormat="yyyy-MM-dd"
encoding="utf-8">
I've also tried sending SENTRY a byte[] directly:
foreach (var attachment in attachments)
{
using var fs = new FileStream(attachment, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
sentryAttachments.Add(Path.GetFileName(attachment), ReadFully(fs));
}
return sentryAttachments;
static byte[] ReadFully(Stream input)
{
var buffer = new byte[102400];
using var ms = new MemoryStream();
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
But that didn't work either.
I've run out of test ideas of my own. And without repro I know that on your side it's complicated.
I'll try to see if I can make a repro that reproduces it, just extracting the parts that make up the log and sending it to SENTRY.
from sentry-dotnet.
With that last snippet it seems like you're passing the bytes straight to the attachment. So Sentry shouldn't be competing with the file with any other thread/lib/etc.
So if this happens even in this case, it's possible we have a bug somewhere.
Is the stack trace still coming through BufferPayloadAsync
?
from sentry-dotnet.
Hello,
It's the same error.
The phone of one of my testers has the bug in RELEASE, so I can easily test with it if needed (unfortunately I can't DEBUG on it).
I also tried sending the CSV file directly, without zipping it, and it didn't send either.
I tested something:
The same logs are sent to SENTRY and by mail (with MAUI ESSENTIALS).
With SENTRY I don't receive all the logs.
By e-mail I receive and can open all the log files.
So, in fact, I think the problem is with Sentry.
from sentry-dotnet.
The same logs are sent to SENTRY and by mail (with MAUI ESSENTIALS).
So here there could be a race condition? Is it the same Stream object sent on both?
If you disable the email feature, is Sentry able to send it through?
from sentry-dotnet.
It was just a test I did once to see if the files were corrupted or not.
I don't send the files at the same time to avoid any problems.
I send the e-mail first and when I receive it I load the same files sent by e-mail in byte[] and send them by Sentry. And that's when some of them are missing, whereas by e-mail I have them all. And I get the same error stacktrace.
from sentry-dotnet.
It was just a test I did once to see if the files were corrupted or not.
I don't send the files at the same time to avoid any problems. I send the e-mail first and when I receive it I load the same files sent by e-mail in byte[] and send them by Sentry. And that's when some of them are missing, whereas by e-mail I have them all. And I get the same error stacktrace.
Do you know their size? Sentry has limits in place. But afaik attachment is like 10Mb
from sentry-dotnet.
Hello,
The log file size maximum is 2/3 Mb and most of the time < 1Mb.
I think I've found the problem. It comes from the <EnableLLVM>true</EnableLLVM>
compilation flag.
If I remove it, the logs are sent, including the old ones (the ones that weren't sent before).
I provide a quick sample that reproduces my problem in a "fast" version (log rotation 1 minute and it logs a lot).
If you compile in DEBUG mode, no problem. If you compile in RELEASE with EnableLLVM
set to TRUE, the logs almost never arrive (the compilation is very long, just so you know). If you compile in RELEASE with EnableLLVM
set to FALSE, no problem.
But I don't know why...
The EnableLLVM
flag is essential for us because it improves overall application performance.
--
For the SAMPLE project, there are 3 buttons, 1 to send by e-mail (you need to define the target address in the code), 1 to send to SENTRY giving the FILENAME (you need to define the DSN) and 1 to send to SENTRY with one byte[] per file (you need to define the DSN).
Wait several minutes before sending the logs (several files are created).
A files.zip file is also sent, containing all current logs (which should be on SENTRY).
You can see in the e-mail that all the files are there, but not in SENTRY.
The EnableLLVM
is in the csproj
, I've put a TODO next to it.
from sentry-dotnet.
Hi @pierre-galaup,
Thanks for sending through the sample. I can reproduce the problem on my own machine... however it's extremely challenging to debug.
When I run the app in Debug mode, after about 5 or 10 seconds I'm getting an error:
Failed to establish connection to debugger agent
Is that something you've bumped into before? The only reference I found googling for this is here, and that didn't help.
Also, are you using Windows or macOS for development?
from sentry-dotnet.
Hello @jamescrosswell,
I use a WINDOWS and MAC environment. And always with Rider.
I'm using a Pixel 4A as a target.
To make this SAMPLE I used my WINDOWS.
Maybe by lowering the number of DEBUGs (await Task.Delay(10); => await Task.Delay(100); or more), it will be easier to DEBUG? But will it always reproduce the problem?
Indeed it's very complicated to DEBUG with this FLAG activated, I use a lot of logging with ADB to help me. But clearly debuging like this is very complex.
I don't have any other solution, I usually don't DEBUG with the EnableLLVM flag set to TRUE!
from sentry-dotnet.
Related Issues (20)
- Hubs & Scopes Refactoring
- Failed to send envelopes persist on disk
- SentryHttpClientFactory option ignored? HOT 1
- `Debug` and `DiagnosticLogger` options behavior HOT 9
- Crons Hangfire integration - find job names automatically HOT 1
- Scopes not being applied to Spans when using ASP.NET Core with OTel
- Investigate using custom builds for AOT compiled or trimmed apps
- Check DebugStackTrace conditional execution/suppressions HOT 5
- Updated SDK gives error with symbol upload on Windows
- Queries in Sentry show banner"could not find query source" on latest SDK version
- Implicit OpenTelemetry initialization
- Enable Ben.Demystifier for AOT apps HOT 3
- Unable to build a MAUI iOS app using a self-hosted Azure DevOps build agent HOT 19
- Sentry.MAUI crashing when launching HOT 26
- Just migrated my UWP app to Sentry from AppCenter but the release build is crashing on startup. Debug build runs fine HOT 32
- ASP.NET .NET Framework Website (web.config) project with Sentry fails to builds on Azure build agent HOT 6
- WinUI: Native (test) crashes aren't reported HOT 5
- Prepare Metrics for GA
- Metrics Rate Limits HOT 1
- UWP: "In foreground" context warning + not working HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sentry-dotnet.