From 8edc49afb3b4305c88b5c2a5462f676f606ff8f3 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sat, 15 Jun 2019 18:24:46 +0200 Subject: [PATCH 01/10] add publishing to nuget --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index c1e25b2..bbe417d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -36,6 +36,7 @@ after_build: - cmd: ECHO nuget pack src/Log4net.Appender.InfluxDBSyslog\Log4net.Appender.InfluxDBSyslog.csproj -version "%GitVersion_NuGetVersion%" -prop "target=%CONFIGURATION%" -Symbols -SymbolPackageFormat snupkg - cmd: nuget pack src/Log4net.Appender.InfluxDBSyslog\Log4net.Appender.InfluxDBSyslog.csproj -version "%GitVersion_NuGetVersion%" -prop "target=%CONFIGURATION%" -Symbols -SymbolPackageFormat snupkg - cmd: appveyor PushArtifact "Log4net.Appender.InfluxDBSyslog.%GitVersion_NuGetVersion%.nupkg" +- cmd: nuget push "Log4net.Appender.InfluxDBSyslog.%GitVersion_NuGetVersion%.nupkg" -Source https://api.nuget.org/v3/index.json -apikey oy2bn3atl5ntmtrwa4kqxgm242ffozmulk4wg7qvm2odv4 notifications: - provider: Email to: From 5a2197fbdc4fd3a34d61111e560b8a86cf86e530 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sat, 15 Jun 2019 18:36:26 +0200 Subject: [PATCH 02/10] replace api key with a secured version --- appveyor.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index bbe417d..5c23aec 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,8 @@ environment: secure: JwKHzxmM+/3pEixMh4+ahdBP/WfaXu8ACXJc6jvs5Eo= PROJECTTOKEN: secure: 7AolUkwXviuDD/C9rN7tEQmo5FhiGR2mo/j0Xi8pSeAJO9xCv1cR/CQvCQ7mZbnB + NUGETAPIKEY: + secure: VyMyYjPUU54ViZKnHF3IR7qvhYmsYIZoVIb+YbBncXidXb0aNv4eXJ0CDItYCCjZ nuget: project_feed: true disable_publish_on_pr: true @@ -36,7 +38,7 @@ after_build: - cmd: ECHO nuget pack src/Log4net.Appender.InfluxDBSyslog\Log4net.Appender.InfluxDBSyslog.csproj -version "%GitVersion_NuGetVersion%" -prop "target=%CONFIGURATION%" -Symbols -SymbolPackageFormat snupkg - cmd: nuget pack src/Log4net.Appender.InfluxDBSyslog\Log4net.Appender.InfluxDBSyslog.csproj -version "%GitVersion_NuGetVersion%" -prop "target=%CONFIGURATION%" -Symbols -SymbolPackageFormat snupkg - cmd: appveyor PushArtifact "Log4net.Appender.InfluxDBSyslog.%GitVersion_NuGetVersion%.nupkg" -- cmd: nuget push "Log4net.Appender.InfluxDBSyslog.%GitVersion_NuGetVersion%.nupkg" -Source https://api.nuget.org/v3/index.json -apikey oy2bn3atl5ntmtrwa4kqxgm242ffozmulk4wg7qvm2odv4 +- ps: nuget push "Log4net.Appender.InfluxDBSyslog.%GitVersion_NuGetVersion%.nupkg" -Source https://api.nuget.org/v3/index.json -apikey $env:NUGETAPIKEY notifications: - provider: Email to: From f6ac9c10382b0d1eb0a4dc86d505174cc675e01a Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sat, 15 Jun 2019 23:21:55 +0200 Subject: [PATCH 03/10] first kind of working hardcoded version --- ...net.Appender.InfluxDBSyslog.Console.csproj | 14 +++++ .../Program.cs | 18 +++++-- .../log4net.config | 23 ++++++++ ...g4net.Appender.InfluxDBSyslog.Tests.csproj | 14 +++-- .../UnitTest1.cs | 52 ++++++++++++++++++- .../InfluxAppender.cs | 40 ++++++++++++-- .../Log4net.Appender.InfluxDBSyslog.csproj | 5 +- .../Log4net.Appender.InfluxDBSyslog.nuspec | 5 +- 8 files changed, 159 insertions(+), 12 deletions(-) create mode 100644 Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config diff --git a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj index 23df604..b9376e6 100644 --- a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj +++ b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj @@ -5,4 +5,18 @@ netcoreapp2.1 + + + + + + + PreserveNewest + + + + + + + diff --git a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Program.cs b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Program.cs index a809851..adde591 100644 --- a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Program.cs +++ b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Program.cs @@ -1,12 +1,24 @@ -using System; +using log4net; +using log4net.Config; +using System; +using System.Reflection; -namespace Log4net.Appender.InfluxDBSyslog.Console +namespace Log4net.Appender.InfluxDBSyslog.ConsoleTest { class Program { + private static readonly ILog log = LogManager.GetLogger(typeof(Program)); static void Main(string[] args) { - System.Console.WriteLine("Hello World!"); + // Set up a simple configuration that logs on the console. + // Thanks Stackify https://stackify.com/making-log4net-net-core-work/ + var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); + XmlConfigurator.Configure(logRepository, new System.IO.FileInfo("log4net.config")); + //BasicConfigurator.Configure(logRepository); + Console.WriteLine("Hello World!"); + log.Error("Hello Console"); + Console.WriteLine("Press any key to exit"); + Console.ReadKey(); } } } diff --git a/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config b/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config new file mode 100644 index 0000000..0247feb --- /dev/null +++ b/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config @@ -0,0 +1,23 @@ + + + +
+ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj b/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj index 4ec64e7..b5f1fcb 100644 --- a/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj +++ b/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj @@ -7,9 +7,17 @@ - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs b/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs index 7cb9ea4..c8043ac 100644 --- a/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs +++ b/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs @@ -1,13 +1,63 @@ +using log4net; +using log4net.Appender; +using log4net.Config; +using log4net.Layout; +using Moq; using System; +using System.Reflection; using Xunit; namespace Log4net.Appender.InfluxDBSyslog.Test { public class UnitTest1 { + private static InfluxAppender _appender; + private static ILog _log; + + public UnitTest1() + { + CreateAppender(); + } + static void CreateAppender() + { + var layout = new PatternLayout("%.255message"); + layout.ActivateOptions(); + + var appender = new InfluxAppender() + { + Name = "InfluxAppender", + Host = "http://localhost:8086" + }; + appender.ActivateOptions(); + + var diagAppender = new TraceAppender + { + Layout = layout, + Name = "InfluxAppenderDiagLogger", + }; + diagAppender.ActivateOptions(); + + var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); + BasicConfigurator.Configure(logRepository, diagAppender, appender); + + _appender = appender; + _log = LogManager.GetLogger(typeof(InfluxAppender)); + } + [Fact] - public void Test1() + public void AppendTest() { + // Arrange + Mock mock = new Mock() { CallBase = true }; + var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); + mock.Object.Host = "http://localhost:8086"; + BasicConfigurator.Configure(logRepository, mock.Object); + + var log = LogManager.GetLogger(typeof(InfluxAppender)); + // Act + log.Info("message"); + + //Assert Assert.True(true); } } diff --git a/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs b/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs index a774e78..db71a3a 100644 --- a/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs +++ b/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs @@ -1,18 +1,52 @@ -using log4net.Appender; +using InfluxData.Net.InfluxDb.Infrastructure; +using log4net.Appender; using log4net.Core; using System; +using System.Collections.Generic; namespace Log4net.Appender.InfluxDBSyslog { public class InfluxAppender : AppenderSkeleton { + public string Host { get; set; } public InfluxAppender() { + } - protected override void Append(LoggingEvent loggingEvent) + protected override async void Append(LoggingEvent loggingEvent) { - throw new NotImplementedException(); + InfluxDbClientConfiguration config = new InfluxDbClientConfiguration( + new Uri(Host), + string.Empty, + string.Empty, + InfluxData.Net.Common.Enums.InfluxDbVersion.Latest); + InfluxData.Net.InfluxDb.InfluxDbClient client = new InfluxData.Net.InfluxDb.InfluxDbClient(config); + + var fields = new Dictionary(); + fields.Add("facility_code", 14); + fields.Add("message", loggingEvent.MessageObject); + fields.Add("procid", "1234"); + fields.Add("severity_code", 2); + fields.Add("timestamp", DateTimeOffset.Now.ToUnixTimeMilliseconds() * 1000000); + fields.Add("version", 1); + + var tags = new Dictionary(); + tags.Add("appname", "testapp1"); + tags.Add("facility", "console"); + tags.Add("host", "testhost"); + tags.Add("hostname", "testhost"); + tags.Add("severity", "crit"); + var x = await client.Client.WriteAsync(new InfluxData.Net.InfluxDb.Models.Point() + { + Name = "syslog", + Fields = fields, + Tags = tags, + Timestamp = DateTimeOffset.Now.UtcDateTime + }, "_internal" + ); + + var body = x.Body; } } } diff --git a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj index 1344c23..b2c59ad 100644 --- a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj +++ b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj @@ -7,11 +7,14 @@ Zither IT Log4net appender that posts events to InfluxDB in Syslog format Copyright © 2019 Mark Burton + https://github.com/MarkZither/Log4net.Appender.InfluxDBSyslog + https://github.com/MarkZither/Log4net.Appender.InfluxDBSyslog + true - + diff --git a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.nuspec b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.nuspec index e7c5b19..0d72140 100644 --- a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.nuspec +++ b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.nuspec @@ -10,6 +10,9 @@ $description$ Summary of changes made in this release of the package. Copyright 2019 - Tag1 Tag2 + Log4net InfluxDB syslog + + + \ No newline at end of file From af7cfe379be2b2201ceb59c8c7563c6ee82e7086 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sat, 15 Jun 2019 23:33:02 +0200 Subject: [PATCH 04/10] fix the console sample --- .../Log4net.Appender.InfluxDBSyslog.Console.csproj | 2 +- Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config | 1 + .../Log4net.Appender.InfluxDBSyslog.csproj | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj index b9376e6..f5c7250 100644 --- a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj +++ b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj @@ -16,7 +16,7 @@ - + diff --git a/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config b/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config index 0247feb..eb62c46 100644 --- a/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config +++ b/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config @@ -10,6 +10,7 @@ + http://localhost:8086 diff --git a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj index b2c59ad..e9ee4c0 100644 --- a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj +++ b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj @@ -10,6 +10,7 @@ https://github.com/MarkZither/Log4net.Appender.InfluxDBSyslog https://github.com/MarkZither/Log4net.Appender.InfluxDBSyslog true + 0.1.0-alpha10 From 205cbfb8ccc37abffe0381a8ed068f85c320588c Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sat, 15 Jun 2019 23:37:16 +0200 Subject: [PATCH 05/10] wildcard the version of the nuget package in the console sample --- .../Log4net.Appender.InfluxDBSyslog.Console.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj index f5c7250..5ee811d 100644 --- a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj +++ b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj @@ -1,4 +1,4 @@ - + Exe @@ -16,7 +16,7 @@ - + From 4169204024708ffaf8aca4cee01a76c301c8b098 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sat, 15 Jun 2019 23:47:30 +0200 Subject: [PATCH 06/10] don't create nuget package on build in debug --- Log4net.Appender.InfluxDBSyslog.sln | 7 +++++++ .../Log4net.Appender.InfluxDBSyslog.Console.csproj | 1 + .../Log4net.Appender.InfluxDBSyslog.Tests.csproj | 2 ++ .../Log4net.Appender.InfluxDBSyslog.csproj | 3 ++- 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Log4net.Appender.InfluxDBSyslog.sln b/Log4net.Appender.InfluxDBSyslog.sln index 88dea16..fd10717 100644 --- a/Log4net.Appender.InfluxDBSyslog.sln +++ b/Log4net.Appender.InfluxDBSyslog.sln @@ -20,19 +20,26 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + DebugWithPackageGeneration|Any CPU = DebugWithPackageGeneration|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {FFAC394B-DD5C-4220-B780-0DB02CBEF935}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FFAC394B-DD5C-4220-B780-0DB02CBEF935}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FFAC394B-DD5C-4220-B780-0DB02CBEF935}.DebugWithPackageGeneration|Any CPU.ActiveCfg = DebugWithPackageGeneration|Any CPU + {FFAC394B-DD5C-4220-B780-0DB02CBEF935}.DebugWithPackageGeneration|Any CPU.Build.0 = DebugWithPackageGeneration|Any CPU {FFAC394B-DD5C-4220-B780-0DB02CBEF935}.Release|Any CPU.ActiveCfg = Release|Any CPU {FFAC394B-DD5C-4220-B780-0DB02CBEF935}.Release|Any CPU.Build.0 = Release|Any CPU {9D0AB22A-83B3-4513-8A86-B3C270905FDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9D0AB22A-83B3-4513-8A86-B3C270905FDC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D0AB22A-83B3-4513-8A86-B3C270905FDC}.DebugWithPackageGeneration|Any CPU.ActiveCfg = DebugWithPackageGeneration|Any CPU + {9D0AB22A-83B3-4513-8A86-B3C270905FDC}.DebugWithPackageGeneration|Any CPU.Build.0 = DebugWithPackageGeneration|Any CPU {9D0AB22A-83B3-4513-8A86-B3C270905FDC}.Release|Any CPU.ActiveCfg = Release|Any CPU {9D0AB22A-83B3-4513-8A86-B3C270905FDC}.Release|Any CPU.Build.0 = Release|Any CPU {49B6AB83-E106-4493-86DF-A59B5E77FAB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {49B6AB83-E106-4493-86DF-A59B5E77FAB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {49B6AB83-E106-4493-86DF-A59B5E77FAB3}.DebugWithPackageGeneration|Any CPU.ActiveCfg = DebugWithPackageGeneration|Any CPU + {49B6AB83-E106-4493-86DF-A59B5E77FAB3}.DebugWithPackageGeneration|Any CPU.Build.0 = DebugWithPackageGeneration|Any CPU {49B6AB83-E106-4493-86DF-A59B5E77FAB3}.Release|Any CPU.ActiveCfg = Release|Any CPU {49B6AB83-E106-4493-86DF-A59B5E77FAB3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection diff --git a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj index 5ee811d..98372b5 100644 --- a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj +++ b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj @@ -3,6 +3,7 @@ Exe netcoreapp2.1 + Debug;Release;DebugWithPackageGeneration diff --git a/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj b/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj index b5f1fcb..f65e184 100644 --- a/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj +++ b/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj @@ -4,6 +4,8 @@ netcoreapp2.1 false + + Debug;Release;DebugWithPackageGeneration diff --git a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj index e9ee4c0..09be064 100644 --- a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj +++ b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj @@ -9,8 +9,9 @@ Copyright © 2019 Mark Burton https://github.com/MarkZither/Log4net.Appender.InfluxDBSyslog https://github.com/MarkZither/Log4net.Appender.InfluxDBSyslog - true + false 0.1.0-alpha10 + Debug;Release;DebugWithPackageGeneration From 77b84fb6f64bebe501252aacd24d4caa9d6db143 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sun, 16 Jun 2019 09:20:54 +0200 Subject: [PATCH 07/10] make nuget pack conditional --- .../Log4net.Appender.InfluxDBSyslog.Console.csproj | 4 +++- .../Log4net.Appender.InfluxDBSyslog.csproj | 10 +++++++--- .../Log4net.Appender.InfluxDBSyslog.nuspec | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj index 98372b5..f27aa4f 100644 --- a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj +++ b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Log4net.Appender.InfluxDBSyslog.Console.csproj @@ -4,6 +4,8 @@ Exe netcoreapp2.1 Debug;Release;DebugWithPackageGeneration + true + 0.1.0-alpha14 @@ -17,7 +19,7 @@ - + diff --git a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj index 09be064..395bcbd 100644 --- a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj +++ b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.csproj @@ -8,12 +8,16 @@ Log4net appender that posts events to InfluxDB in Syslog format Copyright © 2019 Mark Burton https://github.com/MarkZither/Log4net.Appender.InfluxDBSyslog - https://github.com/MarkZither/Log4net.Appender.InfluxDBSyslog - false + 0.1.0-alpha10 Debug;Release;DebugWithPackageGeneration + Log4net InfluxDB syslog - + + + true + + diff --git a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.nuspec b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.nuspec index 0d72140..3cbe52a 100644 --- a/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.nuspec +++ b/src/Log4net.Appender.InfluxDBSyslog/Log4net.Appender.InfluxDBSyslog.nuspec @@ -12,6 +12,7 @@ Copyright 2019 Log4net InfluxDB syslog + From 7643bfa91275616b1cb4f7b734cc56df8ba14c0b Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sun, 16 Jun 2019 10:12:26 +0200 Subject: [PATCH 08/10] make nuget push ps for secure env vars --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 5c23aec..5d9c509 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,7 +38,7 @@ after_build: - cmd: ECHO nuget pack src/Log4net.Appender.InfluxDBSyslog\Log4net.Appender.InfluxDBSyslog.csproj -version "%GitVersion_NuGetVersion%" -prop "target=%CONFIGURATION%" -Symbols -SymbolPackageFormat snupkg - cmd: nuget pack src/Log4net.Appender.InfluxDBSyslog\Log4net.Appender.InfluxDBSyslog.csproj -version "%GitVersion_NuGetVersion%" -prop "target=%CONFIGURATION%" -Symbols -SymbolPackageFormat snupkg - cmd: appveyor PushArtifact "Log4net.Appender.InfluxDBSyslog.%GitVersion_NuGetVersion%.nupkg" -- ps: nuget push "Log4net.Appender.InfluxDBSyslog.%GitVersion_NuGetVersion%.nupkg" -Source https://api.nuget.org/v3/index.json -apikey $env:NUGETAPIKEY +- ps: nuget push "Log4net.Appender.InfluxDBSyslog.$env:GitVersion_NuGetVersion.nupkg" -Source https://api.nuget.org/v3/index.json -apikey $env:NUGETAPIKEY notifications: - provider: Email to: From 06c844e2a621384318ffba1fe0d0862f0aceb42d Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sun, 16 Jun 2019 13:59:34 +0200 Subject: [PATCH 09/10] mock the test on appveyor --- ...g4net.Appender.InfluxDBSyslog.Tests.csproj | 2 + .../UnitTest1.cs | 63 ++++++++++++++++++- .../InfluxAppender.cs | 12 +++- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj b/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj index f65e184..234f064 100644 --- a/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj +++ b/Test/Log4net.Appender.InfluxDBSyslog.Tests/Log4net.Appender.InfluxDBSyslog.Tests.csproj @@ -11,11 +11,13 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs b/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs index c8043ac..55b1784 100644 --- a/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs +++ b/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs @@ -3,8 +3,12 @@ using log4net.Config; using log4net.Layout; using Moq; +using RichardSzalay.MockHttp; using System; +using System.Net; +using System.Net.Http; using System.Reflection; +using System.Threading; using Xunit; namespace Log4net.Appender.InfluxDBSyslog.Test @@ -13,11 +17,13 @@ public class UnitTest1 { private static InfluxAppender _appender; private static ILog _log; + private HttpClient _client; public UnitTest1() { CreateAppender(); } + static void CreateAppender() { var layout = new PatternLayout("%.255message"); @@ -38,19 +44,70 @@ static void CreateAppender() diagAppender.ActivateOptions(); var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); - BasicConfigurator.Configure(logRepository, diagAppender, appender); + BasicConfigurator.Configure(logRepository, diagAppender); _appender = appender; _log = LogManager.GetLogger(typeof(InfluxAppender)); } [Fact] - public void AppendTest() + public void AppendIntegrationTest() { - // Arrange + // Arrange + var callbackExecuted = false; + var json = @"{ + ""data"": [ + {}"; + Mock mock = new Mock() { CallBase = true }; + mock.Object.Host = "http://localhost:8086"; + + Action callback = new Action((requestMessage, cancellationToken) => { + Assert.Equal("http://localhost:5000/identity/api/users", requestMessage.RequestUri.AbsoluteUri); + callbackExecuted = true; + }); + + //var httpMessageHandlerMock = MockHttpMessageHandler(HttpStatusCode.OK, json, callback); + //var httpClient = new Func(() => new HttpClient(httpMessageHandlerMock.Object)); + var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); + + + BasicConfigurator.Configure(logRepository, mock.Object); + + var log = LogManager.GetLogger(typeof(InfluxAppender)); + // Act + log.Info("message"); + + //Assert + Assert.True(true); + } + + [SkippableFact] + public void AppendTest() + { + Skip.If(bool.TryParse(Environment.GetEnvironmentVariable("APPVEYOR"), out _)); + // Arrange + var callbackExecuted = false; + var json = @"{ + ""data"": [ + {}"; + + + Mock mock = new Mock() { CallBase = true }; mock.Object.Host = "http://localhost:8086"; + + Action callback = new Action((requestMessage, cancellationToken) => { + Assert.Equal("http://localhost:5000/identity/api/users", requestMessage.RequestUri.AbsoluteUri); + callbackExecuted = true; + }); + + //var httpMessageHandlerMock = MockHttpMessageHandler(HttpStatusCode.OK, json, callback); + //var httpClient = new Func(() => new HttpClient(httpMessageHandlerMock.Object)); + + var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); + + BasicConfigurator.Configure(logRepository, mock.Object); var log = LogManager.GetLogger(typeof(InfluxAppender)); diff --git a/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs b/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs index db71a3a..8bb97e2 100644 --- a/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs +++ b/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs @@ -3,15 +3,21 @@ using log4net.Core; using System; using System.Collections.Generic; +using System.Net.Http; namespace Log4net.Appender.InfluxDBSyslog { public class InfluxAppender : AppenderSkeleton { public string Host { get; set; } + private HttpClient HttpClient; public InfluxAppender() { - + HttpClient = new HttpClient(); + } + public InfluxAppender(HttpClient httpClient) + { + HttpClient = httpClient; } protected override async void Append(LoggingEvent loggingEvent) @@ -20,7 +26,9 @@ protected override async void Append(LoggingEvent loggingEvent) new Uri(Host), string.Empty, string.Empty, - InfluxData.Net.Common.Enums.InfluxDbVersion.Latest); + InfluxData.Net.Common.Enums.InfluxDbVersion.Latest, + InfluxData.Net.Common.Enums.QueryLocation.FormData, + HttpClient); InfluxData.Net.InfluxDb.InfluxDbClient client = new InfluxData.Net.InfluxDb.InfluxDbClient(config); var fields = new Dictionary(); From a5d9ffd9d3a48697cd8ef94a05c55fa72119c138 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sun, 16 Jun 2019 17:24:03 +0200 Subject: [PATCH 10/10] Add configuration to log4net.config --- Log4net.Appender.InfluxDBSyslog.sln | 1 + README.md | 69 ++++++++ .../Program.cs | 71 +++++++++ .../log4net.config | 9 +- .../UnitTest1.cs | 44 ++--- docs/img/Chronograf_Syslog_From_Log4net.png | Bin 0 -> 59570 bytes .../InfluxAppender.cs | 150 ++++++++++++++++-- .../SyslogSeverity.cs | 12 ++ 8 files changed, 302 insertions(+), 54 deletions(-) create mode 100644 docs/img/Chronograf_Syslog_From_Log4net.png create mode 100644 src/Log4net.Appender.InfluxDBSyslog/SyslogSeverity.cs diff --git a/Log4net.Appender.InfluxDBSyslog.sln b/Log4net.Appender.InfluxDBSyslog.sln index fd10717..667cbba 100644 --- a/Log4net.Appender.InfluxDBSyslog.sln +++ b/Log4net.Appender.InfluxDBSyslog.sln @@ -15,6 +15,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .gitignore = .gitignore appveyor.yml = appveyor.yml directory.build.targets = directory.build.targets + README.md = README.md EndProjectSection EndProject Global diff --git a/README.md b/README.md index 75708f6..1fcfe22 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,74 @@ # Log4net.Appender.InfluxDBSyslog Log4net appender that posts events to InfluxDB in Syslog format +| Branch | Status | +| -------- | -------------- | +|Master Branch|[![Build status](https://ci.appveyor.com/api/projects/status/dvouxggnqka0ptso/branch/master?svg=true)](https://ci.appveyor.com/project/MarkZither/Log4net.Appender.InfluxDBSyslog/branch/master)| +|Dev Branch|[![Build status](https://ci.appveyor.com/api/projects/status/dvouxggnqka0ptso/branch/dev?svg=true)](https://ci.appveyor.com/project/MarkZither/Log4net.Appender.InfluxDBSyslog/branch/dev)| + +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Log4net.Appender.InfluxDBSyslog&metric=alert_status)](https://sonarcloud.io/dashboard?id=Log4net.Appender.InfluxDBSyslog) + + +## How to setup +### NuGet Package +Install from nuget +``` +PM> Install-Package Log4net.Appender.InfluxDBSyslog +``` + +or +``` +dotnet add package Log4net.Appender.InfluxDBSyslog --version 0.1.0-alpha0020 +``` + +### Configure the appender +``` xml + + + +
+ + + + http + localhost + 8086 + Console Test + Console Test Custom Facility + + + + + + + +``` + +### InfluxDB and Chronograf +Download InfluxDB 1.7 from [influxdata.com](https://portal.influxdata.com/downloads/) + +Run influxd and chronograf and see your logs flowing in. +![syslog data in Chronograf](docs/img/Chronograf_Syslog_From_Log4net.png) + +### Dependencies + + - log4net + - InfluxData.net + +### Building the project + + dotnet build + +## Contribute + +If you have any idea for an improvement or found a bug, do not hesitate to open an issue. + +## Thanks + [Get Your Syslog On](https://www.influxdata.com/blog/get-your-syslog-on/) [Writing Logs Directly to InfluxDB - DZone](https://dzone.com/articles/writing-logs-directly-to-influxdb) + + +## License + +Log4net.Appenders.Fluentd is distributed under MIT License. \ No newline at end of file diff --git a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Program.cs b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Program.cs index adde591..f3aaa2f 100644 --- a/Samples/Log4net.Appender.InfluxDBSyslog.Console/Program.cs +++ b/Samples/Log4net.Appender.InfluxDBSyslog.Console/Program.cs @@ -2,6 +2,7 @@ using log4net.Config; using System; using System.Reflection; +using System.Threading; namespace Log4net.Appender.InfluxDBSyslog.ConsoleTest { @@ -16,6 +17,76 @@ static void Main(string[] args) XmlConfigurator.Configure(logRepository, new System.IO.FileInfo("log4net.config")); //BasicConfigurator.Configure(logRepository); Console.WriteLine("Hello World!"); + log.Error("Error Console"); + log.Debug("Debug Console"); + log.Warn("Warn Console"); + log.Info("Info Console"); + Thread.Sleep(50); + log.Fatal("Fatal Console"); + log.Error("Hello Console"); + log.Error("Error Console"); + log.Debug("Debug Console"); + log.Warn("Warn Console"); + Thread.Sleep(500); + log.Info("Info Console"); + log.Fatal("Fatal Console"); + log.Error("Hello Console"); + log.Error("Error Console"); + log.Debug("Debug Console"); + log.Warn("Warn Console"); + log.Info("Info Console"); + Thread.Sleep(150); + log.Fatal("Fatal Console"); + log.Error("Hello Console"); + log.Error("Error Console"); + log.Debug("Debug Console"); + log.Warn("Warn Console"); + Thread.Sleep(450); + log.Info("Info Console"); + log.Fatal("Fatal Console"); + log.Error("Hello Console"); + log.Error("Error Console"); + log.Debug("Debug Console"); + log.Warn("Warn Console"); + Thread.Sleep(250); + log.Info("Info Console"); + log.Fatal("Fatal Console"); + log.Error("Hello Console"); + log.Error("Error Console"); + log.Debug("Debug Console"); + log.Warn("Warn Console"); + log.Info("Info Console"); + Thread.Sleep(150); + log.Fatal("Fatal Console"); + log.Error("Hello Console"); + log.Error("Error Console"); + log.Debug("Debug Console"); + log.Warn("Warn Console"); + log.Info("Info Console"); + Thread.Sleep(500); + log.Fatal("Fatal Console"); + log.Error("Hello Console"); + log.Error("Error Console"); + log.Debug("Debug Console"); + log.Warn("Warn Console"); + log.Info("Info Console"); + log.Fatal("Fatal Console"); + log.Error("Hello Console"); + Thread.Sleep(250); + log.Error("Error Console"); + log.Debug("Debug Console"); + log.Warn("Warn Console"); + log.Info("Info Console"); + log.Fatal("Fatal Console"); + Thread.Sleep(150); + log.Error("Hello Console"); + log.Error("Error Console"); + log.Debug("Debug Console"); + Thread.Sleep(750); + log.Warn("Warn Console"); + log.Info("Info Console"); + log.Fatal("Fatal Console"); + Thread.Sleep(50); log.Error("Hello Console"); Console.WriteLine("Press any key to exit"); Console.ReadKey(); diff --git a/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config b/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config index eb62c46..7c4f08b 100644 --- a/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config +++ b/Samples/Log4net.Appender.InfluxDBSyslog.Console/log4net.config @@ -10,10 +10,11 @@ - http://localhost:8086 - - - + http + localhost + 8086 + Console Test + Console Test Custom Facility diff --git a/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs b/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs index 55b1784..8eacd73 100644 --- a/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs +++ b/Test/Log4net.Appender.InfluxDBSyslog.Tests/UnitTest1.cs @@ -17,7 +17,6 @@ public class UnitTest1 { private static InfluxAppender _appender; private static ILog _log; - private HttpClient _client; public UnitTest1() { @@ -32,7 +31,7 @@ static void CreateAppender() var appender = new InfluxAppender() { Name = "InfluxAppender", - Host = "http://localhost:8086" + Host = "localhost" }; appender.ActivateOptions(); @@ -53,26 +52,15 @@ static void CreateAppender() [Fact] public void AppendIntegrationTest() { - // Arrange - var callbackExecuted = false; - var json = @"{ - ""data"": [ - {}"; - + // Arrange Mock mock = new Mock() { CallBase = true }; - mock.Object.Host = "http://localhost:8086"; - - Action callback = new Action((requestMessage, cancellationToken) => { - Assert.Equal("http://localhost:5000/identity/api/users", requestMessage.RequestUri.AbsoluteUri); - callbackExecuted = true; - }); - - //var httpMessageHandlerMock = MockHttpMessageHandler(HttpStatusCode.OK, json, callback); - //var httpClient = new Func(() => new HttpClient(httpMessageHandlerMock.Object)); + mock.Object.Host = "localhost"; + mock.Object.RemotePort = 8086; + mock.Object.Facility = "App"; + mock.Object.AppName = "MyTestApp"; var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); - BasicConfigurator.Configure(logRepository, mock.Object); var log = LogManager.GetLogger(typeof(InfluxAppender)); @@ -88,26 +76,14 @@ public void AppendTest() { Skip.If(bool.TryParse(Environment.GetEnvironmentVariable("APPVEYOR"), out _)); // Arrange - var callbackExecuted = false; - var json = @"{ - ""data"": [ - {}"; - - Mock mock = new Mock() { CallBase = true }; - mock.Object.Host = "http://localhost:8086"; - - Action callback = new Action((requestMessage, cancellationToken) => { - Assert.Equal("http://localhost:5000/identity/api/users", requestMessage.RequestUri.AbsoluteUri); - callbackExecuted = true; - }); - - //var httpMessageHandlerMock = MockHttpMessageHandler(HttpStatusCode.OK, json, callback); - //var httpClient = new Func(() => new HttpClient(httpMessageHandlerMock.Object)); + mock.Object.Host = "localhost"; + mock.Object.RemotePort = 8086; + mock.Object.Facility = "App"; + mock.Object.AppName = "MyTestApp"; var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); - BasicConfigurator.Configure(logRepository, mock.Object); var log = LogManager.GetLogger(typeof(InfluxAppender)); diff --git a/docs/img/Chronograf_Syslog_From_Log4net.png b/docs/img/Chronograf_Syslog_From_Log4net.png new file mode 100644 index 0000000000000000000000000000000000000000..8c68c601f366b422f0cbc813f7ad0065132aa43d GIT binary patch literal 59570 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�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≻ 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 JtL03C{tGehu+;zn literal 0 HcmV?d00001 diff --git a/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs b/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs index 8bb97e2..ab6b732 100644 --- a/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs +++ b/src/Log4net.Appender.InfluxDBSyslog/InfluxAppender.cs @@ -3,13 +3,58 @@ using log4net.Core; using System; using System.Collections.Generic; +using System.Globalization; +using System.Net; using System.Net.Http; namespace Log4net.Appender.InfluxDBSyslog { public class InfluxAppender : AppenderSkeleton { - public string Host { get; set; } + public string Scheme { get; set; } = "http"; + public string Host { get; set; } = "localhost"; + /// + /// Gets or sets the TCP port number of the remote host or multicast group to which + /// the underlying should sent the logging event. + /// + /// + /// An integer value in the range to + /// indicating the TCP port number of the remote host or multicast group to which the logging event + /// will be sent. + /// + /// + /// The underlying will send messages to this TCP port number + /// on the remote host or multicast group. + /// + /// The value specified is less than or greater than . + public int RemotePort + { + get { return this._remotePort; } + set + { + if (value < IPEndPoint.MinPort || value > IPEndPoint.MaxPort) + { + throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("value", value, + "The value specified is less than " + + IPEndPoint.MinPort.ToString(NumberFormatInfo.InvariantInfo) + + " or greater than " + + IPEndPoint.MaxPort.ToString(NumberFormatInfo.InvariantInfo) + "."); + } + else + { + this._remotePort = value; + } + } + } + /// + /// The TCP port number of the remote host or multicast group to + /// which the logging event will be sent. + /// + private int _remotePort; + public string Facility { get; set; } + public string AppName { get; set; } + + private HttpClient HttpClient; public InfluxAppender() { @@ -22,8 +67,11 @@ public InfluxAppender(HttpClient httpClient) protected override async void Append(LoggingEvent loggingEvent) { + //var renderedMessage = RenderLoggingEvent(loggingEvent); + SyslogSeverity severity = GetSyslogSeverity(loggingEvent.Level); + InfluxDbClientConfiguration config = new InfluxDbClientConfiguration( - new Uri(Host), + new UriBuilder(Scheme, Host, RemotePort).Uri, string.Empty, string.Empty, InfluxData.Net.Common.Enums.InfluxDbVersion.Latest, @@ -32,29 +80,99 @@ protected override async void Append(LoggingEvent loggingEvent) InfluxData.Net.InfluxDb.InfluxDbClient client = new InfluxData.Net.InfluxDb.InfluxDbClient(config); var fields = new Dictionary(); - fields.Add("facility_code", 14); + fields.Add("facility_code", 16); fields.Add("message", loggingEvent.MessageObject); fields.Add("procid", "1234"); - fields.Add("severity_code", 2); + fields.Add("severity_code", severity.SeverityCode); fields.Add("timestamp", DateTimeOffset.Now.ToUnixTimeMilliseconds() * 1000000); fields.Add("version", 1); var tags = new Dictionary(); - tags.Add("appname", "testapp1"); - tags.Add("facility", "console"); - tags.Add("host", "testhost"); - tags.Add("hostname", "testhost"); - tags.Add("severity", "crit"); - var x = await client.Client.WriteAsync(new InfluxData.Net.InfluxDb.Models.Point() + tags.Add("appname", AppName); + tags.Add("facility", Facility); + tags.Add("host", Environment.MachineName); + tags.Add("hostname", Environment.MachineName); + tags.Add("severity", severity.Severity); + try { - Name = "syslog", - Fields = fields, - Tags = tags, - Timestamp = DateTimeOffset.Now.UtcDateTime - }, "_internal" + var apiResp = await client.Client.WriteAsync(new InfluxData.Net.InfluxDb.Models.Point() + { + Name = "syslog", + Fields = fields, + Tags = tags, + Timestamp = DateTimeOffset.Now.UtcDateTime + }, "_internal" ); - var body = x.Body; + if (!apiResp.Success) + { + base.ErrorHandler.Error($"{nameof(InfluxAppender)} Write - {apiResp.Body}"); + } + } + catch (Exception ex) + { + base.ErrorHandler.Error($"{nameof(InfluxAppender)} Emit - {ex.Message}"); + } + } + + private SyslogSeverity GetSyslogSeverity(Level level) + { + switch (level.Name) + { + case "FATAL": + return new SyslogSeverity() { Severity = "emerg", SeverityCode = 0 }; + case "ERROR": + return new SyslogSeverity() { Severity = "err", SeverityCode = 3 }; + case "WARN": + return new SyslogSeverity() { Severity = "warning", SeverityCode = 4 }; + case "INFO": + return new SyslogSeverity() { Severity = "info", SeverityCode = 4 }; + case "DEBUG": + return new SyslogSeverity() { Severity = "debug", SeverityCode = 6 }; + default: + return new SyslogSeverity() { Severity = "notice", SeverityCode = 7 }; + } + } + + /// + /// Initialize the appender based on the options set. + /// + /// + /// + /// This is part of the delayed object + /// activation scheme. The method must + /// be called on this object after the configuration properties have + /// been set. Until is called this + /// object is in an undefined state and must not be used. + /// + /// + /// If any of the configuration properties are modified then + /// must be called again. + /// + /// + /// The appender will be ignored if no was specified or + /// an invalid remote or local TCP port number was specified. + /// + /// + /// The required property was not specified. + /// The TCP port number assigned to is less than or greater than . + public override void ActivateOptions() + { + base.ActivateOptions(); + + if (this.Host == null) + { + throw new ArgumentNullException("RemoteAddress"); + } + + if (this.RemotePort < IPEndPoint.MinPort || this.RemotePort > IPEndPoint.MaxPort) + { + throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("RemotePort", this.RemotePort, + "The RemotePort is less than " + + IPEndPoint.MinPort.ToString(NumberFormatInfo.InvariantInfo) + + " or greater than " + + IPEndPoint.MaxPort.ToString(NumberFormatInfo.InvariantInfo) + "."); + } } } } diff --git a/src/Log4net.Appender.InfluxDBSyslog/SyslogSeverity.cs b/src/Log4net.Appender.InfluxDBSyslog/SyslogSeverity.cs new file mode 100644 index 0000000..0407868 --- /dev/null +++ b/src/Log4net.Appender.InfluxDBSyslog/SyslogSeverity.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Log4net.Appender.InfluxDBSyslog +{ + public class SyslogSeverity + { + public string Severity { get; set; } + public int SeverityCode { get; set; } + } +}