Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft Proposal for Diagnostics Client Library (a.k.a. "Runtime Client Library") #574

Merged
merged 34 commits into from
Nov 13, 2019
Merged
Changes from 11 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c8d1da2
API design doc
sywhang Oct 14, 2019
5aa58a5
more doc
sywhang Oct 15, 2019
b14c3dd
More docs
sywhang Oct 17, 2019
724ca08
some sample code, more detailed description of each API
sywhang Oct 18, 2019
e03a50a
cleanups
sywhang Oct 18, 2019
3ac65ca
Fix markup
sywhang Oct 18, 2019
09edb81
more cleanup
sywhang Oct 18, 2019
6db8055
more cleanup
sywhang Oct 18, 2019
8ffcb28
add DiagnosticsIPCHelper
sywhang Oct 18, 2019
1ab8edb
Add default IPC socket path related helpers
sywhang Oct 18, 2019
4fe23b3
Fix some typos, cases for names
sywhang Oct 21, 2019
8c249ab
Make EventPipeProvider.FilterData an IEnumerable
sywhang Oct 22, 2019
8938d93
Add AddFilterData to EventPipeProvider class
sywhang Oct 22, 2019
00ca2be
Trying to write sample code first
sywhang Oct 23, 2019
98f5509
Some cleanup on unused structs/enums
sywhang Oct 23, 2019
100cec0
Remove EventPipe namespace
sywhang Oct 23, 2019
8c8281b
Adding more sample code, EventPipeSession definition
sywhang Oct 24, 2019
cf5b24d
Some more code in the sample
sywhang Oct 24, 2019
1859bf8
Fix API description
sywhang Oct 24, 2019
b121b5f
Simplify Exceptions, modify some formatting
sywhang Oct 25, 2019
9f671e8
Fix typo and add more description to the intro
sywhang Oct 25, 2019
db05fb7
Remove EventPipeProvider.ToDisplayString() and make Provider IReadOnl…
sywhang Oct 25, 2019
8148b9f
Fix some error in the sample code
sywhang Oct 25, 2019
32b5a64
Address PR comments
sywhang Oct 30, 2019
738a947
State the intended assembly name explicitly
sywhang Oct 30, 2019
2d6a498
Fix some typos
sywhang Nov 1, 2019
9d7bac2
Fix sample code description
sywhang Nov 1, 2019
7eb973a
More fixes
sywhang Nov 5, 2019
9bc8658
Add example about live-parsing events for a period of time
sywhang Nov 5, 2019
57d4f0b
var
sywhang Nov 6, 2019
aa4169d
Fix sample code, add profiler attach sample
sywhang Nov 6, 2019
74d9e12
More fixes
sywhang Nov 6, 2019
1038447
Remove unused sampleprofiler from sample #4
sywhang Nov 7, 2019
c05e35c
More descriptions about each sample, fix few nits
sywhang Nov 7, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
296 changes: 296 additions & 0 deletions documentation/design-docs/diagnostics-client-library.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
# Diagnostics Client Library API Design

## Intro
The Diagnostics Client Library (currently named as "Runtime Client Library") is a managed library that can be used to interact with the .NET runtime via the diagnostics IPC protocol as documented in https://github.com/dotnet/diagnostics/blob/master/documentation/design-docs/ipc-protocol.md.

The name "Diagnostics Client Library" comes from the fact that we call the runtime (CoreCLR) component responsible for accepting and handling the diagnostics IPC commands the "diagnostics server" - https://github.com/dotnet/coreclr/blob/master/src/vm/diagnosticserver.h. Since this library is a managed library on the other side of the IPC protocol responsible for communicating with the runtime's "diagnostics server", calling this the "Diagnostics Client Library" made sense.
sywhang marked this conversation as resolved.
Show resolved Hide resolved
sywhang marked this conversation as resolved.
Show resolved Hide resolved

## Goals

The goal of this library is as following:

* Serve as an implementation of the IPC protocol to communicate with CoreCLR's diagnostics server.
* Provide an easy-to-use API for any library/tools authors to utilize the IPC protocol

## Non-Goals

* Provide tool-specific functionalities that are too high-level (i.e. dumping the GC heap, parsing counter payload, etc.) This will broaden the scope of this library too far and will cause complexity
* Parse event payloads (i.e. - This is also command-specific and can be done by other libraries.

## API Descriptions

At a high level, the DiagnosticsClient library provides a `CommandHandler` class for each of the command specified as part of the diagnostics IPC protocol described here: https://github.com/dotnet/diagnostics/blob/master/documentation/design-docs/ipc-protocol.md#commands. For example, `EventPipeCommandHandler` handles all the `EventPipe` commands that are specified, such as `CollectTracing` and `CollectTracing2`. For each of these commands, there should be a method that handles it.
sywhang marked this conversation as resolved.
Show resolved Hide resolved
sywhang marked this conversation as resolved.
Show resolved Hide resolved

Currently the handler classes are scattered across in different format. On top of that they are all static methods. To make it cleaner and allow a single instance of the CommandHandler class to be responsible for handling communication with a *single process*, I propose that these CommandHandler methods become instance methods and their constructor to take in the process ID of the process they are responsible for communicating with.
sywhang marked this conversation as resolved.
Show resolved Hide resolved

There are also helper methods that contain various util methods for talking to the IPC channel. These are included in the `DiagnosticsIpcHelper` class.
sywhang marked this conversation as resolved.
Show resolved Hide resolved

We may create additional namespaces under Microsoft.Diagnostics.Client for command-specific classes that may be useful. i.e. `Microsoft.Diagnostics.Client.EventPipe`.

### VersionInfo
This is a helper class that encodes the minimum and maximum supported versions of the diagnostics IPC protocol. This helps the developer to programmatically opt in/out of certain features easily. Currently both min/max would be 1.
sywhang marked this conversation as resolved.
Show resolved Hide resolved

```cs
namespace Microsoft.Diagnostics.Client
{
public class VersionInfo
{
public static const int MIN_SUPPORTED_VERSION;
public static const int MAX_SUPPORTED_VERSION;
}
}
```

### DiagnosticsCommand
This is an enum for all the diagnostics command supported in the current version of the library.
```cs
namespace Microsoft.Diagnostics.Client
{
/// <summary>
/// An enum for all the supported diagnostics IPC command
/// </summary>
public enum DiagnosticsCommand
sywhang marked this conversation as resolved.
Show resolved Hide resolved
{
Dump,
EventPipe
Profiler
}
}
```

### DiagnosticsIpcHelper
This is a class that contains some utility methods for various purposes.
```cs
namespace Microsoft.Diagnostics.Client
{
/// <summary>
/// A utility class that contain various helper methods to interact with the diagnostics IPC.
/// </summary>
public class DiagnosticsIpcHelper
{
sywhang marked this conversation as resolved.
Show resolved Hide resolved
/// <summary>
/// Get all the active processes that can be attached to.
/// </summary>
/// <returns>
/// IEnumerable of all the active process IDs.
/// </returns>
public static IEnumerable<int> GetActiveProcesses();
sywhang marked this conversation as resolved.
Show resolved Hide resolved
sywhang marked this conversation as resolved.
Show resolved Hide resolved

// The default path that the diagnostics client library looks for the IPC socket (default: /tmp)
public static string DefaultIpcSocketPath { get; set; }
sywhang marked this conversation as resolved.
Show resolved Hide resolved
sywhang marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Get all the supported commands by this version of the diagnostics IPC.
/// </summary>
/// <returns>
/// IEnumerable of all supported commands Command Code.
/// </returns>
public static IEnumerable<int> GetAvailableCommands();
sywhang marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Convert a command name in the right format (CommandSet:Command) - i.e. EventPipe.CollectTracing - to corresponding command code.
/// </summary>
/// <returns>
/// Corresponding command code for the given command name. This may throw UnknownCommandException.
/// </returns>
public static int GetCommandCodeFromCommandName(string commandName);
sywhang marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Convert a command code to its string representation
/// </summary>
/// <returns>
/// Corresponding command name for the given command code. This may throw UnknownCommandException
/// </returns>
public static string GetCommandNameFromCommandCode(int commandCode);
sywhang marked this conversation as resolved.
Show resolved Hide resolved

}
}
```

### EventPipeCommandHandler
This is a CommandHandler class for sending EventPipe commands across the diagnostics IPC channel.
```cs
namespace Microsoft.Diagnostics.Client
{
/// <summary>
/// A class for handling EventPipe commands.
/// </summary>
public class EventPipeCommandHandler
sywhang marked this conversation as resolved.
Show resolved Hide resolved
sywhang marked this conversation as resolved.
Show resolved Hide resolved
sywhang marked this conversation as resolved.
Show resolved Hide resolved
{
public ulong SessionId { get; } /// A ulong representing the current session ID. Defaults to ulong.Max
sywhang marked this conversation as resolved.
Show resolved Hide resolved
public uint CircularBufferSizeMB { get; set; } /// The maximum buffer size in MB. Defaults to
public EventPipeSerializationFormat SerializationFormat { get; set; } /// Serialization format. Defaults to NetTrace

public EventPipeCommandHandler(int processId)

/// <summary>
/// Add a provider to the EventPipe command
/// </summary>
public void AddProvider(
sywhang marked this conversation as resolved.
Show resolved Hide resolved
string name,
ulong keywords=ulong.MaxValue,
EventLevel=EventLevel.Verbose,
string filterData=null)

/// <summary>
/// Add a path that this instances looks for the IPC socket.
/// </summary>
public void AddIpcSocketPath(string path)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels odd that EventPipe would have more customization than the other handlers?


/// <summary>
/// Start tracing the application via CollectTracing1 command.
/// </summary>
/// <returns>
/// A Stream object to read
/// </returns>
public Stream CollectTracing1(SessionConfiguration configuration)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably favor async APIs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also drop this one entirely. We promised no breaking changes after Preview7 which created the split, but that doesn't require us to make the pre-Preview7 variant easy to access : )

sywhang marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Start tracing the application via CollectTracing2 command.
/// </summary>
/// <returns>
/// A Stream object to read
/// </returns>
public Stream CollectTracing2()
sywhang marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Stop tracing the applicating via the StopTracing command.
/// </summary>
/// <returns>
/// true if stopping the tracing session succeeded. false otherwise.
sywhang marked this conversation as resolved.
Show resolved Hide resolved
/// </returns>
public bool StopTracing()
}
}
```

### DumpCommandHandler
This is a CommandHandler class for sending Dump commands across the diagnostics IPC channel.
```cs
namespace Microsoft.Diagnostics.Client
{
public class DumpCommandHandler
{
public DumpCommandHandler(int processId);
public int GenerateCoreDump();
sywhang marked this conversation as resolved.
Show resolved Hide resolved
}
}
```


### ProfilerCommandHandler
This is a CommandHandler class for sending Profiler commands across the diagnostics IPC channel.
```cs
namespace Microsoft.Diagnostics.Client
{
public class ProfilerCommandHandler
{
public ProfilerCommandHandler(int processId);
public int AttachProfiler(uint attachTimeout, Guid profilerGuid, string profilerPath, byte[] additionalData);
}
}
```


### Exceptions that can be thrown
```cs
namespace Microsoft.Diagnostics.Client.Exceptions
sywhang marked this conversation as resolved.
Show resolved Hide resolved
{
public class UnknownCommandException : Exception {}
sywhang marked this conversation as resolved.
Show resolved Hide resolved
public class UnknownMagicException : Exception {}
sywhang marked this conversation as resolved.
Show resolved Hide resolved
public class EventPipeInvalidArgumentException : Exception {}
public class DumpInvalidArgumentException : Exception {}
public class ProfilerInvalidArgumentException : Exception {}
sywhang marked this conversation as resolved.
Show resolved Hide resolved
}
```

## Micorosft.Diagnostics.Client.EventPipe namespace

### EventPipeCommandSet
An enum for all EventPipe commands.
``` cs
namespace Micorosft.Diagnostics.Client.EventPipe
{
public enum EventPipeCommandSet
sywhang marked this conversation as resolved.
Show resolved Hide resolved
{
StopTracing,
CollectTracing,
CollectTracing2
}
}
```

### EventPipeSerializationFormat
An enum for all EventPipe serialization format.
```cs
namespace Microsoft.Diagnostics.Client.EventPipe
{
public enum EventPipeSerializationFormat
{
NetPerf,
NetTrace
}
}
```

### EventPipeProvider
A class that describes an EventPipe provider.
```cs
namespace Microsoft.Diagnostics.Client.EventPipe
{
public class EventPipeProvider
{
public EventPipeProvider(
string name,
ulong keywords = ulong.MaxValue,
noahfalk marked this conversation as resolved.
Show resolved Hide resolved
EventLevel eventLevel = EventLevel.Verbose,
string filterData = null)
sywhang marked this conversation as resolved.
Show resolved Hide resolved

public ulong Keywords { get; }
sywhang marked this conversation as resolved.
Show resolved Hide resolved

public EventLevel EventLevel { get; }

public string Name { get; }

public string FilterData { get; }
sywhang marked this conversation as resolved.
Show resolved Hide resolved

public string ToDisplayString();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make ToString() do whatever this was doing and eliminate this one?


public override string ToString();

public override bool Equals(object obj);

public override int GetHashCode();

public static bool operator ==(Provider left, Provider right);

public static bool operator !=(Provider left, Provider right);
}
}
```
## Sample Code:
sywhang marked this conversation as resolved.
Show resolved Hide resolved


### 1. Attaching to a process and dumping out its event data
```cs

public static void Main(String[] args)
{
int processId = Int32.Parse(args[0]);

// Create an EventPipe command handler for the given process ID
EventPipeCommandHandler handler = new EventPipeCommandHandler(processId);
sywhang marked this conversation as resolved.
Show resolved Hide resolved

// Add providers that should be turned on
handler.AddProvider("Microsoft-Windows-DotNETRuntime", 0x1, EventLevel.Informational);
handler.AddProvider("System.Runtime", 0x1, EventLevel.Informational, "EventCounterIntervalSec=1");

// Start tracing
Stream stream = handler.CollectTracing1();

// Use TraceEvent to read & parse the stream here.
}
```

// TODO: MORE TO COME