Skip to content

Commit 02799ad

Browse files
RassKrajkumar-rangarajpjanotti
authored
Add console sink to the diagnostic logging (open-telemetry#3558)
* Add console logger sink * cleanup * remove container detection * add unit tests * add managed logs output tests * update tests * Update docs * refactor CreateSink * refactor LoggerImpl * reset whitespace * fix native logger --------- Co-authored-by: Rajkumar Rangaraj <[email protected]> Co-authored-by: Paulo Janotti <[email protected]>
1 parent 4f7d8aa commit 02799ad

File tree

19 files changed

+341
-36
lines changed

19 files changed

+341
-36
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h
3232
- `OTEL_EXPORTER_OTLP_LOGS_PROTOCOL`.
3333
- Support for air-gapped installations through `DOWNLOAD_DIR` or `LOCAL_PATH`
3434
arguments to `otel-dotnet-auto-install.sh`.
35+
- Added `OTEL_DOTNET_AUTO_LOGGER` to select preferred sink for AutoInstrumentation
36+
diagnostic logs.
3537

3638
### Changed
3739

docs/config.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ However, if given setting supports it, then:
5858
| `OTEL_DOTNET_AUTO_HOME` | Installation location. | | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
5959
| `OTEL_DOTNET_AUTO_EXCLUDE_PROCESSES` | Names of the executable files that the profiler cannot instrument. Supports multiple comma-separated values, for example: `ReservedProcess.exe,powershell.exe`. If unset, the profiler attaches to all processes by default. \[1\]\[2\] | | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
6060
| `OTEL_DOTNET_AUTO_FAIL_FAST_ENABLED` | Enables possibility to fail process when automatic instrumentation cannot be executed. It is designed for debugging purposes. It should not be used in production environment. \[1\] | `false` | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
61+
| `OTEL_DOTNET_AUTO_LOGGER` | AutoInstrumentation diagnostic logs sink. (supported values: `none`,`file`,`console`) | `file` | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
6162
| `OTEL_LOG_LEVEL` | SDK log level. (supported values: `none`,`error`,`warn`,`info`,`debug`) | `info` | [Stable](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
6263

6364
\[1\] If `OTEL_DOTNET_AUTO_FAIL_FAST_ENABLED` is set to `true` then processes

src/OpenTelemetry.AutoInstrumentation.Loader/OpenTelemetry.AutoInstrumentation.Loader.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\NoopLogger.cs">
1717
<Link>Logging\NoopLogger.cs</Link>
1818
</Compile>
19+
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\ConsoleSink.cs">
20+
<Link>Logging\ConsoleSink.cs</Link>
21+
</Compile>
1922
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\FileSink.cs">
2023
<Link>Logging\FileSink.cs</Link>
2124
</Compile>
@@ -43,6 +46,9 @@
4346
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\LogLevel.cs">
4447
<Link>Logging\LogLevel.cs</Link>
4548
</Compile>
49+
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\LogSink.cs">
50+
<Link>Logging\LogSink.cs</Link>
51+
</Compile>
4652
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\NoopSink.cs">
4753
<Link>Logging\NoopSink.cs</Link>
4854
</Compile>

src/OpenTelemetry.AutoInstrumentation.Native/environment_variables.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ namespace environment {
1414
// Sets logging level used by autoinstrumentation loggers
1515
const WSTRING log_level = WStr("OTEL_LOG_LEVEL");
1616

17+
// Sets logger used by autoinstrumentation
18+
const WSTRING log_sink = WStr("OTEL_DOTNET_AUTO_LOGGER");
19+
1720
// Sets max size of a single log file
1821
const WSTRING max_log_file_size = WStr("OTEL_DOTNET_AUTO_LOG_FILE_SIZE");
1922

src/OpenTelemetry.AutoInstrumentation.Native/logger_impl.h

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "spdlog/sinks/null_sink.h"
1414
#include "spdlog/sinks/rotating_file_sink.h"
15+
#include "spdlog/sinks/stdout_sinks.h"
1516

1617
#ifndef _WIN32
1718
typedef struct stat Stat;
@@ -34,6 +35,7 @@ class LoggerImpl : public Singleton<LoggerImpl<TLoggerPolicy>>
3435
private:
3536
std::shared_ptr<spdlog::logger> m_fileout;
3637
static std::string GetLogPath(const std::string& file_name_suffix);
38+
static std::shared_ptr<spdlog::logger> CreateFileSink(std::string logger_name);
3739
LoggerImpl();
3840
~LoggerImpl();
3941

@@ -43,6 +45,10 @@ class LoggerImpl : public Singleton<LoggerImpl<TLoggerPolicy>>
4345
static inline const WSTRING log_level_info = WStr("info");
4446
static inline const WSTRING log_level_debug = WStr("debug");
4547

48+
static inline const WSTRING log_sink_none = WStr("none");
49+
static inline const WSTRING log_sink_file = WStr("file");
50+
static inline const WSTRING log_sink_console = WStr("console");
51+
4652
static inline const std::string logger_name = "Logger";
4753

4854
bool ShouldLog(spdlog::level::level_enum log_level);
@@ -93,6 +99,38 @@ std::string LoggerImpl<TLoggerPolicy>::GetLogPath(const std::string& file_name_s
9399
return path;
94100
}
95101

102+
template <typename TLoggerPolicy>
103+
std::shared_ptr<spdlog::logger> LoggerImpl<TLoggerPolicy>::CreateFileSink(std::string logger_name)
104+
{
105+
static auto current_process_name = ToString(GetCurrentProcessName());
106+
static auto current_process_id = GetPID();
107+
static auto current_process_without_extension =
108+
current_process_name.substr(0, current_process_name.find_last_of("."));
109+
110+
static auto file_name_suffix =
111+
std::to_string(current_process_id) + "-" + current_process_without_extension + "-Native";
112+
113+
// by default, use the same size as on managed side: 10MiB
114+
static auto file_size = GetConfiguredSize(environment::max_log_file_size, 10485760);
115+
116+
static std::shared_ptr<spdlog::logger> fileout;
117+
118+
try
119+
{
120+
fileout = spdlog::rotating_logger_mt(logger_name, GetLogPath(file_name_suffix), file_size, 10);
121+
}
122+
catch (...)
123+
{
124+
// By writing into the stderr was changing the behavior in a CI scenario.
125+
// There's not a good way to report errors when trying to create the log file.
126+
// But we never should be changing the normal behavior of an app.
127+
// std::cerr << "LoggerImpl Handler: Error creating native log file." << std::endl;
128+
fileout = spdlog::null_logger_mt(logger_name);
129+
}
130+
131+
return fileout;
132+
}
133+
96134
template <typename TLoggerPolicy>
97135
LoggerImpl<TLoggerPolicy>::LoggerImpl()
98136
{
@@ -131,28 +169,22 @@ LoggerImpl<TLoggerPolicy>::LoggerImpl()
131169

132170
spdlog::flush_every(std::chrono::seconds(3));
133171

134-
static auto current_process_name = ToString(GetCurrentProcessName());
135-
static auto current_process_id = GetPID();
136-
static auto current_process_without_extension =
137-
current_process_name.substr(0, current_process_name.find_last_of("."));
172+
static auto configured_log_sink = GetEnvironmentValue(environment::log_sink);
138173

139-
static auto file_name_suffix =
140-
std::to_string(current_process_id) + "-" + current_process_without_extension + "-Native";
141-
142-
// by default, use the same size as on managed side: 10MiB
143-
static auto file_size = GetConfiguredSize(environment::max_log_file_size, 10485760);
144-
145-
try
174+
if (configured_log_sink == log_sink_none)
146175
{
147-
m_fileout = spdlog::rotating_logger_mt(logger_name, GetLogPath(file_name_suffix), file_size, 10);
176+
m_fileout = spdlog::null_logger_mt(logger_name);
177+
return;
148178
}
149-
catch (...)
179+
else if (configured_log_sink == log_sink_console)
150180
{
151-
// By writing into the stderr was changing the behavior in a CI scenario.
152-
// There's not a good way to report errors when trying to create the log file.
153-
// But we never should be changing the normal behavior of an app.
154-
// std::cerr << "LoggerImpl Handler: Error creating native log file." << std::endl;
155-
m_fileout = spdlog::null_logger_mt(logger_name);
181+
m_fileout = spdlog::stdout_logger_mt(logger_name);
182+
}
183+
// Default to file sink
184+
else
185+
{
186+
// Creates file sink, if file sink creation fails fallbacks to NoOp sink.
187+
m_fileout = CreateFileSink(logger_name);
156188
}
157189

158190
m_fileout->set_level(log_level);
@@ -237,7 +269,7 @@ void LoggerImpl<TLoggerPolicy>::Error(const Args&... args)
237269
}
238270

239271
template <typename TLoggerPolicy>
240-
template< typename... Args>
272+
template <typename... Args>
241273
void LoggerImpl<TLoggerPolicy>::Critical(const Args&... args)
242274
{
243275
// to avoid possibly unnecessary LogToString conversion, check log level before calling underlying logger
@@ -259,13 +291,12 @@ void LoggerImpl<TLoggerPolicy>::Flush()
259291
m_fileout->flush();
260292
}
261293

262-
263294
template <typename TLoggerPolicy>
264295
bool LoggerImpl<TLoggerPolicy>::IsDebugEnabled() const
265296
{
266297
return m_fileout->level() == spdlog::level::debug;
267298
}
268299

269-
} // namespace shared
300+
} // namespace trace
270301

271302
#endif // OTEL_CLR_PROFILER_LOGGER_IMPL_H_

src/OpenTelemetry.AutoInstrumentation.StartupHook/OpenTelemetry.AutoInstrumentation.StartupHook.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\NoopLogger.cs">
1717
<Link>Logging\NoopLogger.cs</Link>
1818
</Compile>
19+
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\ConsoleSink.cs">
20+
<Link>Logging\ConsoleSink.cs</Link>
21+
</Compile>
1922
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\FileSink.cs">
2023
<Link>Logging\FileSink.cs</Link>
2124
</Compile>
@@ -43,6 +46,9 @@
4346
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\LogLevel.cs">
4447
<Link>Logging\LogLevel.cs</Link>
4548
</Compile>
49+
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\LogSink.cs">
50+
<Link>Logging\LogSink.cs</Link>
51+
</Compile>
4652
<Compile Include="..\OpenTelemetry.AutoInstrumentation\Logging\NoopSink.cs">
4753
<Link>Logging\NoopSink.cs</Link>
4854
</Compile>

src/OpenTelemetry.AutoInstrumentation/Constants.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ public static class LogLevel
6363
public const string Information = "info";
6464
public const string Debug = "debug";
6565
}
66+
67+
public static class Loggers
68+
{
69+
public const string File = "file";
70+
public const string Console = "console";
71+
}
6672
}
6773

6874
public static class EnvironmentVariables
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
namespace OpenTelemetry.AutoInstrumentation.Logging;
5+
6+
internal class ConsoleSink : ISink
7+
{
8+
private readonly string _source;
9+
10+
public ConsoleSink(string source)
11+
{
12+
_source = source;
13+
}
14+
15+
public void Write(string message)
16+
{
17+
Console.WriteLine($"[{_source}] {message}");
18+
}
19+
}

src/OpenTelemetry.AutoInstrumentation/Logging/IOtelLogger.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace OpenTelemetry.AutoInstrumentation.Logging;
55

6-
internal interface IOtelLogger
6+
internal interface IOtelLogger : IDisposable
77
{
88
LogLevel Level { get; }
99

src/OpenTelemetry.AutoInstrumentation/Logging/InternalLogger.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ public void Error<T0, T1, T2>(Exception exception, string messageTemplate, T0 pr
142142
public void Error(Exception exception, string messageTemplate, object[] args, bool writeToEventLog)
143143
=> Write(LogLevel.Error, exception, messageTemplate, args, writeToEventLog);
144144

145+
public void Dispose()
146+
{
147+
if (_sink is IDisposable disposableSink)
148+
{
149+
disposableSink.Dispose();
150+
}
151+
}
152+
145153
private static void WriteEventSourceLog(LogLevel level, string message)
146154
{
147155
switch (level)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
namespace OpenTelemetry.AutoInstrumentation.Logging;
5+
6+
/// <summary>
7+
/// Specifies the target sink.
8+
/// </summary>
9+
internal enum LogSink
10+
{
11+
/// <summary>
12+
/// File sink.
13+
/// </summary>
14+
File,
15+
16+
/// <summary>
17+
/// Std out or Console sink.
18+
/// </summary>
19+
Console,
20+
21+
/// <summary>
22+
/// No op sink or null sink.
23+
/// </summary>
24+
NoOp
25+
}

src/OpenTelemetry.AutoInstrumentation/Logging/NoopLogger.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,8 @@ public void Error<T0, T1, T2>(Exception exception, string messageTemplate, T0 pr
180180
public void Error(Exception exception, string messageTemplate, object[] args, bool writeToEventLog = true)
181181
{
182182
}
183+
184+
public void Dispose()
185+
{
186+
}
183187
}

0 commit comments

Comments
 (0)