NLog.Targets.Syslog
NLog.Targets.Syslog copied to clipboard
Fails to connect TCP socket on Android in Maui 8 (.Net 8) stack
Bug description Remote logging config is slow and eventually fails silently. (~10-15 sec) On Android - Maui 8.
Expected behavior Setting config enables remote logging, or throws @ config if failure.
Actual behavior
Setting config for a remote syslog results in an internal error resulting in no logs sent. The internal nLog.Syslog.Targets
code is mis-identifying Android OS as OSX.
Internal logs from nLog:
[DOTNET] 2024-09-04 12:51:10.7680 Warn [Syslog] SendAsync failed Exception: System.ApplicationException: Socket option syscall error value: '-1'
[DOTNET] at NLog.Targets.Syslog.MessageSend.Interop.ThrowOnError(Int32 error)
[DOTNET] at NLog.Targets.Syslog.MessageSend.Interop.SetSockOptSysCall(Socket socket, SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue)
>>>[DOTNET] at NLog.Targets.Syslog.MessageSend.SocketInitializationForOsx.ApplyKeepAliveValues(Socket socket, KeepAliveConfig keepAliveConfig) <<<<<<
[DOTNET] at NLog.Targets.Syslog.MessageSend.SocketInitialization.SetKeepAlive(Socket socket, KeepAliveConfig keepAliveConfig)
[DOTNET] at NLog.Targets.Syslog.MessageSend.Tcp.Init(IPEndPoint ipEndPoint)
[DOTNET] at NLog.Targets.Syslog.MessageSend.MessageTransmitter.<PrepareForSendAsync>b__19_0(Task _)
[DOTNET] at NLog.Targets.Syslog.Extensions.TaskExtensions.<>c__DisplayClass1_0`1[[System.Threading.Tasks.Task, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].<Then>b__0(Task t, Object c)
[DOTNET] at System.Threading.Tasks.ContinuationResultTaskFromTask`1[[System.Threading.Tasks.Task`1[[System.Threading.Tasks.Task, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].InnerInvoke()
[DOTNET] at System.Threading.Tasks.Task.<>c.<.cctor>b__281_0(Object obj)
[DOTNET] at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
[DOTNET] --- End of stack trace from previous location ---
[DOTNET] at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
[DOTNET] at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
This is the section of code responsible for identifying the OS @ runtime: https://github.com/luigiberrettini/NLog.Targets.Syslog/blob/8187976cd29cb1baef5447163b1b305681576fad/src/NLog.Targets.Syslog/MessageSend/SocketInitialization.cs#L12C9-L19C10
public static SocketInitialization ForCurrentOs()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return new SocketInitializationForWindows();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return new SocketInitializationForLinux();
return new SocketInitializationForOsx();
}
From debugging my app-code, Android is returning as "UNIX" from: Environment.OSVersion.Platform
, resulting in the above code defaulting to OSx as the OS, which explains why my Maui app does still log from the iOS package.
System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier;
does return a value that could correctly ID Android: "android-arm64", but does not match existing internal conventions for identifying the OS @ runtime.
To reproduce Simply try to configure a syslog target on Android (Maui 8).
Additional context
- NLog version: 5.3.2
- NLog.Targets.Syslog version 7.0.0
- NLog configuration used Inline c#
DeviceId = deviceIdentifier;
var machineName = variable1 ?? "pre-login-shared";
var programName = user ?? "[unknown]";
var config = new NLog.Config.LoggingConfiguration();
var papertrailTarget = new NLog.Targets.Syslog.SyslogTarget();
config.AddTarget("syslog", papertrailTarget);
papertrailTarget.MessageCreation.Facility = Facility.Local7;
papertrailTarget.MessageCreation.Rfc5424.Hostname = machineName;
papertrailTarget.MessageCreation.Rfc5424.AppName = programName;
papertrailTarget.MessageSend.Protocol = ProtocolType.Tcp;
papertrailTarget.MessageSend.Tcp.Server = "[redacted]";
papertrailTarget.MessageSend.Tcp.Port = [redacted];
papertrailTarget.MessageSend.Tcp.Tls.Enabled = true;
// Only allow debug logging in debug mode, so we don't open a security hole by accidentally
// logging sensitive debug information
#if DEBUG
var rule = new NLog.Config.LoggingRule("*", NLog.LogLevel.Debug, papertrailTarget);
#else
var rule = new NLog.Config.LoggingRule("*", NLog.LogLevel.Info, papertrailTarget);
#endif
config.LoggingRules.Add(rule);
NLog.LogManager.Configuration = config;
- Any other context about the problem
The above inline-config has worked for both Android and iOS for years in Xamarin.Forms, only while porting our stack to Maui/.Net 8 did we see this issue. I expect that with the older mono-runtime that our Xamarin stack used, Android was identifying as Linux, and so worked as expected? I have not yet confirmed that. The Xamarin code where this was compiled previously was .NetStandard 2.1, and the new code base is all .Net8, but I did some testing to revert the logging project back to .NetStandard 2.1 without a change in the outcome.
The only idea I have ATM is to allow some sort of optional injection for identifying the OS instead of relying on only .Net 8 Core API's that don't know about mobile os's, but fallback to the current impl if the injection site is left null. Allowing some sort of optional injection would allow for application-code to map from mobile OS to the correct equivalent Windows/Linux/OSx desktop variant, but not disrupt current server/desktop code?
This is Maui's list of OS's: https://github.com/dotnet/maui/blob/5c0e6d64a11e3912c94c5d2591c44e986909fa23/src/Essentials/src/Types/DevicePlatform.shared.cs#L65