diff --git a/.ionide/symbolCache.db b/.ionide/symbolCache.db new file mode 100644 index 00000000..8a73c4f7 Binary files /dev/null and b/.ionide/symbolCache.db differ diff --git a/CHANGES.md b/CHANGES.md index 7d4a853f..6e86076e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,8 @@ ## Changelog +8.3 + * Do not crash when ES is unreachable and the option `DetectElasticsearchVersion` is set to true. + * Disable dot-escaping for field names, because ELK already supports dots in field names. * Support for explicitly setting `Options.TypeName` to `null` this will remove the deprecated `_type` from the bulk payload being sent to Elastic. Earlier an exception was diff --git a/global.json b/global.json index 99e7444e..99d2533c 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.1.500" + "version": "2.1.807" } } \ No newline at end of file diff --git a/sample/Serilog.Sinks.Elasticsearch.Sample/Program.cs b/sample/Serilog.Sinks.Elasticsearch.Sample/Program.cs index 565a0be5..b8640806 100644 --- a/sample/Serilog.Sinks.Elasticsearch.Sample/Program.cs +++ b/sample/Serilog.Sinks.Elasticsearch.Sample/Program.cs @@ -41,7 +41,7 @@ static void Main(string[] args) NumberOfReplicas = 1, NumberOfShards = 2, //BufferBaseFilename = "./buffer", - RegisterTemplateFailure = RegisterTemplateRecovery.FailSink, + // RegisterTemplateFailure = RegisterTemplateRecovery.FailSink, FailureCallback = e => Console.WriteLine("Unable to submit event " + e.MessageTemplate), EmitEventFailure = EmitEventFailureHandling.WriteToSelfLog | EmitEventFailureHandling.WriteToFailureSink | diff --git a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkState.cs b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkState.cs index a1560c9f..f41be74c 100644 --- a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkState.cs +++ b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkState.cs @@ -242,17 +242,25 @@ public void DiscoverClusterVersion() { if (!_options.DetectElasticsearchVersion) return; - var response = _client.Cat.Nodes(new CatNodesRequestParameters() + try { - Headers = new[] { "v" } - }); - if (!response.Success) return; - _discoveredVersion = response.Body.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) - .FirstOrDefault(); + var response = _client.Cat.Nodes(new CatNodesRequestParameters() + { + Headers = new[] { "v" } + }); + if (!response.Success) return; + + _discoveredVersion = response.Body.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + .FirstOrDefault(); - if (_discoveredVersion?.StartsWith("7.") ?? false) - _options.TypeName = "_doc"; + if (_discoveredVersion?.StartsWith("7.") ?? false) + _options.TypeName = "_doc"; + } + catch (Exception ex) + { + SelfLog.WriteLine("Failed to discover the cluster version. {0}", ex); + } } } } diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/ElasticsearchSinkTestsBase.cs b/test/Serilog.Sinks.Elasticsearch.Tests/ElasticsearchSinkTestsBase.cs index 6fc6c7a3..6fe5c84d 100644 --- a/test/Serilog.Sinks.Elasticsearch.Tests/ElasticsearchSinkTestsBase.cs +++ b/test/Serilog.Sinks.Elasticsearch.Tests/ElasticsearchSinkTestsBase.cs @@ -23,6 +23,7 @@ public abstract class ElasticsearchSinkTestsBase protected readonly ElasticsearchSinkOptions _options; protected List _seenHttpPosts = new List(); protected List _seenHttpHeads = new List(); + protected List> _seenHttpGets = new List>(); protected List> _seenHttpPuts = new List>(); private IElasticsearchSerializer _serializer; @@ -32,10 +33,11 @@ protected ElasticsearchSinkTestsBase() { _seenHttpPosts = new List(); _seenHttpHeads = new List(); + _seenHttpGets = new List>(); _seenHttpPuts = new List>(); var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200")); - _connection = new ConnectionStub(_seenHttpPosts, _seenHttpHeads, _seenHttpPuts, () => _templateExistsReturnCode); + _connection = new ConnectionStub(_seenHttpPosts, _seenHttpHeads, _seenHttpPuts, _seenHttpGets, () => _templateExistsReturnCode); _serializer = JsonNetSerializer.Default(LowLevelRequestResponseSerializer.Instance, new ConnectionSettings(connectionPool, _connection)); _options = new ElasticsearchSinkOptions(connectionPool) @@ -119,6 +121,7 @@ public class ConnectionStub : InMemoryConnection { private Func _templateExistReturnCode; private List _seenHttpHeads; + private List> _seenHttpGets; private List _seenHttpPosts; private List> _seenHttpPuts; @@ -126,12 +129,14 @@ public ConnectionStub( List _seenHttpPosts, List _seenHttpHeads, List> _seenHttpPuts, + List> _seenHttpGets, Func templateExistReturnCode ) { this._seenHttpPosts = _seenHttpPosts; this._seenHttpHeads = _seenHttpHeads; this._seenHttpPuts = _seenHttpPuts; + this._seenHttpGets = _seenHttpGets; this._templateExistReturnCode = templateExistReturnCode; } @@ -149,6 +154,9 @@ public override TReturn Request(RequestData requestData) case HttpMethod.POST: _seenHttpPosts.Add(Encoding.UTF8.GetString(ms.ToArray())); break; + case HttpMethod.GET: + _seenHttpGets.Add(Tuple.Create(requestData.Uri, this._templateExistReturnCode())); + break; case HttpMethod.HEAD: _seenHttpHeads.Add(this._templateExistReturnCode()); break; @@ -172,6 +180,9 @@ public override async Task RequestAsync(RequestData reques case HttpMethod.POST: _seenHttpPosts.Add(Encoding.UTF8.GetString(ms.ToArray())); break; + case HttpMethod.GET: + _seenHttpGets.Add(Tuple.Create(requestData.Uri, this._templateExistReturnCode())); + break; case HttpMethod.HEAD: _seenHttpHeads.Add(this._templateExistReturnCode()); break; diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/DiscoverVersionHandlesUnavailableServerTests.cs b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/DiscoverVersionHandlesUnavailableServerTests.cs new file mode 100644 index 00000000..b80446f4 --- /dev/null +++ b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/DiscoverVersionHandlesUnavailableServerTests.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; +using System.Text; +using FluentAssertions; +using Xunit; +using Serilog.Debugging; + +namespace Serilog.Sinks.Elasticsearch.Tests.Templating +{ + [Collection("isolation")] + public class DiscoverVersionHandlesUnavailableServerTests : ElasticsearchSinkTestsBase + { + [Fact] + public void Should_not_crash_when_server_is_unavaiable() + { + // If this crashes, the test will fail + CreateLoggerThatCrashes(); + } + + [Fact] + public void Should_write_error_to_self_log() + { + var selfLogMessages = new StringBuilder(); + SelfLog.Enable(new StringWriter(selfLogMessages)); + + // Exception occurs on creation - should be logged + CreateLoggerThatCrashes(); + + var selfLogContents = selfLogMessages.ToString(); + selfLogContents.Should().Contain("Failed to discover the cluster version"); + + } + + private static ILogger CreateLoggerThatCrashes() + { + var loggerConfig = new LoggerConfiguration() + .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://localhost:9199")) + { + DetectElasticsearchVersion = true + }); + + return loggerConfig.CreateLogger(); + } + } +} \ No newline at end of file diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/DiscoverVersionTests.cs b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/DiscoverVersionTests.cs new file mode 100644 index 00000000..7d767744 --- /dev/null +++ b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/DiscoverVersionTests.cs @@ -0,0 +1,39 @@ +using System; +using FluentAssertions; +using Xunit; + +namespace Serilog.Sinks.Elasticsearch.Tests.Templating +{ + public class DiscoverVersionTests : ElasticsearchSinkTestsBase + { + private readonly Tuple _templateGet; + + public DiscoverVersionTests() + { + _options.DetectElasticsearchVersion = true; + + var loggerConfig = new LoggerConfiguration() + .MinimumLevel.Debug() + .Enrich.WithMachineName() + .WriteTo.ColoredConsole() + .WriteTo.Elasticsearch(_options); + + var logger = loggerConfig.CreateLogger(); + using ((IDisposable) logger) + { + logger.Error("Test exception. Should not contain an embedded exception object."); + } + + this._seenHttpGets.Should().NotBeNullOrEmpty().And.HaveCount(1); + _templateGet = this._seenHttpGets[0]; + } + + + [Fact] + public void TemplatePutToCorrectUrl() + { + var uri = _templateGet.Item1; + uri.AbsolutePath.Should().Be("/_cat/nodes"); + } + } +} \ No newline at end of file diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/SendsTemplateHandlesUnavailableServerTests.cs b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/SendsTemplateHandlesUnavailableServerTests.cs index d549f544..2f1b0a51 100644 --- a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/SendsTemplateHandlesUnavailableServerTests.cs +++ b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/SendsTemplateHandlesUnavailableServerTests.cs @@ -11,7 +11,7 @@ namespace Serilog.Sinks.Elasticsearch.Tests.Templating public class SendsTemplateHandlesUnavailableServerTests : ElasticsearchSinkTestsBase { [Fact] - public void Should_not_crash_when_server_is_unavaiable() + public void Should_not_crash_when_server_is_unavailable() { // If this crashes, the test will fail CreateLoggerThatCrashes();