Skip to content

Commit 40bf601

Browse files
authored
Enable global file logging (#2371)
This ensures we can specify file logging globally and uniformly. Greatly simplifying the debug-ability of the agent. The preferred way is to set any or all of the following: * `ELASTIC_OTEL_LOG_TARGETS` (to anything but `none`) * if only set to `stdout` no file will be created but global logging will kicking ) * `OTEL_DOTNET_AUTO_LOG_DIRECTORY` * `OTEL_LOG_LEVEL` * `trace` `debug` will enable global file logging if the other two variables are not set explicitly. This ensure we have one way to debug both our proprietary agent as well as the [Elastic OpenTelemetry Distribution](https://github.com/elastic/elastic-otel-dotnet). See: elastic/elastic-otel-dotnet#129 For backwards compatible reasons the profiler variables are also supported: * `ELASTIC_APM_PROFILER_LOG` * `ELASTIC_APM_PROFILER_LOG_DIR` * `ELASTIC_APM_PROFILER_LOG_TARGETS` Globally setting * `ELASTIC_APM_LOG_LEVEL` and `ELASTIC_APM_LOG_DIRECTORY` is also supported but not preferred. Setting these in any of our supported deploy scenarios: * Manual instrumentation (nuget) * ASP.NET (classic) * ASP.NET core * NOTE: we now log to both the configured ILogger and our global logging. * Auto Instrumentation * Profiler * Startup hooks To keep support existing deploys this now always globally logs to file if only `ELASTIC_APM_STARTUP_HOOKS_LOGGING` is set as well. This further updates our docs for the profiler and troubleshooting to prefer `ELASTIC_OTEL_*` variables. The profiler is updated to read the same environment variables as managed code.
1 parent 7b2dc2b commit 40bf601

38 files changed

+849
-664
lines changed

docs/setup-auto-instrumentation.asciidoc

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ A semi-colon separated list of APM service names to exclude from auto-instrument
398398
Values defined are checked against the value of <<config-service-name,`ELASTIC_APM_SERVICE_NAME`>>
399399
environment variable.
400400

401-
`ELASTIC_APM_PROFILER_LOG` _(optional)_::
401+
`ELASTIC_OTEL_LOG_LEVEL` _(optional)_::
402402

403403
The log level at which the profiler should log. Valid values are
404404

@@ -409,11 +409,15 @@ The log level at which the profiler should log. Valid values are
409409
* error
410410
* none
411411

412+
412413
The default value is `warn`. More verbose log levels like `trace` and `debug` can
413414
affect the runtime performance of profiler auto instrumentation, so are recommended
414415
_only_ for diagnostics purposes.
415416

416-
`ELASTIC_APM_PROFILER_LOG_DIR` _(optional)_::
417+
This takes precedence over the now deprecated `ELASTIC_APM_PROFILER_LOG`
418+
419+
420+
`ELASTIC_OTEL_LOG_DIRECTORY` _(optional)_::
417421

418422
The directory in which to write profiler log files. If unset, defaults to
419423

@@ -424,6 +428,8 @@ If the default directory cannot be written to for some reason, the profiler
424428
will try to write log files to a `logs` directory in the home directory specified
425429
by `ELASTIC_APM_PROFILER_HOME` environment variable.
426430

431+
This takes precedence over the now deprecated `ELASTIC_APM_PROFILER_LOG_DIR`
432+
427433
[IMPORTANT]
428434
--
429435
The user account under which the profiler process runs must have permission to
@@ -432,7 +438,8 @@ on IIS, the https://learn.microsoft.com/en-us/iis/manage/configuring-security/ap
432438
has write permissions in the target directory.
433439
--
434440

435-
`ELASTIC_APM_PROFILER_LOG_TARGETS` _(optional)_::
441+
442+
`ELASTIC_OTEL_LOG_TARGETS` _(optional)_::
436443

437444
A semi-colon separated list of targets for profiler logs. Valid values are
438445

@@ -441,3 +448,5 @@ A semi-colon separated list of targets for profiler logs. Valid values are
441448

442449
The default value is `file`, which logs to the directory specified by
443450
`ELASTIC_APM_PROFILER_LOG_DIR` environment variable.
451+
452+
This takes precedence over the now deprecated `ELASTIC_APM_PROFILER_LOG_TARGETS`

docs/troubleshooting.asciidoc

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,58 @@ If you don't see anything suspicious in the agent logs (no warning or error), it
3232
[[collect-agent-logs]]
3333
=== Collecting agent logs
3434

35-
The way to collect logs depends on the setup of your application.
35+
[float]
36+
[[collect-logs-globally]]
37+
==== Enable global file logging.
38+
39+
The easiest way to get debug information from the Agent, regardless of the way it's run, is to enable global file logging.
40+
41+
Specifying at least one of the following environment variables will ensure the agent logs to a file
42+
43+
`OTEL_LOG_LEVEL` _(optional)_::
44+
45+
The log level at which the profiler should log. Valid values are
46+
47+
* trace
48+
* debug
49+
* info
50+
* warn
51+
* error
52+
* none
53+
54+
55+
The default value is `warn`. More verbose log levels like `trace` and `debug` can
56+
affect the runtime performance of profiler auto instrumentation, so are recommended
57+
_only_ for diagnostics purposes.
58+
59+
NOTE: if `ELASTIC_OTEL_LOG_TARGETS` is not explicitly set to include `file` global file logging will only
60+
be enabled when configured with `trace` or `debug`.
61+
62+
`OTEL_DOTNET_AUTO_LOG_DIRECTORY` _(optional)_::
63+
64+
The directory in which to write log files. If unset, defaults to
65+
66+
* `%PROGRAMDATA%\elastic\apm-agent-dotnet\logs` on Windows
67+
* `/var/log/elastic/apm-agent-dotnet` on Linux
68+
69+
70+
[IMPORTANT]
71+
--
72+
The user account under which the profiler process runs must have permission to
73+
write to the destination log directory. Specifically, ensure that when running
74+
on IIS, the https://learn.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities[AppPool identity]
75+
has write permissions in the target directory.
76+
--
77+
78+
`ELASTIC_OTEL_LOG_TARGETS` _(optional)_::
79+
80+
A semi-colon separated list of targets for profiler logs. Valid values are
81+
82+
* file
83+
* stdout
84+
85+
The default value is `file` if `OTEL_DOTNET_AUTO_LOG_DIRECTORY` is set or `OTEL_LOG_LEVEL` is set to `trace` or `debug`.
86+
3687

3788
[float]
3889
[[collect-logs-core]]
@@ -62,49 +113,9 @@ For example, the following configuration in `appsettings.json` limits APM agents
62113
----
63114
<1> Control the verbosity of the agent logs by setting the log level for the `Elastic.Apm` category
64115

65-
[float]
66-
[[collect-logs-classic]]
67-
==== ASP.NET Classic
68-
69-
ASP.NET (classic) does not have a predefined logging system. By default, the agent is configured to
70-
emit log messages to a
71-
https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.tracesource[`System.Diagnostics.TraceSource`]
72-
with the source name `"Elastic.Apm"`. The TraceSource adheres to the log levels defined in the
73-
APM agent configuration. Typically, you will configure a preferred log level using an application setting in `web.config`.
74-
75-
[IMPORTANT]
76-
--
77-
System.Diagnostics.TraceSource requires the https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/how-to-compile-conditionally-with-trace-and-debug[`TRACE` compiler directive to be specified], which is specified
78-
by default for both Debug and Release build configurations.
79-
--
80-
81-
https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.tracelistener[TraceListeners]
82-
can be configured to monitor log messages for the trace source, using the https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/trace-debug/system-diagnostics-element[`<system.diagnostics>`] section of
83-
web.config. For example, the following web.config section writes Elastic.Apm log messages to a file
84-
named my_log_file.log:
85-
86-
[source,xml]
87-
----
88-
<configuration>
89-
<!-- other sections .... -->
90-
<system.diagnostics>
91-
<sources>
92-
<source name="Elastic.Apm"> <1>
93-
<listeners>
94-
<add name="file"
95-
type="System.Diagnostics.TextWriterTraceListener"
96-
initializeData="my_log_file.log" />
97-
</listeners>
98-
</source>
99-
</sources>
100-
</system.diagnostics>
101-
</configuration>
102-
----
103-
<1> Define listeners under a source with name `"Elastic.Apm"` to capture agent logs
104-
105116
[float]
106117
[[collect-logs-class-other-logging-systems]]
107-
===== Other logging systems
118+
==== Other logging systems
108119

109120
If you have a logging system in place such as https://nlog-project.org/[NLog], https://serilog.net/[Serilog],
110121
or similar, you can direct the agent logs into your logging system by creating an adapter between
@@ -242,17 +253,7 @@ The agent is only supported on IIS7 and higher where the `Integrated Pipeline Mo
242253
[[startup-hook-failure]]
243254
=== Startup hooks failure
244255

245-
If the <<zero-code-change-setup, startup hook>> integration throws an exception, additional detail can be obtained by
246-
setting the `ELASTIC_APM_STARTUP_HOOKS_LOGGING` environment variable before starting the application
247-
248-
[source,sh]
249-
----
250-
set ELASTIC_APM_STARTUP_HOOKS_LOGGING=1
251-
----
252-
253-
and then running the application in a context where the environment variable will be visible. In setting this value,
254-
an `ElasticApmAgentStartupHook.log` file is written to the directory containing the startup hook assembly, in addition to
255-
writing to standard output.
256+
If the <<zero-code-change-setup, startup hook>> integration throws an exception, additional detail can be obtained through <<collect-logs-globally, enabling the global log collection>>.
256257

257258
[float]
258259
[[agent-overhead]]

src/Elastic.Apm/AgentComponents.cs

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ internal AgentComponents(
5252
var config = CreateConfiguration(logger, configurationReader);
5353
hostNameDetector ??= new HostNameDetector();
5454

55-
Logger = logger ?? CheckForProfilerLogger(DefaultLogger(null, configurationReader), config.LogLevel);
55+
Logger = logger ?? GetGlobalLogger(DefaultLogger(null, configurationReader), config.LogLevel);
5656
ConfigurationStore = new ConfigurationStore(new RuntimeConfigurationSnapshot(config), Logger);
5757

5858
Service = Service.GetDefaultService(config, Logger);
@@ -199,38 +199,39 @@ private static IConfigurationReader CreateConfiguration(IApmLogger logger, IConf
199199
#endif
200200
}
201201

202-
203-
//
204-
// This is the hooking point that checks for the existence of profiler-related
205-
// logging settings.
206-
// If no agent logging is configured but we detect profiler logging settings, those
207-
// will be honoured.
208-
// The finer-grained log-level (agent vs profiler) will be used.
209-
// This has the benefit that users will also get agent logs in addition to profiler-only
210-
// logs.
211-
//
212-
internal static IApmLogger CheckForProfilerLogger(IApmLogger fallbackLogger, LogLevel agentLogLevel, IDictionary environmentVariables = null)
202+
/// <summary>
203+
/// This ensures agents will respect externally provided loggers.
204+
/// <para>If the agent is started as part of profiling it should adhere to profiling configuration</para>
205+
/// <para>If file logging environment variables are set we should always log to that location</para>
206+
/// </summary>
207+
/// <param name="fallbackLogger"></param>
208+
/// <param name="agentLogLevel"></param>
209+
/// <param name="environmentVariables"></param>
210+
/// <returns></returns>
211+
internal static IApmLogger GetGlobalLogger(IApmLogger fallbackLogger, LogLevel agentLogLevel, IDictionary environmentVariables = null)
213212
{
214213
try
215214
{
216-
var profilerLogConfig = ProfilerLogConfig.Check(environmentVariables);
217-
if (profilerLogConfig.IsActive)
215+
var fileLogConfig = GlobalLogConfiguration.FromEnvironment(environmentVariables);
216+
if (!fileLogConfig.IsActive)
218217
{
219-
var effectiveLogLevel = LogLevelUtils.GetFinest(agentLogLevel, profilerLogConfig.LogLevel);
218+
fallbackLogger.Info()?.Log("No system wide logging configured, defaulting to fallback logger");
219+
return fallbackLogger;
220+
}
220221

221-
if ((profilerLogConfig.LogTargets & ProfilerLogTarget.File) == ProfilerLogTarget.File)
222-
TraceLogger.TraceSource.Listeners.Add(new TextWriterTraceListener(profilerLogConfig.LogFilePath));
223-
if ((profilerLogConfig.LogTargets & ProfilerLogTarget.StdOut) == ProfilerLogTarget.StdOut)
224-
TraceLogger.TraceSource.Listeners.Add(new TextWriterTraceListener(Console.Out));
222+
var effectiveLogLevel = LogLevelUtils.GetFinest(agentLogLevel, fileLogConfig.LogLevel);
223+
if ((fileLogConfig.LogTargets & GlobalLogTarget.File) == GlobalLogTarget.File)
224+
TraceLogger.TraceSource.Listeners.Add(new TextWriterTraceListener(fileLogConfig.AgentLogFilePath));
225+
if ((fileLogConfig.LogTargets & GlobalLogTarget.StdOut) == GlobalLogTarget.StdOut)
226+
TraceLogger.TraceSource.Listeners.Add(new TextWriterTraceListener(Console.Out));
225227

226-
var logger = new TraceLogger(effectiveLogLevel);
227-
logger.Info()?.Log($"{nameof(ProfilerLogConfig)} - {profilerLogConfig}");
228-
return logger;
229-
}
228+
var logger = new TraceLogger(effectiveLogLevel);
229+
logger.Info()?.Log($"{nameof(fileLogConfig)} - {fileLogConfig}");
230+
return logger;
230231
}
231232
catch (Exception e)
232233
{
233-
fallbackLogger.Warning()?.LogException(e, "Error in CheckForProfilerLogger");
234+
fallbackLogger.Warning()?.LogException(e, "Error in GetGlobalLogger");
234235
}
235236
return fallbackLogger;
236237
}

src/Elastic.Apm/Config/Net4FullFramework/FullFrameworkDefaultImplementations.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ internal static IApmLogger CreateDefaultLogger(LogLevel? configuredDefault)
2222
if (!string.IsNullOrEmpty(logLevel))
2323
Enum.TryParse(logLevel, true, out level);
2424

25-
return AgentComponents.CheckForProfilerLogger(new TraceLogger(level), level);
25+
return AgentComponents.GetGlobalLogger(new TraceLogger(level), level);
2626
}
2727

2828
/// <summary>

src/Elastic.Apm/Config/ProfilerLogConfig.cs

Lines changed: 0 additions & 90 deletions
This file was deleted.

0 commit comments

Comments
 (0)