diff --git a/Apps/LogExporterApp/LogExporterApp.csproj b/Apps/LogExporterApp/LogExporterApp.csproj
index 6c6107d2..16020dbf 100644
--- a/Apps/LogExporterApp/LogExporterApp.csproj
+++ b/Apps/LogExporterApp/LogExporterApp.csproj
@@ -20,7 +20,9 @@
-
+
+
+
diff --git a/Apps/LogExporterApp/Strategy/SyslogExportStrategy.cs b/Apps/LogExporterApp/Strategy/SyslogExportStrategy.cs
index a01c81c6..eee2d356 100644
--- a/Apps/LogExporterApp/Strategy/SyslogExportStrategy.cs
+++ b/Apps/LogExporterApp/Strategy/SyslogExportStrategy.cs
@@ -17,9 +17,10 @@ along with this program. If not, see .
*/
-using SyslogNet.Client;
-using SyslogNet.Client.Serialization;
-using SyslogNet.Client.Transport;
+using Serilog;
+using Serilog.Events;
+using Serilog.Parsing;
+using Serilog.Sinks.Syslog;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -33,21 +34,17 @@ namespace LogExporter.Strategy
private const string _appName = "Technitium DNS Server";
- private const string _msgId = "dnslog";
-
- private const string _sdId = "dnsparams";
+ private const string _sdId = "meta";
private const string DEFAUL_PROTOCOL = "udp";
private const int DEFAULT_PORT = 514;
- private readonly string _host;
+ private readonly Facility _facility = Facility.Local6;
- private readonly string _processId;
+ private readonly Rfc5424Formatter _formatter;
- private readonly ISyslogMessageSender _sender;
-
- private readonly ISyslogMessageSerializer _serializer;
+ private readonly Serilog.Core.Logger _sender;
private bool disposedValue;
@@ -60,18 +57,18 @@ namespace LogExporter.Strategy
port ??= DEFAULT_PORT;
protocol ??= DEFAUL_PROTOCOL;
+ var conf = new LoggerConfiguration();
+
_sender = protocol.ToLowerInvariant() switch
{
- "tls" => new SyslogEncryptedTcpSender(address, port.Value),
- "tcp" => new SyslogTcpSender(address, port.Value),
- "udp" => new SyslogUdpSender(address, port.Value),
- "local" => new SyslogLocalSender(),
+ "tls" => conf.WriteTo.TcpSyslog(address, port.Value, _appName, FramingType.OCTET_COUNTING, SyslogFormat.RFC5424, _facility, useTls: true).Enrich.FromLogContext().CreateLogger(),
+ "tcp" => conf.WriteTo.TcpSyslog(address, port.Value, _appName, FramingType.OCTET_COUNTING, SyslogFormat.RFC5424, _facility, useTls: false).Enrich.FromLogContext().CreateLogger(),
+ "udp" => conf.WriteTo.UdpSyslog(address, port.Value, _appName, SyslogFormat.RFC5424, _facility).Enrich.FromLogContext().CreateLogger(),
+ "local" => conf.WriteTo.LocalSyslog(_appName, _facility).Enrich.FromLogContext().CreateLogger(),
_ => throw new Exception("Invalid protocol specified"),
};
- _serializer = new SyslogRfc5424MessageSerializer();
- _processId = Environment.ProcessId.ToString();
- _host = Environment.MachineName;
+ _formatter = new Rfc5424Formatter(_facility, _appName, null, _sdId, Environment.MachineName);
}
#endregion constructor
@@ -80,11 +77,12 @@ namespace LogExporter.Strategy
public Task ExportAsync(List logs)
{
- return Task.Run(() =>
- {
- var messages = new List(logs.Select(Convert));
- _sender.Send(messages, _serializer);
- });
+ var tasks = logs
+ .Select(log => Task.Run(() =>
+ Log.Information(_formatter.FormatMessage(Convert(log))))
+ );
+
+ return Task.WhenAll(tasks);
}
#endregion public
@@ -115,83 +113,88 @@ namespace LogExporter.Strategy
#region private
- private SyslogMessage Convert(LogEntry log)
+ private LogEvent Convert(LogEntry log)
{
- // Create the structured data with all key details from LogEntry
- var elements = new StructuredDataElement(_sdId, new Dictionary(StringComparer.OrdinalIgnoreCase)
+ // Initialize properties with base log details
+ var properties = new List
{
- { "timestamp", log.Timestamp.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") },
- { "clientIp", log.ClientIp },
- { "clientPort", log.ClientPort.ToString() },
- { "dnssecOk", log.DnssecOk.ToString() },
- { "protocol", log.Protocol.ToString() },
- { "rCode", log.ResponseCode.ToString() }
- });
+ new LogEventProperty("timestamp", new ScalarValue(log.Timestamp.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"))),
+ new LogEventProperty("clientIp", new ScalarValue(log.ClientIp)),
+ new LogEventProperty("clientPort", new ScalarValue(log.ClientPort.ToString())),
+ new LogEventProperty("dnssecOk", new ScalarValue(log.DnssecOk.ToString())),
+ new LogEventProperty("protocol", new ScalarValue(log.Protocol.ToString())),
+ new LogEventProperty("rCode", new ScalarValue(log.ResponseCode.ToString()))
+ };
- // Add each question to the structured data
+ // Add each question as properties
if (log.Questions?.Count > 0)
{
for (int i = 0; i < log.Questions.Count; i++)
{
var question = log.Questions[i];
- elements.Parameters.Add($"qName_{i}", question.QuestionName);
- elements.Parameters.Add($"qType_{i}", question.QuestionType.HasValue ? question.QuestionType.Value.ToString() : "unknown");
- elements.Parameters.Add($"qClass_{i}", question.QuestionClass.HasValue ? question.QuestionClass.Value.ToString() : "unknown");
- elements.Parameters.Add($"qSize_{i}", question.Size.ToString());
+ properties.Add(new LogEventProperty($"qName_{i}", new ScalarValue(question.QuestionName)));
+ properties.Add(new LogEventProperty($"qType_{i}", new ScalarValue(question.QuestionType?.ToString() ?? "unknown")));
+ properties.Add(new LogEventProperty($"qClass_{i}", new ScalarValue(question.QuestionClass?.ToString() ?? "unknown")));
+ properties.Add(new LogEventProperty($"qSize_{i}", new ScalarValue(question.Size.ToString())));
}
+
+ // Generate questions summary
+ var questionSummary = string.Join("; ", log.Questions.Select((q, i) =>
+ $"QNAME_{i}: {q.QuestionName}, QTYPE: {q.QuestionType?.ToString() ?? "unknown"}, QCLASS: {q.QuestionClass?.ToString() ?? "unknown"}"));
+ properties.Add(new LogEventProperty("questionsSummary", new ScalarValue(questionSummary)));
+ }
+ else
+ {
+ properties.Add(new LogEventProperty("questionsSummary", new ScalarValue(string.Empty)));
}
- // Add each answer to the structured data
+ // Add each answer as properties
if (log.Answers?.Count > 0)
{
for (int i = 0; i < log.Answers.Count; i++)
{
var answer = log.Answers[i];
- elements.Parameters.Add($"aType_{i}", answer.RecordType.ToString());
- elements.Parameters.Add($"aData_{i}", answer.RecordData);
- elements.Parameters.Add($"aClass_{i}", answer.RecordClass.ToString());
- elements.Parameters.Add($"aTtl_{i}", answer.RecordTtl.ToString());
- elements.Parameters.Add($"aSize_{i}", answer.Size.ToString());
- elements.Parameters.Add($"aDnssecStatus_{i}", answer.DnssecStatus.ToString());
+ properties.Add(new LogEventProperty($"aType_{i}", new ScalarValue(answer.RecordType.ToString())));
+ properties.Add(new LogEventProperty($"aData_{i}", new ScalarValue(answer.RecordData)));
+ properties.Add(new LogEventProperty($"aClass_{i}", new ScalarValue(answer.RecordClass.ToString())));
+ properties.Add(new LogEventProperty($"aTtl_{i}", new ScalarValue(answer.RecordTtl.ToString())));
+ properties.Add(new LogEventProperty($"aSize_{i}", new ScalarValue(answer.Size.ToString())));
+ properties.Add(new LogEventProperty($"aDnssecStatus_{i}", new ScalarValue(answer.DnssecStatus.ToString())));
}
+
+ // Generate answers summary
+ var answerSummary = string.Join(", ", log.Answers.Select(a => a.RecordData));
+ properties.Add(new LogEventProperty("answersSummary", new ScalarValue(answerSummary)));
+ }
+ else
+ {
+ properties.Add(new LogEventProperty("answersSummary", new ScalarValue(string.Empty)));
}
- // Include request and response tags if present
+ // Add request and response tags if present
if (log.RequestTag != null)
{
- elements.Parameters.Add("requestTag", log.RequestTag.ToString());
+ properties.Add(new LogEventProperty("requestTag", new ScalarValue(log.RequestTag.ToString())));
}
if (log.ResponseTag != null)
{
- elements.Parameters.Add("responseTag", log.ResponseTag.ToString());
+ properties.Add(new LogEventProperty("responseTag", new ScalarValue(log.ResponseTag.ToString())));
}
- // Build a comprehensive message summary
- string questionSummary = log.Questions?.Count > 0
- ? string.Join("; ", log.Questions.Select(q =>
- $"QNAME: {q.QuestionName}; QTYPE: {q.QuestionType?.ToString() ?? "unknown"}; QCLASS: {q.QuestionClass?.ToString() ?? "unknown"}"))
- : string.Empty;
+ // Define the message template to match the original summary format
+ const string templateText = "{questionsSummary}; RCODE: {rCode}; ANSWER: [{answersSummary}]";
- // Build the answer summary in the desired format
- string answerSummary = log.Answers?.Count > 0
- ? string.Join(", ", log.Answers.Select(a => a.RecordData))
- : string.Empty;
+ // Parse the template
+ var template = new MessageTemplateParser().Parse(templateText);
- // Construct the message summary string to match the desired format
- string messageSummary = $"{questionSummary}; RCODE: {log.ResponseCode}; ANSWER: [{answerSummary}]";
-
- // Create and return the syslog message
- return new SyslogMessage(
- log.Timestamp,
- Facility.UserLevelMessages,
- Severity.Informational,
- _host,
- _appName,
- _processId,
- _msgId,
- messageSummary,
- elements
+ // Create the LogEvent and return it
+ return new LogEvent(
+ timestamp: log.Timestamp,
+ level: LogEventLevel.Information,
+ exception: null,
+ messageTemplate: template,
+ properties: properties
);
}