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

Improve Performance counter handling #1536

Merged
merged 6 commits into from
Nov 3, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
20 changes: 20 additions & 0 deletions docs/metrics.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ The metrics will be stored in the `apm-*` index and have the `processor.event` p

As of APM version 6.6, these metrics will be visualized in the APM app.

[IMPORTANT]
--
System metrics are collected using Performance Counters on Windows. The account under which a traced
application runs must be part of the **Performance Monitor Users** group to be able to access
performance counter values.

An account can be added to the **Performance Monitor Users** group from the command line

[source,sh]
----
net localgroup "Performance Monitor Users" "<Account Name>" /add <1>
----
<1> `<Account Name>` is the account under which the traced application runs

For applications running in IIS,
https://docs.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities[IIS application pool identities use _virtual_ accounts]
with a name following the convention `IIS APPPOOL\<Application pool name>`. An individual application pool identity
can be added to the **Performance Monitor Users** group.
--

For more system metrics, consider installing {metricbeat-ref}/index.html[metricbeat] on your hosts.

*`system.cpu.total.norm.pct`*::
Expand Down
48 changes: 35 additions & 13 deletions src/Elastic.Apm/Metrics/MetricsProvider/SystemTotalCpuProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,53 @@ public SystemTotalCpuProvider(IApmLogger logger)
_logger = logger.Scoped(nameof(SystemTotalCpuProvider));
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var categoryName = "Processor";
try
{
_processorTimePerfCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
try
{
_processorTimePerfCounter = new PerformanceCounter(categoryName, "% Processor Time", "_Total");
}
catch (InvalidOperationException e)
{
_logger.Debug()?.LogException(e, "Error instantiating '{CategoryName}' performance counter.", categoryName);
_processorTimePerfCounter?.Dispose();
// If the Processor performance counter category does not exist, try Processor Information.
categoryName = "Processor Information";
_processorTimePerfCounter = new PerformanceCounter(categoryName, "% Processor Time", "_Total");
}

//The perf. counter API returns 0 the for the 1. call (probably because there is no delta in the 1. call) - so we just call it here first
_processorTimePerfCounter.NextValue();
}
catch (Exception e)
{
_logger.Error()
?.LogException(e, "Failed instantiating PerformanceCounter "
+ "- please make sure the current user has permissions to read performance counters. E.g. make sure the current user is member of "
+ "the 'Performance Monitor Users' group");

if (e is UnauthorizedAccessException)
{
_logger.Error()
?.LogException(e, "Error instantiating '{CategoryName}' performance counter."
+ " Process does not have permissions to read performance counters."
+ " See https://www.elastic.co/guide/en/apm/agent/dotnet/current/metrics.html#metrics-system to see how to configure.", categoryName);
}
else
{
_logger.Error()
?.LogException(e, "Error instantiating '{CategoryName}' performance counter", categoryName);
}

_logger.Warning()?.Log("System metrics won't be collected");
_processorTimePerfCounter?.Dispose();
_processorTimePerfCounter = null;
}
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
var (success, idle, total) = ReadProcStat();
if (!success) return;

if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return;

var (success, idle, total) = ReadProcStat();
if (!success) return;

_prevIdleTime = idle;
_prevTotalTime = total;
_prevIdleTime = idle;
_prevTotalTime = total;
}
}

internal SystemTotalCpuProvider(IApmLogger logger, StreamReader procStatStreamReader)
Expand Down