diff --git a/src/Elastic.CommonSchema.NLog/EcsLayout.cs b/src/Elastic.CommonSchema.NLog/EcsLayout.cs
index f2117f0a..2345d318 100644
--- a/src/Elastic.CommonSchema.NLog/EcsLayout.cs
+++ b/src/Elastic.CommonSchema.NLog/EcsLayout.cs
@@ -19,7 +19,7 @@ namespace Elastic.CommonSchema.NLog
internal class NlogEcsDocumentCreationOptions : IEcsDocumentCreationOptions
{
public static NlogEcsDocumentCreationOptions Default { get; } = new();
- public bool IncludeHost { get; set; } = false;
+ public bool IncludeHost { get; set; } = true;
public bool IncludeProcess { get; set; } = false;
public bool IncludeUser { get; set; } = false;
public bool IncludeActivityData { get; set; } = false;
@@ -33,9 +33,13 @@ public class EcsLayout : Layout
{
/// An NLOG layout implementation that renders logs as ECS json
public const string Name = nameof(EcsLayout);
-
private static bool? _nlogApmLoaded;
private static Agent _defaultAgent;
+ private Agent _previousAgent;
+ private Service _previousService;
+ private Host _previousHost;
+ private Server _previousServer;
+ private Process _previousProcess;
private static bool NLogApmLoaded()
{
@@ -160,6 +164,8 @@ private static bool NLogWeb4Registered() =>
public Layout ApmServiceNodeName { get; set; }
///
public Layout ApmServiceVersion { get; set; }
+ ///
+ public Layout ServiceEnvironment { get; set; }
///
public Layout LogOriginCallSiteMethod { get; set; }
@@ -237,6 +243,8 @@ private static bool NLogWeb4Registered() =>
///
public Layout ServerAddress { get; set; }
+ ///
+ public Layout ServerDomain { get; set; }
///
public Layout ServerIp { get; set; }
///
@@ -302,10 +310,10 @@ public NLogEcsDocument RenderEcsDocument(LogEventInfo logEvent)
SetApmTransactionId(ecsEvent, logEvent);
SetApmSpanId(ecsEvent, logEvent);
- // prefer setting service information set by Elastic APM
- var service = GetService(logEvent);
- if (service != null)
- ecsEvent.Service = service;
+ ecsEvent.Agent = GetAgent(logEvent, _defaultAgent);
+ ecsEvent.Service = GetService(logEvent, ecsEvent.Service);
+ ecsEvent.Host = GetHost(logEvent, ecsEvent.Host);
+ ecsEvent.Server = GetServer(logEvent, ecsEvent.Server);
ecsEvent.Message = logEvent.FormattedMessage;
ecsEvent.Log = GetLog(logEvent);
@@ -313,9 +321,6 @@ public NLogEcsDocument RenderEcsDocument(LogEventInfo logEvent)
ecsEvent.Process = GetProcess(logEvent);
ecsEvent.Tags = GetTags(logEvent);
ecsEvent.Labels = GetLabels(logEvent);
- ecsEvent.Agent = GetAgent(logEvent) ?? _defaultAgent;
- ecsEvent.Server = GetServer(logEvent);
- ecsEvent.Host = GetHost(logEvent);
ecsEvent.Http = GetHttp(logEvent);
ecsEvent.Url = GetUrl(logEvent);
@@ -337,16 +342,6 @@ public NLogEcsDocument RenderEcsDocument(LogEventInfo logEvent)
return ecsEvent;
}
- private Service GetService(LogEventInfo logEventInfo)
- {
- var serviceName = ApmServiceName?.Render(logEventInfo);
- if (string.IsNullOrEmpty(serviceName)) return null;
-
- var serviceNodeName = ApmServiceNodeName?.Render(logEventInfo);
- var serviceVersion = ApmServiceVersion?.Render(logEventInfo);
- return new Service { Name = serviceName, Version = serviceVersion, NodeName = serviceNodeName };
- }
-
///
/// Override to supplement the ECS event parsing
///
@@ -547,27 +542,28 @@ private Event GetEvent(LogEventInfo logEventInfo)
return evnt;
}
- private Agent GetAgent(LogEventInfo logEventInfo)
+ private Agent GetAgent(LogEventInfo logEventInfo, Agent defaultAgent)
{
var agentId = AgentId?.Render(logEventInfo);
var agentName = AgentName?.Render(logEventInfo);
var agentType = AgentType?.Render(logEventInfo);
var agentVersion = AgentVersion?.Render(logEventInfo);
- if (string.IsNullOrEmpty(agentId)
- && string.IsNullOrEmpty(agentName)
- && string.IsNullOrEmpty(agentType)
- && string.IsNullOrEmpty(agentVersion))
- return null;
+ var previousAgent = _previousAgent ?? defaultAgent;
+ if ((string.IsNullOrEmpty(agentId) || agentId == previousAgent?.Id)
+ && (string.IsNullOrEmpty(agentName) || agentName == previousAgent?.Name)
+ && (string.IsNullOrEmpty(agentType) || agentType == previousAgent?.Type)
+ && (string.IsNullOrEmpty(agentVersion) || agentVersion == previousAgent?.Version))
+ return previousAgent;
var agent = new Agent
{
- Id = agentId,
- Name = agentName,
- Type = agentType,
- Version = agentVersion
+ Id = string.IsNullOrEmpty(agentId) ? previousAgent?.Id : agentId,
+ Name = string.IsNullOrEmpty(agentName) ? previousAgent?.Name : agentName,
+ Type = string.IsNullOrEmpty(agentType) ? previousAgent?.Type : agentType,
+ Version = string.IsNullOrEmpty(agentVersion) ? previousAgent?.Version : agentVersion,
};
-
+ _previousAgent = agent;
return agent;
}
@@ -580,41 +576,115 @@ private Process GetProcess(LogEventInfo logEventInfo)
var processThreadId = ProcessThreadId?.Render(logEventInfo);
var processThreadName = ProcessThreadName?.Render(logEventInfo);
- if (string.IsNullOrEmpty(processId)
- && string.IsNullOrEmpty(processName)
- && string.IsNullOrEmpty(processTitle)
- && string.IsNullOrEmpty(processExecutable)
- && string.IsNullOrEmpty(processThreadId)
- && string.IsNullOrEmpty(processThreadName))
- return null;
+ if (!string.IsNullOrEmpty(processThreadId) || !string.IsNullOrEmpty(processThreadName))
+ {
+ return new Process
+ {
+ Title = processTitle,
+ Name = processName,
+ Executable = processExecutable,
+ Pid = !string.IsNullOrEmpty(processId) ? long.Parse(processId) : null,
+ ThreadId = !string.IsNullOrEmpty(processThreadId) ? long.Parse(processThreadId) : null,
+ ThreadName = !string.IsNullOrEmpty(processThreadName) ? processThreadName : null,
+ };
+ }
+
+ // Only attempt to reuse Process-object when not including Thread-details
+ var previousProcess = _previousProcess;
+ if ( (string.IsNullOrEmpty(processTitle) || processTitle == previousProcess?.Title)
+ && (string.IsNullOrEmpty(processName) || processName == previousProcess?.Name)
+ && (string.IsNullOrEmpty(processId) || long.Parse(processId) == previousProcess?.Pid)
+ && (string.IsNullOrEmpty(processExecutable) || processExecutable == previousProcess?.Executable))
+ return previousProcess;
- return new Process
+ var process = new Process
{
- Title = processTitle,
- Name = processName,
- Pid = !string.IsNullOrEmpty(processId) ? long.Parse(processId) : null,
- Executable = processExecutable,
- ThreadId = !string.IsNullOrEmpty(processThreadId) ? long.Parse(processThreadId) : null,
- ThreadName = !string.IsNullOrEmpty(processThreadName) ? processThreadName : null,
+ Title = string.IsNullOrEmpty(processTitle) ? previousProcess?.Title : processTitle,
+ Name = string.IsNullOrEmpty(processName) ? previousProcess?.Name : processName,
+ Executable = string.IsNullOrEmpty(processExecutable) ? previousProcess?.Executable : processExecutable,
+ Pid = string.IsNullOrEmpty(processId) ? previousProcess?.Pid : long.Parse(processId),
};
+ _previousProcess = process;
+ return process;
}
- private Server GetServer(LogEventInfo logEventInfo)
+ private Server GetServer(LogEventInfo logEventInfo, Server defaultServer)
{
var serverUser = ServerUser?.Render(logEventInfo);
var serverAddress = ServerAddress?.Render(logEventInfo);
+ var serverDomain = ServerDomain?.Render(logEventInfo);
var serverIp = ServerIp?.Render(logEventInfo);
- if (string.IsNullOrEmpty(serverUser) && string.IsNullOrEmpty(serverAddress) && string.IsNullOrEmpty(serverIp))
- return null;
- return new Server
+ var previousServer = _previousServer ?? defaultServer;
+ if ((string.IsNullOrEmpty(serverUser) || serverUser == previousServer?.User?.Name)
+ && (string.IsNullOrEmpty(serverAddress) || serverAddress == previousServer?.Address)
+ && (string.IsNullOrEmpty(serverDomain) || serverDomain == previousServer?.Domain)
+ && (string.IsNullOrEmpty(serverIp) || serverIp == previousServer?.Ip))
+ return previousServer;
+
+ var server = new Server
{
- User = !string.IsNullOrEmpty(serverUser)
- ? new User { Name = serverUser }
- : null,
- Address = serverAddress,
- Ip = serverIp
+ User = string.IsNullOrEmpty(serverUser) ? previousServer?.User : new User() { Name = serverUser },
+ Address = string.IsNullOrEmpty(serverAddress) ? previousServer?.Address : serverAddress,
+ Domain = string.IsNullOrEmpty(serverDomain) ? previousServer?.Domain : serverDomain,
+ Ip = string.IsNullOrEmpty(serverIp) ? previousServer?.Ip : serverIp,
};
+ _previousServer = server;
+ return server;
+ }
+
+ private Service GetService(LogEventInfo logEventInfo, Service defaultService)
+ {
+ var serviceName = ApmServiceName?.Render(logEventInfo);
+ if (string.IsNullOrEmpty(serviceName))
+ return defaultService;
+
+ var serviceNodeName = ApmServiceNodeName?.Render(logEventInfo);
+ var serviceVersion = ApmServiceVersion?.Render(logEventInfo);
+ var serviceEnvironment = ServiceEnvironment?.Render(logEventInfo);
+
+ var previousService = _previousService ?? defaultService;
+ if ( (string.IsNullOrEmpty(serviceName) || serviceName == previousService?.Name)
+ && (string.IsNullOrEmpty(serviceNodeName) || serviceNodeName == previousService?.NodeName)
+ && (string.IsNullOrEmpty(serviceVersion) || serviceVersion == previousService?.Version)
+ && (string.IsNullOrEmpty(serviceEnvironment) || serviceEnvironment == previousService?.Environment))
+ return previousService;
+
+ var service = new Service
+ {
+ Name = string.IsNullOrEmpty(serviceName) ? previousService?.Name : serviceName,
+ NodeName = string.IsNullOrEmpty(serviceNodeName) ? previousService?.NodeName : serviceNodeName,
+ Version = string.IsNullOrEmpty(serviceVersion) ? previousService?.Version : serviceVersion,
+ Environment = string.IsNullOrEmpty(serviceEnvironment) ? previousService?.Environment : serviceEnvironment,
+ Type = previousService?.Type,
+ };
+ _previousService = service;
+ return service;
+ }
+
+ private Host GetHost(LogEventInfo logEventInfo, Host defaultHost)
+ {
+ var hostId = HostId?.Render(logEventInfo);
+ var hostName = HostName?.Render(logEventInfo);
+ var hostIp = HostIp?.Render(logEventInfo);
+
+ var previousHost = _previousHost ?? defaultHost;
+ if ((string.IsNullOrEmpty(hostId) || hostId == previousHost?.Id)
+ && (string.IsNullOrEmpty(hostName) || hostName == previousHost?.Hostname)
+ && (string.IsNullOrEmpty(hostIp) || (previousHost?.Ip?.Length == 1 && hostIp == previousHost.Ip[0])))
+ return previousHost;
+
+ var host = new Host
+ {
+ Id = string.IsNullOrEmpty(hostId) ? previousHost?.Id : hostId,
+ Hostname = string.IsNullOrEmpty(hostName) ? previousHost?.Hostname : hostName,
+ Ip = string.IsNullOrEmpty(hostIp) ? previousHost?.Ip : new[] { hostIp },
+ Type = previousHost?.Type,
+ Architecture = previousHost?.Architecture,
+ Os = previousHost?.Os,
+ };
+ _previousHost = host;
+ return host;
}
private void SetApmTraceId(EcsDocument ecsDocument, LogEventInfo logEventInfo)
@@ -690,27 +760,6 @@ private Url GetUrl(LogEventInfo logEventInfo)
return url;
}
- private Host GetHost(LogEventInfo logEventInfo)
- {
- var hostId = HostId?.Render(logEventInfo);
- var hostName = HostName?.Render(logEventInfo);
- var hostIp = HostIp?.Render(logEventInfo);
-
- if (string.IsNullOrEmpty(hostId)
- && string.IsNullOrEmpty(hostName)
- && string.IsNullOrEmpty(hostIp))
- return null;
-
- var host = new Host
- {
- Id = string.IsNullOrEmpty(hostId) ? null : hostId,
- Name = string.IsNullOrEmpty(hostName) ? null : hostName,
- Ip = string.IsNullOrEmpty(hostIp) ? null : new[] { hostIp }
- };
-
- return host;
- }
-
private static long GetSysLogSeverity(LogLevel logLevel)
{
if (logLevel == LogLevel.Trace || logLevel == LogLevel.Debug)