Skip to content
This repository has been archived by the owner on Feb 12, 2025. It is now read-only.

Fails to connect TCP socket on Android in Maui 8 (.Net 8) stack #315

Open
jasells opened this issue Sep 4, 2024 · 1 comment · May be fixed by #318
Open

Fails to connect TCP socket on Android in Maui 8 (.Net 8) stack #315

jasells opened this issue Sep 4, 2024 · 1 comment · May be fixed by #318
Assignees
Labels

Comments

@jasells
Copy link

jasells commented Sep 4, 2024

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

@jasells
Copy link
Author

jasells commented Feb 11, 2025

Ok, finally back to this. Disappointed there has been 0 activity here...

This change looks like it un-breaks setting up a TCP socket on Xamarin.Android/Maui.

public static SocketInitialization ForCurrentOs()
        {
            // Android/Maui returns " Linux 4.14.276-g6ef255005cea-ab9062920 #1 SMP PREEMPT Wed Sep 14 08:05:09 UTC 2022" here. On the devices I tested on.
            //  we'll use this below.
            string rt = RuntimeInformation.OSDescription;

            bool isMac = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);

            Debug.WriteLine($"=====  NLog.Targets.Syslog detected OS: {rt}");
            Debug.WriteLine($"isMac: {isMac}");

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                return new SocketInitializationForWindows();

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
                ||
                rt.ToLower().Contains("linux"))
            {
                return new SocketInitializationForLinux();
            }

            return new SocketInitializationForOsx();
        }

This isn't robust... since it still defaults to OSX if no specific detection made prior, and in my testing, iOS returns rt = "Darwin x.y.z ...." from OSDescription, so could proactively detect Apple-family OS's ...

It really only works for iOS because Apple's config is last/default, currently, so doesn't really need to change, I suppose.

A more complete/robust solution to officially support Maui would be to add an injection site to override this method impl, and then inject it from a new wrapper lib (NLog.Targets.Syslog.Maui, for example) that has Maui dependencies and can get specific Maui-supported platform info and correctly detect the OS, which Maui already has API's to do reliably.... And provides Maui-friendly initializaiton. 🤔

@luigiberrettini @snakefoot
Is there any interest to the community to add official Maui support?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants