-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Copy endpoint info, runtime info, commmand parsing, and tests from do…
…tnet/diagnostics (#451)
- Loading branch information
1 parent
3fc13d4
commit deb715e
Showing
38 changed files
with
1,033 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
src/Microsoft.Diagnostics.Monitoring.WebApi/CommandLineHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Text; | ||
|
||
namespace Microsoft.Diagnostics.Monitoring.WebApi | ||
{ | ||
internal class CommandLineHelper | ||
{ | ||
public static string ExtractExecutablePath(string commandLine, bool isWindows) | ||
{ | ||
if (string.IsNullOrEmpty(commandLine)) | ||
{ | ||
return commandLine; | ||
} | ||
|
||
int commandLineLength = commandLine.Length; | ||
bool isQuoted = false; | ||
bool isEscaped = false; | ||
int i = 0; | ||
char c = commandLine[0]; | ||
|
||
// Search for the first whitespace character that is not quoted. | ||
// Store character literals as it iterates the command line. Escaped | ||
// characters within double quotes are unescaped for non-Windows systems. | ||
// Algorithm based on INIT_FormatCommandLine behavior from | ||
// https://github.com/dotnet/runtime/blob/main/src/coreclr/pal/src/init/pal.cpp | ||
StringBuilder builder = new StringBuilder(commandLineLength); | ||
do | ||
{ | ||
if (isEscaped) | ||
{ | ||
builder.Append(c); | ||
isEscaped = false; | ||
} | ||
else if (c == '"') | ||
{ | ||
isQuoted = !isQuoted; | ||
} | ||
else if (c == '\\' && !isWindows) | ||
{ | ||
if (isQuoted) | ||
{ | ||
isEscaped = true; | ||
} | ||
else | ||
{ | ||
builder.Append(c); | ||
} | ||
} | ||
else | ||
{ | ||
builder.Append(c); | ||
} | ||
|
||
if (commandLineLength == ++i) | ||
{ | ||
break; | ||
} | ||
|
||
c = commandLine[i]; | ||
} | ||
while (isQuoted || !char.IsWhiteSpace(c)); | ||
|
||
return builder.ToString(); | ||
} | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/ClientEndpointInfoSource.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using Microsoft.Diagnostics.NETCore.Client; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Microsoft.Diagnostics.Monitoring.WebApi | ||
{ | ||
internal sealed class ClientEndpointInfoSource : IEndpointInfoSourceInternal | ||
{ | ||
public async Task<IEnumerable<IEndpointInfo>> GetEndpointInfoAsync(CancellationToken token) | ||
{ | ||
var endpointInfoTasks = new List<Task<EndpointInfo>>(); | ||
// Run the EndpointInfo creation parallel. The call to FromProcessId sends | ||
// a GetProcessInfo command to the runtime instance to get additional information. | ||
foreach (int pid in DiagnosticsClient.GetPublishedProcesses()) | ||
{ | ||
endpointInfoTasks.Add(Task.Run(() => | ||
{ | ||
try | ||
{ | ||
return EndpointInfo.FromProcessId(pid); | ||
} | ||
// Catch when runtime instance shuts down while attepting to use the established diagnostic port connection. | ||
catch (EndOfStreamException) | ||
{ | ||
return null; | ||
} | ||
//Catch when the application is running a more privilaged socket than dotnet-monitor. For example, running a web app as administrator | ||
//while running dotnet-monitor without elevation. | ||
catch (UnauthorizedAccessException) | ||
{ | ||
return null; | ||
} | ||
//Most errors from IpcTransport, such as a stale socket. | ||
catch (ServerNotAvailableException) | ||
{ | ||
return null; | ||
} | ||
}, token)); | ||
} | ||
|
||
await Task.WhenAll(endpointInfoTasks); | ||
|
||
return endpointInfoTasks.Where(t => t.Result != null).Select(t => t.Result); | ||
} | ||
} | ||
} |
99 changes: 99 additions & 0 deletions
99
src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/EndpointInfo.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using Microsoft.Diagnostics.NETCore.Client; | ||
using System; | ||
using System.Diagnostics; | ||
|
||
namespace Microsoft.Diagnostics.Monitoring.WebApi | ||
{ | ||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | ||
internal class EndpointInfo : IEndpointInfo | ||
{ | ||
public static EndpointInfo FromProcessId(int processId) | ||
{ | ||
var client = new DiagnosticsClient(processId); | ||
|
||
ProcessInfo processInfo = null; | ||
try | ||
{ | ||
// Primary motivation is to get the runtime instance cookie in order to | ||
// keep parity with the FromIpcEndpointInfo implementation; store the | ||
// remainder of the information since it already has access to it. | ||
processInfo = client.GetProcessInfo(); | ||
|
||
Debug.Assert(processId == unchecked((int)processInfo.ProcessId)); | ||
} | ||
catch (ServerErrorException) | ||
{ | ||
// The runtime likely doesn't understand the GetProcessInfo command. | ||
} | ||
catch (TimeoutException) | ||
{ | ||
// Runtime didn't respond within client timeout. | ||
} | ||
|
||
// CONSIDER: Generate a runtime instance identifier based on the pipe name | ||
// for .NET Core 3.1 e.g. pid + disambiguator in GUID form. | ||
return new EndpointInfo() | ||
{ | ||
Endpoint = new PidIpcEndpoint(processId), | ||
ProcessId = processId, | ||
RuntimeInstanceCookie = processInfo?.RuntimeInstanceCookie ?? Guid.Empty, | ||
CommandLine = processInfo?.CommandLine, | ||
OperatingSystem = processInfo?.OperatingSystem, | ||
ProcessArchitecture = processInfo?.ProcessArchitecture | ||
}; | ||
} | ||
|
||
public static EndpointInfo FromIpcEndpointInfo(IpcEndpointInfo info) | ||
{ | ||
var client = new DiagnosticsClient(info.Endpoint); | ||
|
||
ProcessInfo processInfo = null; | ||
try | ||
{ | ||
// Primary motivation is to keep parity with the FromProcessId implementation, | ||
// which provides the additional process information because it already has | ||
// access to it. | ||
processInfo = client.GetProcessInfo(); | ||
|
||
Debug.Assert(info.ProcessId == unchecked((int)processInfo.ProcessId)); | ||
Debug.Assert(info.RuntimeInstanceCookie == processInfo.RuntimeInstanceCookie); | ||
} | ||
catch (ServerErrorException) | ||
{ | ||
// The runtime likely doesn't understand the GetProcessInfo command. | ||
} | ||
catch (TimeoutException) | ||
{ | ||
// Runtime didn't respond within client timeout. | ||
} | ||
|
||
return new EndpointInfo() | ||
{ | ||
Endpoint = info.Endpoint, | ||
ProcessId = info.ProcessId, | ||
RuntimeInstanceCookie = info.RuntimeInstanceCookie, | ||
CommandLine = processInfo?.CommandLine, | ||
OperatingSystem = processInfo?.OperatingSystem, | ||
ProcessArchitecture = processInfo?.ProcessArchitecture | ||
}; | ||
} | ||
|
||
public IpcEndpoint Endpoint { get; private set; } | ||
|
||
public int ProcessId { get; private set; } | ||
|
||
public Guid RuntimeInstanceCookie { get; private set; } | ||
|
||
public string CommandLine { get; private set; } | ||
|
||
public string OperatingSystem { get; private set; } | ||
|
||
public string ProcessArchitecture { get; private set; } | ||
|
||
internal string DebuggerDisplay => FormattableString.Invariant($"PID={ProcessId}, Cookie={RuntimeInstanceCookie}"); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/IEndpointInfoSource.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using Microsoft.Diagnostics.NETCore.Client; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Microsoft.Diagnostics.Monitoring.WebApi | ||
{ | ||
internal interface IEndpointInfo | ||
{ | ||
IpcEndpoint Endpoint { get; } | ||
|
||
int ProcessId { get; } | ||
|
||
Guid RuntimeInstanceCookie { get; } | ||
|
||
string CommandLine { get; } | ||
|
||
string OperatingSystem { get; } | ||
|
||
string ProcessArchitecture { get; } | ||
} | ||
|
||
public interface IEndpointInfoSource | ||
{ | ||
} | ||
|
||
internal interface IEndpointInfoSourceInternal : IEndpointInfoSource | ||
{ | ||
Task<IEnumerable<IEndpointInfo>> GetEndpointInfoAsync(CancellationToken token); | ||
} | ||
} |
Oops, something went wrong.