### Install XenoAtom.MsBuildPipeLogger package Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/readme.md Use this command to install the XenoAtom.MsBuildPipeLogger NuGet package. The package copies the logger assembly to an isolated output subfolder so MSBuild does not probe unrelated application assemblies. ```sh dotnet add package XenoAtom.MsBuildPipeLogger ``` -------------------------------- ### Named pipe logger server example Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Creates a NamedPipeLoggerServer with a unique pipe name, subscribes to AnyEventRaised to print messages, builds a logger specification using the pipe name, and launches dotnet msbuild with the /logger argument. The server reads events asynchronously and waits for the process to exit before stopping. ```csharp using System.Diagnostics; using XenoAtom.MsBuildPipeLogger; var pipeName = PipeLoggerServer.CreateUniquePipeName("build-events"); using var server = new NamedPipeLoggerServer(pipeName); server.AnyEventRaised += e => Console.WriteLine(e.Message); var loggerSpecification = PipeLoggerServer.GetLoggerSpecification($"name={pipeName}"); using var process = new Process(); process.StartInfo.FileName = "dotnet"; process.StartInfo.ArgumentList.Add("msbuild"); process.StartInfo.ArgumentList.Add("MyProject.csproj"); process.StartInfo.ArgumentList.Add($"/logger:{loggerSpecification}"); process.StartInfo.UseShellExecute = false; var readTask = Task.Run(server.ReadAll); process.Start(); process.WaitForExit(); server.StopListening(); readTask.Wait(); ``` -------------------------------- ### Anonymous pipe logger server example Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Creates an AnonymousPipeLoggerServer, subscribes to AnyEventRaised to print messages, builds a logger specification from the client handle, and launches dotnet msbuild with the /logger argument. The server reads events asynchronously and waits for the process to exit before stopping. ```csharp using System.Diagnostics; using XenoAtom.MsBuildPipeLogger; using var server = new AnonymousPipeLoggerServer(); server.AnyEventRaised += e => Console.WriteLine(e.Message); var loggerSpecification = PipeLoggerServer.GetLoggerSpecification(server.GetClientHandle()); using var process = new Process(); process.StartInfo.FileName = "dotnet"; process.StartInfo.ArgumentList.Add("msbuild"); process.StartInfo.ArgumentList.Add("MyProject.csproj"); process.StartInfo.ArgumentList.Add($"/logger:{loggerSpecification}"); process.StartInfo.UseShellExecute = false; var readTask = Task.Run(server.ReadAll); process.Start(); process.WaitForExit(); server.StopListening(); readTask.Wait(); ``` -------------------------------- ### Use PipeLoggerServer.GetLoggerSpecification with NamedPipeLoggerServer Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Creates a unique named pipe, starts a dotnet msbuild process with the logger specification, and reads events. Requires the XenoAtom.MsBuildPipeLogger package. The server serves every submission, suitable for dotnet build. ```csharp using System.Diagnostics; using XenoAtom.MsBuildPipeLogger; var pipeName = PipeLoggerServer.CreateUniquePipeName("build-events"); using var server = new NamedPipeLoggerServer(pipeName); server.AnyEventRaised += e => Console.WriteLine(e.Message); using var process = new Process(); process.StartInfo.FileName = "dotnet"; process.StartInfo.ArgumentList.Add("msbuild"); process.StartInfo.ArgumentList.Add("MyProject.csproj"); process.StartInfo.ArgumentList.Add("/nologo"); process.StartInfo.ArgumentList.Add("/nr:false"); var loggerSpecification = PipeLoggerServer.GetLoggerSpecification($"name={pipeName}"); process.StartInfo.ArgumentList.Add($"/logger:{loggerSpecification}"); process.StartInfo.UseShellExecute = false; var readTask = Task.Run(server.ReadAll); process.Start(); process.WaitForExit(); server.StopListening(); readTask.Wait(); ``` -------------------------------- ### StopListening() to end a read after process exit Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Use this sequence when the observed process may run multiple build submissions. Start ReadAll on a background task, start and wait for the process, then call StopListening() to request a stop and drain already-arrived events before waiting on the read task. ```csharp var readTask = Task.Run(server.ReadAll); process.Start(); process.WaitForExit(); server.StopListening(); // request a stop, then drain what has already arrived readTask.Wait(); ``` -------------------------------- ### Build and test commands (dotnet build, dotnet test) Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/AGENTS.md Commands to build and test the project from the root directory. Run from the project root: first change to the src directory, then build in Release configuration, then run tests in Release configuration. ```sh # from the project root (this folder) cd src dotnet build -c Release dotnet test -c Release ``` -------------------------------- ### Publish and run the Native AOT sample Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/src/XenoAtom.MsBuildPipeLogger.NativeAotSample/readme.md Publishes the sample for a given runtime identifier and runs the resulting native binary. Replace with your runtime identifier (e.g. osx-arm64, linux-x64, win-x64). The published folder contains a self-contained native binary plus the isolated logger under XenoAtom.MsBuildPipeLogger/. ```sh # from the src directory dotnet publish XenoAtom.MsBuildPipeLogger.NativeAotSample -c Release -r ./XenoAtom.MsBuildPipeLogger.NativeAotSample/bin/Release/net10.0//publish/XenoAtom.MsBuildPipeLogger.NativeAotSample ``` -------------------------------- ### Set up NamedPipeLoggerServer to receive events Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Creates a named pipe server with a unique pipe name, subscribes to the MessageRaised event to print messages, and reads all events. Call StopListening() from another thread once the build process exits. ```csharp using var server = new NamedPipeLoggerServer(PipeLoggerServer.CreateUniquePipeName()); server.MessageRaised += m => Console.WriteLine(m.Message); server.ReadAll(); // call server.StopListening() from another thread once the build process exits ``` -------------------------------- ### Expected success output Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/src/XenoAtom.MsBuildPipeLogger.NativeAotSample/readme.md On success the host prints the streamed events and exits 0. ```text SUCCESS: MSBuild events were received over the pipe by a Native AOT host. ``` -------------------------------- ### NamedPipeLoggerServer with acceptMultipleConnections: false Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Use this constructor when you know there is exactly one build submission, such as invoking dotnet msbuild or dotnet build --no-restore with restore driven separately. This lets the read end when the client disconnects. ```csharp using var server = new NamedPipeLoggerServer(pipeName, acceptMultipleConnections: false); ``` -------------------------------- ### Add PackageReference to XenoAtom.MsBuildPipeLogger Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Declares the XenoAtom.MsBuildPipeLogger package reference in a project file. The version placeholder must be replaced with an actual version. ```xml ``` -------------------------------- ### NamedPipeLoggerServer Constructor Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Creates a named pipe logger server that can accept multiple connections or a single connection depending on the acceptMultipleConnections parameter. ```APIDOC ## NamedPipeLoggerServer Constructor ### Description Creates a named pipe logger server that connects to a local named pipe. The server can accept multiple connections (default) or a single connection if acceptMultipleConnections is false. ### Method Constructor ### Endpoint N/A (SDK constructor) ### Parameters - **pipeName** (string) - Required - The name of the named pipe to connect to. - **acceptMultipleConnections** (bool) - Optional - If false, the server accepts only one connection and the read ends when the client disconnects. Default is true. ### Request Example ```csharp using var server = new NamedPipeLoggerServer(pipeName, acceptMultipleConnections: false); ``` ### Response No return value. ``` -------------------------------- ### Path length breakdown for Unix pipe names Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Shows the fixed overhead of the Unix pipe path: the TMPDIR prefix and the CoreFxPipe_ prefix. This leaves only about 43 characters for the pipe name. ```text /var/folders/w2/cgg8mtk97gb9_bvg4y108wz00000gn/T/ 49 CoreFxPipe_ 11 ``` -------------------------------- ### AnonymousPipeLoggerServer Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Creates an anonymous pipe logger server that connects to a client through an inherited handle. It serves exactly one submission and the read ends when the client disconnects. ```APIDOC ## AnonymousPipeLoggerServer ### Description Creates an anonymous pipe logger server that connects to a client through an inherited handle. It serves exactly one submission and the read ends when the client disconnects. StopListening() is a no-op on an anonymous pipe. ### Method Constructor ### Endpoint N/A (SDK class) ### Parameters - **handle** (string) - Required - The anonymous pipe client handle to connect to. ### Request Example ```csharp // Example usage not provided in source. ``` ### Response No return value. ``` -------------------------------- ### Using PipeLoggerServer helpers to create pipe names Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Use CreateUniquePipeName to generate a pipe name that always fits, optionally with a prefix that is truncated if needed. GetMaximumPipeNameLength returns the maximum allowed length for custom names. ```csharp var pipeName = PipeLoggerServer.CreateUniquePipeName(); // always fits var pipeName = PipeLoggerServer.CreateUniquePipeName("myapp"); // prefixed, truncated if needed var maximum = PipeLoggerServer.GetMaximumPipeNameLength(); // if you must build your own ``` -------------------------------- ### PipeLoggerServer.Connect() override Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Custom transports derived from PipeLoggerServer must override Connect() to return a bool indicating whether a client was connected and should be read. ```APIDOC ## PipeLoggerServer.Connect() override ### Description Custom transports derived from PipeLoggerServer must override Connect() to return a bool indicating whether a client was connected and should be read. Return true when a client was connected and should be read, or false when the read should finish without a client. ### Method Connect ### Endpoint N/A (SDK method) ### Parameters None. ### Request Example ```csharp protected override bool Connect() { ... } ``` ### Response - **bool** - true if a client was connected and should be read; false if the read should finish without a client. ``` -------------------------------- ### NamedPipeLoggerServer.ReadAll() Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Continuously reads and dispatches PipeBuildEventArgs until the transport closes or StopListening is called. It blocks and processes events as they arrive. ```APIDOC ## NamedPipeLoggerServer.ReadAll() ### Description Continuously reads and dispatches PipeBuildEventArgs until the transport closes or StopListening is called. It blocks and processes events as they arrive. ### Method ReadAll ### Endpoint N/A (SDK method) ### Parameters None. ### Request Example ```csharp var readTask = Task.Run(server.ReadAll); ``` ### Response No return value. ``` -------------------------------- ### NamedPipeLoggerServer.StopListening() Source: https://github.com/xenoatom/xenoatom.msbuildpipelogger/blob/main/doc/readme.md Requests the server to stop accepting new connections and allows the backlog of already-received events to drain before the read completes. This is the recommended way to finish a read after the observed process exits. ```APIDOC ## NamedPipeLoggerServer.StopListening() ### Description Requests the server to stop accepting new connections and allows the backlog of already-received events to drain before the read completes. This is the recommended way to finish a read after the observed process exits. ### Method StopListening ### Endpoint N/A (SDK method) ### Parameters None. ### Request Example ```csharp server.StopListening(); ``` ### Response No return value. ```