diff --git a/.editorconfig b/.editorconfig
index 28e37c6f..9bdbb34e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -2,4 +2,7 @@ root=true
[*]
indent_style = space
-indent_size = 4
\ No newline at end of file
+indent_size = 4
+
+[*.csproj]
+indent_size = 2
diff --git a/Build.ps1 b/Build.ps1
index 06c478f5..a6c50387 100644
--- a/Build.ps1
+++ b/Build.ps1
@@ -2,6 +2,7 @@ echo "In directory: $PSScriptRoot"
$solution = "serilog-sinks-elasticsearch.sln"
$test = "test\\Serilog.Sinks.Elasticsearch.Tests\\Serilog.Sinks.Elasticsearch.Tests.csproj"
+$testIntegration = "test\\Serilog.Sinks.Elasticsearch.IntegrationTests\\Serilog.Sinks.Elasticsearch.IntegrationTests.csproj"
[string[]]$projects = @(
("src\\Serilog.Sinks.Elasticsearch\\Serilog.Sinks.Elasticsearch.csproj"),
("src\\Serilog.Formatting.Elasticsearch\\Serilog.Formatting.Elasticsearch.csproj")
@@ -22,6 +23,16 @@ function Invoke-Build()
Write-Output "The tests failed"
exit 1
}
+
+ Write-Output "Running integration tests"
+ # Tee-Object forces console redirection on vstest which magically makes Console.WriteLine works again.
+ # This allows you to see the console out of Elastic.Xunit while its running
+ & dotnet test $testIntegration -c Release | Tee-Object -Variable integ
+ if($LASTEXITCODE -ne 0)
+ {
+ Write-Output "The integration tests failed"
+ exit 1
+ }
Write-Output "Creating packages"
foreach ($project in $projects)
diff --git a/global.json b/global.json
index 341f9fea..99e7444e 100644
--- a/global.json
+++ b/global.json
@@ -1,5 +1,5 @@
{
"sdk": {
- "version": "2.1.4"
+ "version": "2.1.500"
}
}
\ No newline at end of file
diff --git a/nuget.config b/nuget.config
index 96116f07..a81fc3ec 100644
--- a/nuget.config
+++ b/nuget.config
@@ -11,5 +11,7 @@
+
+
\ No newline at end of file
diff --git a/serilog-sinks-elasticsearch.sln b/serilog-sinks-elasticsearch.sln
index 1f08366a..551c394d 100644
--- a/serilog-sinks-elasticsearch.sln
+++ b/serilog-sinks-elasticsearch.sln
@@ -24,6 +24,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serilog.Sinks.Elasticsearch
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serilog.Formatting.Elasticsearch", "src\Serilog.Formatting.Elasticsearch\Serilog.Formatting.Elasticsearch.csproj", "{0E6D34BF-322A-4803-94D1-355F6D5024BE}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Sinks.Elasticsearch.IntegrationTests", "test\Serilog.Sinks.Elasticsearch.IntegrationTests\Serilog.Sinks.Elasticsearch.IntegrationTests.csproj", "{23BC3821-E028-48B4-8F2C-83BB1B8B5525}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -46,6 +48,10 @@ Global
{0E6D34BF-322A-4803-94D1-355F6D5024BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0E6D34BF-322A-4803-94D1-355F6D5024BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0E6D34BF-322A-4803-94D1-355F6D5024BE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {23BC3821-E028-48B4-8F2C-83BB1B8B5525}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {23BC3821-E028-48B4-8F2C-83BB1B8B5525}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {23BC3821-E028-48B4-8F2C-83BB1B8B5525}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {23BC3821-E028-48B4-8F2C-83BB1B8B5525}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/serilog-sinks-elasticsearch.sln.DotSettings b/serilog-sinks-elasticsearch.sln.DotSettings
new file mode 100644
index 00000000..e62f9e23
--- /dev/null
+++ b/serilog-sinks-elasticsearch.sln.DotSettings
@@ -0,0 +1,8 @@
+
+ True
+ True
+ True
+ True
+ True
+ True
+ True
\ No newline at end of file
diff --git a/src/Serilog.Formatting.Elasticsearch/Serilog.Formatting.ElasticSearch.nuspec b/src/Serilog.Formatting.Elasticsearch/Serilog.Formatting.ElasticSearch.nuspec
index 3047dcd8..50f0444a 100644
--- a/src/Serilog.Formatting.Elasticsearch/Serilog.Formatting.ElasticSearch.nuspec
+++ b/src/Serilog.Formatting.Elasticsearch/Serilog.Formatting.ElasticSearch.nuspec
@@ -13,6 +13,7 @@
serilog logging elasticsearch formatters
+
diff --git a/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.ElasticSearch.Symbols.nuspec b/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.ElasticSearch.Symbols.nuspec
index 289c659a..9932b8fb 100644
--- a/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.ElasticSearch.Symbols.nuspec
+++ b/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.ElasticSearch.Symbols.nuspec
@@ -12,7 +12,7 @@
serilog logging elasticsearch
-
+
diff --git a/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.ElasticSearch.nuspec b/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.ElasticSearch.nuspec
index 5c6c8148..c6ba9cc7 100644
--- a/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.ElasticSearch.nuspec
+++ b/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.ElasticSearch.nuspec
@@ -13,7 +13,7 @@
serilog logging elasticsearch
-
+
diff --git a/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.Elasticsearch.csproj b/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.Elasticsearch.csproj
index b1d79191..cbe61dbf 100644
--- a/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.Elasticsearch.csproj
+++ b/src/Serilog.Sinks.Elasticsearch/Serilog.Sinks.Elasticsearch.csproj
@@ -4,7 +4,7 @@
6.0.0
alpha
Michiel van Oudheusden, Martijn Laarman, Mogens Heller Grabe, Serilog Contributors
- net45;netstandard1.3;netstandard2.0
+ net461;netstandard2.0
true
true
Serilog.Sinks.Elasticsearch
@@ -28,49 +28,31 @@
false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1591;1701;1702
- $(DefineConstants);DURABLE;THREADING_TIMER
-
-
1591;1701;1702
$(DefineConstants);DURABLE;THREADING_TIMER
-
+
1591;1701;1702
$(DefineConstants);DURABLE;THREADING_TIMER;HRESULTS
-
- 1591;1701;1702
- NU1605
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/DurableElasticSearchSink.cs b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/DurableElasticSearchSink.cs
deleted file mode 100644
index 9ac18737..00000000
--- a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/DurableElasticSearchSink.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2014 Serilog Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Elasticsearch.Net;
-using Serilog.Core;
-using Serilog.Events;
-
-
-namespace Serilog.Sinks.Elasticsearch.Durable
-{
- class DurableElasticsearchSink : ILogEventSink, IDisposable
- {
- // we rely on the date in the filename later!
- const string FileNameSuffix = "-.json";
-
- readonly Logger _sink;
- readonly LogShipper> _shipper;
- readonly ElasticsearchSinkState _state;
-
- public DurableElasticsearchSink(ElasticsearchSinkOptions options)
- {
- _state = ElasticsearchSinkState.Create(options);
-
- if (string.IsNullOrWhiteSpace(options.BufferBaseFilename))
- {
- throw new ArgumentException("Cannot create the durable ElasticSearch sink without a buffer base file name!");
- }
-
-
- _sink = new LoggerConfiguration()
- .MinimumLevel.Verbose()
- .WriteTo.File(_state.DurableFormatter,
- options.BufferBaseFilename + FileNameSuffix,
- rollingInterval: RollingInterval.Day,
- fileSizeLimitBytes: options.BufferFileSizeLimitBytes,
- rollOnFileSizeLimit: true,
- retainedFileCountLimit: options.BufferFileCountLimit,
- levelSwitch: _state.Options.LevelSwitch,
- encoding: Encoding.UTF8)
- .CreateLogger();
-
-
- var elasticSearchLogClient = new ElasticsearchLogClient(
- elasticLowLevelClient: _state.Client,
- cleanPayload: _state.Options.BufferCleanPayload);
-
- var payloadReader = new ElasticsearchPayloadReader(
- pipelineName: _state.Options.PipelineName,
- typeName:_state.Options.TypeName,
- serialize:_state.Serialize,
- getIndexForEvent: _state.GetBufferedIndexForEvent
- );
-
- _shipper = new ElasticsearchLogShipper(
- bufferBaseFilename: _state.Options.BufferBaseFilename,
- batchPostingLimit: _state.Options.BatchPostingLimit,
- period: _state.Options.BufferLogShippingInterval ?? TimeSpan.FromSeconds(5),
- eventBodyLimitBytes: _state.Options.SingleEventSizePostingLimit,
- levelControlSwitch: _state.Options.LevelSwitch,
- logClient: elasticSearchLogClient,
- payloadReader: payloadReader,
- retainedInvalidPayloadsLimitBytes: _state.Options.BufferRetainedInvalidPayloadsLimitBytes,
- bufferSizeLimitBytes: _state.Options.BufferFileSizeLimitBytes,
- registerTemplateIfNeeded: _state.RegisterTemplateIfNeeded);
-
- }
-
- public void Emit(LogEvent logEvent)
- {
- // This is a lagging indicator, but the network bandwidth usage benefits
- // are worth the ambiguity.
- if (_shipper.IsIncluded(logEvent))
- {
- _sink.Write(logEvent);
- }
- }
-
- public void Dispose()
- {
- _sink.Dispose();
- _shipper.Dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/ElasticSearchLogClient.cs b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/ElasticSearchLogClient.cs
deleted file mode 100644
index 6b2d45bf..00000000
--- a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/ElasticSearchLogClient.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.ExceptionServices;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using Elasticsearch.Net;
-using Serilog.Debugging;
-
-namespace Serilog.Sinks.Elasticsearch.Durable
-{
- ///
- ///
- ///
- public class ElasticsearchLogClient : ILogClient>
- {
- private readonly IElasticLowLevelClient _elasticLowLevelClient;
- private readonly Func _cleanPayload;
-
- ///
- ///
- ///
- ///
- ///
- public ElasticsearchLogClient(IElasticLowLevelClient elasticLowLevelClient,
- Func cleanPayload)
- {
- _elasticLowLevelClient = elasticLowLevelClient;
- _cleanPayload = cleanPayload;
- }
-
- public async Task SendPayloadAsync(List payload)
- {
- return await SendPayloadAsync(payload, true);
- }
-
- public async Task SendPayloadAsync(List payload,bool first)
- {
- try
- {
- if (payload == null || !payload.Any()) return new SentPayloadResult(null, true);
- var response = await _elasticLowLevelClient.BulkAsync(PostData.MultiJson(payload));
-
- if (response.Success)
- {
- var cleanPayload = new List();
- var invalidPayload = GetInvalidPayloadAsync(response, payload,out cleanPayload);
- if ((cleanPayload?.Any() ?? false) && first)
- {
- await SendPayloadAsync(cleanPayload,false);
- }
-
- return new SentPayloadResult(response, true, invalidPayload);
- }
- else
- {
- SelfLog.WriteLine("Received failed ElasticSearch shipping result {0}: {1}", response.HttpStatusCode,
- response.OriginalException);
- return new SentPayloadResult(response, false,
- new InvalidResult()
- {
- StatusCode = response.HttpStatusCode ?? 500,
- Content = response.OriginalException.ToString()
- });
- }
- }
- catch (Exception ex)
- {
- SelfLog.WriteLine("Exception while emitting periodic batch from {0}: {1}", this, ex);
- return new SentPayloadResult(null, false, null, ex);
- }
-
-
- }
-
- private InvalidResult GetInvalidPayloadAsync(DynamicResponse baseResult, List payload, out List cleanPayload)
- {
- int i = 0;
- cleanPayload = new List();
- var items = baseResult.Body["items"];
- if (items == null) return null;
- List badPayload = new List();
-
- bool hasErrors = false;
- foreach (dynamic item in items)
- {
- long? status = item.index?.status;
- i++;
- if (!status.HasValue || status < 300)
- {
- continue;
- }
-
- hasErrors = true;
- var id = item.index?._id;
- var error = item.index?.error;
- if (int.TryParse(id.Split('_')[0], out int index))
- {
- SelfLog.WriteLine("Received failed ElasticSearch shipping result {0}: {1}. Failed payload : {2}.", status, error?.ToString(), payload.ElementAt(index * 2 + 1));
- badPayload.Add(payload.ElementAt(index * 2));
- badPayload.Add(payload.ElementAt(index * 2 + 1));
- if (_cleanPayload != null)
- {
- cleanPayload.Add(payload.ElementAt(index * 2));
- cleanPayload.Add(_cleanPayload(payload.ElementAt(index * 2 + 1), status, error?.ToString()));
- }
- }
- else
- {
- SelfLog.WriteLine($"Received failed ElasticSearch shipping result {status}: {error?.ToString()}.");
- }
- }
-
- if (!hasErrors)
- return null;
- return new InvalidResult()
- {
- StatusCode = baseResult.HttpStatusCode ?? 500,
- Content = baseResult.ToString(),
- BadPayLoad = String.Join(Environment.NewLine, badPayload)
- };
- }
- }
-}
diff --git a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/ElasticSearchLogShipper.cs b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/ElasticSearchLogShipper.cs
deleted file mode 100644
index 6a6b8b26..00000000
--- a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/ElasticSearchLogShipper.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Serilog.Core;
-using Serilog.Debugging;
-using Serilog.Sinks.Elasticsearch.Durable;
-
-namespace Serilog.Sinks.Elasticsearch.Durable
-{
- ///
- ///
- ///
- public class ElasticsearchLogShipper : LogShipper>
- {
- private readonly Action _registerTemplateIfNeeded;
- bool _didRegisterTemplateIfNeeded = false;
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public ElasticsearchLogShipper(string bufferBaseFilename, int batchPostingLimit, TimeSpan period,
- long? eventBodyLimitBytes, LoggingLevelSwitch levelControlSwitch, ILogClient> logClient,
- IPayloadReader> payloadReader, long? retainedInvalidPayloadsLimitBytes,
- long? bufferSizeLimitBytes, Action registerTemplateIfNeeded)
- : base(bufferBaseFilename, batchPostingLimit, period, eventBodyLimitBytes,
- levelControlSwitch, logClient, payloadReader, retainedInvalidPayloadsLimitBytes, bufferSizeLimitBytes)
- {
- _registerTemplateIfNeeded = registerTemplateIfNeeded;
- }
-
- ///
- ///
- ///
- ///
- protected override async Task OnTick()
- {
- bool success = true;
- try
- {
- if (!_didRegisterTemplateIfNeeded)
- {
- if (_registerTemplateIfNeeded != null)
- {
- _registerTemplateIfNeeded();
- _didRegisterTemplateIfNeeded = true;
- }
- }
- }
- catch (Exception ex)
- {
- SelfLog.WriteLine("Exception while emitting periodic batch from {0}: {1}", this, ex);
- _connectionSchedule.MarkFailure();
- success = false;
- }
- if (success)
- await base.OnTick();
- }
- }
-}
diff --git a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/ElasticSearchPayloadReader.cs b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/ElasticSearchPayloadReader.cs
deleted file mode 100644
index a31b253e..00000000
--- a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/Durable/ElasticSearch/ElasticSearchPayloadReader.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Serilog.Sinks.Elasticsearch.Durable
-{
- ///
- ///
- ///
- public class ElasticsearchPayloadReader: APayloadReader>
- {
- private readonly string _pipelineName;
- private readonly string _typeName;
- private readonly Func