Remove Mono.Unix dependency#223
Conversation
fe42102 to
30e7810
Compare
Mono.Unix dependency
1bea90d to
368b0f2
Compare
1115c35 to
c422e70
Compare
e869628 to
5816bd1
Compare
5816bd1 to
73aa5a2
Compare
Origin detection reads file inode numbers on Linux. This replaces the bundled native libfs.so with a direct statx system call via P/Invoke. struct statx has a fixed, architecture-independent layout, so a single managed definition works across x64/arm64 and glibc/musl without shipping any native binaries. Removes the C library, its Docker cross-build, the CI native-build job, and the per-RID NuGet packaging. The package now has no native assets and no runtime dependencies. 🤖
Correct the NuGet pack output path to the artifacts/ layout, fix clean instructions, and clarify that the wider framework list applies to the test project while the library targets net461/netstandard2.0/netcoreapp3.1/net6.0. 🤖
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5fde5531b9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR removes the external Mono.Unix NuGet dependency by vendoring the required UnixEndPoint implementation and replacing inode lookup based on Mono.Unix.Native.Syscall.stat with a Linux statx P/Invoke helper, plus adds documentation and integration tests around inode lookup.
Changes:
- Removed
Mono.Unixpackage reference and added an in-repoMono.Unix.UnixEndPointimplementation. - Introduced
NativeMethods(statxP/Invoke) and updatedFileSystem.TryStatto use it on Linux (non-NETFRAMEWORK builds). - Added Linux integration tests for inode lookup and new build/testing guidance docs.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/StatsdClient.Tests/NativeLibraryTests.cs | Adds Linux-only integration tests validating inode lookup behavior. |
| src/StatsdClient/UnixEndPoint.cs | Vendors UnixEndPoint to avoid relying on the Mono.Unix package. |
| src/StatsdClient/StatsdClient.csproj | Removes the Mono.Unix package reference from the library project. |
| src/StatsdClient/NativeMethods.cs | Adds statx-based inode lookup via P/Invoke on Linux. |
| src/StatsdClient/IFileSystem.cs | Switches TryStat implementation to use the new inode lookup on Linux. |
| CLAUDE.md | Adds repository build/test guidance for agent-based workflows. |
| BUILD.md | Adds general build and test instructions (including framework selection guidance). |
| .gitattributes | Normalizes line endings and enforces LF for shell scripts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Delegate the Linux platform check to NativeMethods.TryGetInode instead of duplicating it in TryStat, and drop the now-unused usings. 🤖
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Reference BUILD.md for build/test commands instead of duplicating them, and drop stale file listings the agent can discover by grepping. 🤖
andrewlock
left a comment
There was a problem hiding this comment.
LGTM - I think we should mention somewhere th as t this is incompatible with a bunch of glibc versions and musk - maybe in the PR and in the source code (so anyone wondering "why doesn't this work" has an easy answer)
Summary
Removes the
Mono.UnixNuGet dependency, which was incompatible with some target runtimes (e.g. .NET Framework 4.6.1) and blocked customers from upgrading the client (#220).Only two pieces of
Mono.Unixwere actually used, and both are replaced with self-contained alternatives:UnixEndPoint(Unix domain socket transport): vendored directly into the repo assrc/StatsdClient/UnixEndPoint.cs, copied from the Mono source under its MIT license. The public API and namespace (Mono.Unix) are preserved, so transport code is unchanged.Syscall.stat(inode lookup for cgroup/container origin detection on Linux): replaced with a directstatxsystem call via P/Invoke insrc/StatsdClient/NativeMethods.cs.struct statxhas a fixed, architecture-independent layout defined by the kernel, so a single managed struct definition works across x64/arm64 and glibc/musl. No native binaries are shipped, and the package now has no native assets or third-party runtime dependencies.FileSystem.TryStatis narrowed from any Unix platform to Linux only (the sole consumer, cgroup origin detection, reads Linux-only/procpaths) and delegates the platform check toNativeMethods.TryGetInode. Inode lookup is compiled out on .NET Framework (#if !NETFRAMEWORK), which always runs on Windows.Changes
Mono.UnixPackageReferencefromStatsdClient.csproj.src/StatsdClient/UnixEndPoint.cs(vendored, MIT).src/StatsdClient/NativeMethods.cs(statxP/Invoke wrapper).src/StatsdClient/IFileSystem.csto use the new inode lookup.tests/StatsdClient.Tests/NativeLibraryTests.csexercising the realstatxcall on Linux.BUILD.mdandCLAUDE.mddeveloper docs..gitattributesto force LF line endings on shell scripts.Testing
net461,netstandard2.0,netcoreapp3.1,net6.0); the net461 build exercises the#if NETFRAMEWORKfallback path.NativeLibraryTestsexercises the realstatxsyscall on Linux (inode for files, directories, symlinks, the cgroup namespace link, and non-existent-file failure) and verifies the non-Linux path returns false.Compatibility
EDIT 2026-06-04. Summary from 🤖:
Why
Mono.Unixis there at all: it's only used to callstat()and read the inode number for origin detection (OriginDetection.cs) — specifically the host cgroup-namespace check (/proc/self/ns/cgroup, line 104) and the cgroup-inode container-ID fallbackGetCgroupInode, line 168). That's it.This PR initially replaced
Mono.Unixwith a tiny native C library that wrapsstat(), called via P/Invoke. It shiped a.sofor 4 RIDs (linux-x64,linux-musl-x64,linux-arm64,linux-musl-arm64), with Docker cross-builds, CI changes, and NuGet packaging work.Why not P/Invoke libc's
stat()directly? Becausestruct stat's layout varies by architecture (x86_64 vs arm64) and libc (glibc vs musl), so a single C# struct definition can't safely marshal it — which is why we were wrapping it in C in early commits in this PR.@atanzu suggested using
statxinstead. That's a genuinely good idea, and it sidesteps the whole problem:struct statxhas a fixed, architecture-independent layout defined by the kernel (fixed-width fields + explicit padding, 256 bytes). One C# struct works everywhere — no per-arch/per-libc variants.statx(2)is a Linux syscall since kernel 4.11 (2017); the glibc wrapper exists since glibc 2.28 and musl since 1.1.20. You can P/Invoke[LibraryImport("libc")] statx(...)directly, request onlySTATX_INO, and readstx_ino.Mono.Unixpath but with zero external dependency.The one tradeoff: kernels older than 4.11 (e.g. CentOS 7 / kernel 3.10) lack
statx. But origin detection already degrades gracefully (returns empty / false), so on those hosts you'd just lose container-ID-by-inode fallback — the same as today on any unsupported platform. For containerized workloads (the only place this matters) 4.11+ is essentially universal in 2026.