Open am11 opened 4 years ago
Is anyone parsing these today (as opposed to displaying/logging them)? If there's hand rolled parsers out there, do we have to take care about extending the strings? Akin to the user-agent mess in browsers.
I assume "not many" and "it's an acceptable change"
cc @richlander
Is anyone parsing these today (as opposed to displaying/logging them)?
For instance, dotnet-sdk parses that information here: https://github.com/dotnet/sdk/blob/3595e2a/src/Cli/Microsoft.DotNet.Cli.Utils/RuntimeEnvironment.cs#L77. It will continue to work as is. For Windows and macOS, it uses Environment.OSVersion. With the proposed extension, we can update the SDK to parse out this information in a platform agnostic manner.
Right, but one could imagine someone else parsing in such a way that extending the string breaks them. I think that's probably OK just pointing it out. I think it's unfortunate that we're in a position of returning a string from an API that is in a non standard format and gets parsed by user code. cc @eerhardt in case he knows of other folks parsing it.
Ah right. I was thinking if someone is using .Contains("Linux")
or .IndexOf(minimumLinuxKernelVersion)
etc. with OSDescription
API, this change will not break them as the first part of description has been kept intact. If they were matching the verbatim string, OSDescription == "Linux 4.15.0-106-generic #107-Ubuntu SMP Thu Jun 4 11:27:52 UTC 2020"
, that will break but such usage pattern is highly unlikely.
As for the proposed usage of this change; if we add the trailing comma to the last component, it would be a one-liner to extract the individual components; Platform, Version and ID using C#'s slicing feature without extra checks, e.g. for SDK's use-case:
using static System.Runtime.InteropServices.RuntimeInformation;
...
var platformName = OSDescription.Contains("Platform: ")
? OSDescription[(OSDescription.IndexOf("Platform: ") + "Platform: ".Length)..OSDescription.IndexOf(",", OSDescription.IndexOf("Platform: "))]
: null;
var version = OSDescription.Contains("Version: ")
? OSDescription[(OSDescription.IndexOf("Version: ") + "Version: ".Length)..OSDescription.IndexOf(",", OSDescription.IndexOf("Version: "))]
: null;
var distroName = OSDescription.Contains("ID: ")
? OSDescription[(OSDescription.IndexOf("ID: ") + "ID: ".Length)..OSDescription.IndexOf(",", OSDescription.IndexOf("ID: "))]
: null;
var suitablePlatformName = distroName ?? platformName;
Console.WriteLine("Platform: {0}, Version: {1}", suitablePlatformName, version);
(notice the trailing commas in the strings below)
Input: "Linux 4.15.0-106-generic #107-Ubuntu SMP Thu Jun 4 11:27:52 UTC 2020. Platform: Linux, Version: 18.04, ID: ubuntu,"
Result: Platform: ubuntu, Version: 18.04
Input: "Darwin 18.7.0 Darwin Kernel Version 18.7.0: Mon Feb 10 21:08:05 PST 2020; root:xnu-4903.278.28~1/RELEASE_X86_64. Platform: OSX, Version: 10.14, ID: Mac OS X,"
Result: Platform: Mac OS X, Version: 10.14
Input: "Microsoft Windows 10.0.19635. Platform: Windows, Version: 10.0.19635,"
Result: Platform: Windows, Version: 10.0.19635
@eerhardt, @danmosemsft, any remarks on the overall idea?
I have prototyped it for the supported platforms: https://github.com/dotnet/runtime/compare/master...am11:feature/more-info-in-OSDescription, each one has different way of retrieving information from system environment. The overall OSDescription output has additional distro-like information for consumers to display or parse out.
In the worse-case scenario Platform: <value>,
part will always be available on all platforms and rest of the parts (Version:
and ID:
) may or may not be available during the run time; even on the system which provides it under normal circumstances. i.e. someone, for example, removes /etc/os-release
file on a Linux-based distro, and runs an app which calls OSDescription, that will only exclude Version and ID parts from the output.
I'd like to get members of @dotnet/fxdc opinions on this proposal. Technically this isn't a change in the API, but it is a change in the data returned from an API.
If our goal is to make this information parseable - would it be better to introduce explicit APIs for this information? Instead of putting the information into a string and then saying "this is how you parse the string".
I'm in favor of improving this information. I've noticed multiple times that it isn't quite what I wanted.
I don't want to make this more of a project than it needs to be, but I'd really like a persisted spec on this topic. In short, I'd like it describe the following:
I'm happy to work directly with you on this @am11. I'll be your PM!
That said, we need to act fast. I'm also one of the people wanting to starting pressing on the breaks for 5.0. It's almost time to lock in the release and claim victory. If this ends up being a 6.0 change, we shouldn't worry.
Thank you @richlander. I am willing to work on this with you. Surfacing the useful bits of system information in some form (new API or modifying the output of OSDescription) in 5.0 time-frame would be the best case scenario; as many new OS are being supported with this release.
My primary interest was to make SDK code more platform agnostic for .NET 5 onwards. However, I understand that it alone does not warrant such instrumentation in the runtime's public API. On the other hand, as you also noticed, the existing information provided by OSDescription is something which is not quite useful for many consumer use-cases.
The information that is typically available.
For demonstration, if we represent all this heterogeneous information as separate APIs, it would look something like this:
namespace System.Runtime.InteropServices
{
public static partial class RuntimeInformation
{
// the name which is used by IsOSPlatform(string) API to compare the parameter value (not exposed anywhere)
// e.g. Windows, Browser, or value of PAL_UNIX_NAME (FreeBSD, illumos, Linux, OSX, Solaris)
public static readonly string PlatformName; // build-time constant; never null
// Linux and illumos specific
// e.g. Alpine, Android, Gentoo, Ubuntu, SmartOS, OpenIndiana
public static readonly string? DistroId; // null on all platforms other than Linux and illumos derived ones
// Friendly version, which is distro version in case of Linux and illumos, and OS friendly version in case of macOS
public static readonly Version? ProductVersion; // null on Browser (webassembly)
// Friendly name per version. available on macOS and some Linux distros, such as Ubuntu and Android
// e.g. Mojave, Bionic, Lollipop
public static readonly string? ProductVersionFriendlyName; // null on majority of platforms
// Windows specific
public static readonly string? ServicePack; // null on all non-Windows platforms
}
}
This information can be reflected in OSDescription (in separate lines or key-values as proposed above), if additional API surface is not an option.
How to handle containers
DistroId
will be set to the corresponding Linux container's OS name. On other non-docker container-like scenarios (lxc containers, FreeBSD jails and Solaris/illumos zones), either DistroId (in case of lxc and zones) or PlatformName
(in case of FreeBSD) will provide name of the guest OS. Moreover, ProductVersion
will be (friendly) version of guest OS.
Want to DM me on twitter and then we can figure out the best way to collaborate? Me: https://twitter.com/runfaster2000
One thought I had was to create separate GetXXXInformation()
APIs, which would be OS specific. That way we wouldn't have to try to generalize the information and try to make it match across operating systems.
For example, we could have:
namespace System.Runtime.InteropServices
{
public static class RuntimeInformation
{
public static WindowsInformation GetWindowsInformation() {}
public static LinuxInformation GetLinuxInformation() {}
public static OSXInformation GetOSXInformation() {}
....
}
}
And then could design the WindowsInformation
, LinuxInformation
, OSXInformation
types independently as makes sense for that OS. And if you called GetLinuxInformation()
on Windows, or OSX (or any OS platform where IsOSPlatform(OSPlatform.Linux)
returned false
) it would throw a PlatformNotSupportedException
.
This way we don't have to come up with answers to "What should DistroId or ProductVersionFriendlyName mean/do on Windows?" or "What should SerivcePack mean on Ubuntu?". Instead, each OS platform can make available the information that makes sense for that platform. And all the other platforms' information simply throws PNSE.
"What should DistroId or ProductVersionFriendlyName mean/do on Windows?" or "What should SerivcePack mean on Ubuntu?"
These are indeed confusing. Perhaps, we can try to explore neutral names and otherwise throw PNSE from irrelevant properties, e.g., from ServicePack on non-Windows? This way we will not need a new public type for each supported platform.
If the purpose (per top post) is analytics and logging, then maybe it does need to be too strongly typed/fine grained. (After all the SDK today just logs OSDescription wholesale)
After all the SDK today just logs OSDescription wholesale
That's not all it does. It also does:
/etc/os-release
. For FreeBSD it parses RuntimeInformation.OSDescription to get this value./etc/os-release
(i.e. Distro name).Some libraries tests also detect libc flavor. If it is considered as a useful bit of information about platform, perhaps an API can revel it as an enum:
namespace System.Runtime.InteropServices
{
public static class RuntimeInformation
{
public static LibCFlavor LibC { get; }
}
public enum LibCFlavor
{
Bionic, // Android
Bsd, // macOS, FreeBSD
Emscripten, // WASM
Gnu, // GNU Linux distros
MSCrt, // Windows
Muscle, // Alpine Linux, Void Linux
Posix, // Oracle Solaris, illumos and others
}
}
Just to note that System.Runtime.InteropServices.RuntimeInformation.OSDescription
returns the same string:
Microsoft Windows 6.3.9600
for both Windows 8.1 and Windows Server 2012 R2.
Similarly need a way to distinguish between Win 8 and Win 2012 (both 6.2.9200) and so on.
Based on the discussion thread #37831, this proposal is to extend the output of
RuntimeInformation.OSDescription
string and include more information about the current platform.The purpose is to let consumer obtained a more identifiable information about the platform from an existing
OSDescription
API in a consistent manner, for analytics and logging like scenarios.For example, dotnet-sdk uses such information for
dotnet --info
and telemetry (src: https://github.com/dotnet/sdk/blob/3595e2a/src/Cli/Microsoft.DotNet.Cli.Utils/RuntimeEnvironment.cs). Most of that code is also replicated in a test utility method in runtime repo: https://github.com/dotnet/runtime/blob/579d8831e15fcff60a821d6fee554b7f26bba96f/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs#L155RuntimeInformation.OSDescription
FreeBSD 11.0-RELEASE-p1 FreeBSD 11.0-RELEASE-p1 #0 r306420: Thu Sep 29 01:43:23 UTC 2016 root@releng2.nyi.freebsd.org:/usr/obj/usr/src/sys/GENERIC
Linux 4.19.104-gentoo #1 SMP Wed Feb 19 06:37:35 UTC 2020
Darwin 18.7.0 Darwin Kernel Version 18.7.0: Mon Feb 10 21:08:05 PST 2020; root:xnu-4903.278.28~1/RELEASE_X86_64
SunOS 5.11 joyent_20200408T231825Z
SunOS 5.11 11.3
Linux 4.15.0-106-generic #107-Ubuntu SMP Thu Jun 4 11:27:52 UTC 2020
Microsoft Windows 10.0.19635
This proposal is about adding a few more bits of information: name (value of
PAL_UNIX_NAME
orWindows
), version and distro ID. For example, in some cases runtime/hosts only care about major version, so we can just use that. Expected output for the above list is:RuntimeInformation.OSDescription
FreeBSD 11.0-RELEASE-p1 FreeBSD 11.0-RELEASE-p1 #0 r306420: Thu Sep 29 01:43:23 UTC 2016 root@releng2.nyi.freebsd.org:/usr/obj/usr/src/sys/GENERIC. Platform: FreeBSD, Version 11
Linux 4.19.104-gentoo #1 SMP Wed Feb 19 06:37:35 UTC 2020. Platform: Linux, ID: gentoo
(distro does not provide version information)
Darwin 18.7.0 Darwin Kernel Version 18.7.0: Mon Feb 10 21:08:05 PST 2020; root:xnu-4903.278.28~1/RELEASE_X86_64. Platform: OSX, Version: 10.14, ID: Mac OS X
(this version and ID information can be obtained by invoking
sw_vers -productVersion
andsw_vers -productName
respectively, or by reading the XML file directly, whichsw_vers
uses:/System/Library/CoreServices/SystemVersion.plist
)SunOS 5.11 joyent_20200408T231825Z. Platform: illumos, Version 2020, ID: SmartOS
SunOS 5.11 11.3. Platform: Solaris, Version 11
Linux 4.15.0-106-generic #107-Ubuntu SMP Thu Jun 4 11:27:52 UTC 2020. Platform: Linux, Version: 18.04, ID: ubuntu
Microsoft Windows 10.0.19635. Platform: Windows, Version: 10.0.19635