diff --git a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticSearchTemplateProvider.cs b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticSearchTemplateProvider.cs new file mode 100644 index 00000000..1928254a --- /dev/null +++ b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticSearchTemplateProvider.cs @@ -0,0 +1,336 @@ +using System; +using System.Collections.Generic; + +namespace Serilog.Sinks.Elasticsearch +{ + /// + /// + /// + public enum AutoRegisterTemplateVersion + { + /// + /// Elasticsearch version <= 2.4 + /// + ESv2 = 0, + /// + /// Elasticsearch version <= version 5.6 + /// + ESv5 = 1, + /// + /// Elasticsearch version >= version 6.0 + /// + ESv6 = 2 + } + + /// + /// + /// + public class ElasticSearchTemplateProvider + { + /// + /// + /// + /// + /// + /// + /// + public static object GetTemplate( + Dictionary settings, + string templateMatchString, + AutoRegisterTemplateVersion version = AutoRegisterTemplateVersion.ESv2) + { + switch (version) + { + case AutoRegisterTemplateVersion.ESv5: + return GetTemplateESv5(settings, templateMatchString); + case AutoRegisterTemplateVersion.ESv6: + return GetTemplateESv6(settings, templateMatchString); + case AutoRegisterTemplateVersion.ESv2: + return GetTemplateESv2(settings, templateMatchString); + default: + throw new ArgumentOutOfRangeException(nameof(version), version, null); + } + } + + private static object GetTemplateESv6( + Dictionary settings, + string templateMatchString) + { + return new + { + template = templateMatchString, + settings = settings, + mappings = new + { + _default_ = new + { + dynamic_templates = new List + { + //when you use serilog as an adaptor for third party frameworks + //where you have no control over the log message they typically + //contain {0} ad infinitum, we force numeric property names to + //contain strings by default. + { + new + { + numerics_in_fields = new + { + path_match = @"fields\.[\d+]$", + match_pattern = "regex", + mapping = new + { + type = "text", + index = true, + norms = false + } + } + } + }, + { + new + { + string_fields = new + { + match = "*", + match_mapping_type = "string", + mapping = new + { + type = "text", + index = true, + norms = false, + fields = new + { + raw = new + { + type = "keyword", + index = true, + ignore_above = 256 + } + } + } + } + } + } + }, + properties = new Dictionary + { + {"message", new {type = "text", index = "analyzed"}}, + { + "exceptions", new + { + type = "nested", + properties = new Dictionary + { + {"Depth", new {type = "integer"}}, + {"RemoteStackIndex", new {type = "integer"}}, + {"HResult", new {type = "integer"}}, + {"StackTraceString", new {type = "text", index = "analyzed"}}, + {"RemoteStackTraceString", new {type = "text", index = "analyzed"}}, + { + "ExceptionMessage", new + { + type = "object", + properties = new Dictionary + { + {"MemberType", new {type = "integer"}}, + } + } + } + } + } + } + } + } + } + }; + } + + private static object GetTemplateESv5( + Dictionary settings, + string templateMatchString) + { + return new + { + template = templateMatchString, + settings = settings, + mappings = new + { + _default_ = new + { + _all = new { enabled = true, norms = false }, + dynamic_templates = new List + { + //when you use serilog as an adaptor for third party frameworks + //where you have no control over the log message they typically + //contain {0} ad infinitum, we force numeric property names to + //contain strings by default. + { + new + { + numerics_in_fields = new + { + path_match = @"fields\.[\d+]$", + match_pattern = "regex", + mapping = new + { + type = "text", + index = true, + norms = false + } + } + } + }, + { + new + { + string_fields = new + { + match = "*", + match_mapping_type = "string", + mapping = new + { + type = "text", + index = true, + norms = false, + fields = new + { + raw = new + { + type = "keyword", + index = true, + ignore_above = 256 + } + } + } + } + } + } + }, + properties = new Dictionary + { + {"message", new {type = "text", index = "analyzed"}}, + { + "exceptions", new + { + type = "nested", + properties = new Dictionary + { + {"Depth", new {type = "integer"}}, + {"RemoteStackIndex", new {type = "integer"}}, + {"HResult", new {type = "integer"}}, + {"StackTraceString", new {type = "text", index = "analyzed"}}, + {"RemoteStackTraceString", new {type = "text", index = "analyzed"}}, + { + "ExceptionMessage", new + { + type = "object", + properties = new Dictionary + { + {"MemberType", new {type = "integer"}}, + } + } + } + } + } + } + } + } + } + }; + } + + private static object GetTemplateESv2( + Dictionary settings, + string templateMatchString) + { + return new + { + template = templateMatchString, + settings = settings, + mappings = new + { + _default_ = new + { + _all = new { enabled = true, omit_norms = true }, + dynamic_templates = new List + { + //when you use serilog as an adaptor for third party frameworks + //where you have no control over the log message they typically + //contain {0} ad infinitum, we force numeric property names to + //contain strings by default. + { + new + { + numerics_in_fields = new + { + path_match = @"fields\.[\d+]$", + match_pattern = "regex", + mapping = new + { + type = "string", + index = "analyzed", + omit_norms = true + } + } + } + }, + { + new + { + string_fields = new + { + match = "*", + match_mapping_type = "string", + mapping = new + { + type = "string", + index = "analyzed", + omit_norms = true, + fields = new + { + raw = new + { + type = "string", + index = "not_analyzed", + ignore_above = 256 + } + } + } + } + } + } + }, + properties = new Dictionary + { + {"message", new {type = "string", index = "analyzed"}}, + { + "exceptions", new + { + type = "nested", + properties = new Dictionary + { + {"Depth", new {type = "integer"}}, + {"RemoteStackIndex", new {type = "integer"}}, + {"HResult", new {type = "integer"}}, + {"StackTraceString", new {type = "string", index = "analyzed"}}, + {"RemoteStackTraceString", new {type = "string", index = "analyzed"}}, + { + "ExceptionMessage", new + { + type = "object", + properties = new Dictionary + { + {"MemberType", new {type = "integer"}}, + } + } + } + } + } + } + } + } + } + }; + } + } +} diff --git a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkOptions.cs b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkOptions.cs index 9be9dcd9..b509f6bc 100644 --- a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkOptions.cs +++ b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkOptions.cs @@ -1,11 +1,11 @@ // 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. @@ -35,6 +35,12 @@ public class ElasticsearchSinkOptions /// public bool AutoRegisterTemplate { get; set; } + /// + /// When using the feature, this allows to set the Elasticsearch version. Depending on the + /// version, a template will be selected. Defaults to pre 5.0. + /// + public AutoRegisterTemplateVersion AutoRegisterTemplateVersion { get; set; } + /// /// Specifies the option on how to handle failures when writing the template to Elasticsearch. This is only applicable when using the AutoRegisterTemplate option. /// @@ -173,7 +179,7 @@ public class ElasticsearchSinkOptions public ITextFormatter CustomDurableFormatter { get; set; } /// - /// Specifies how failing emits should be handled. + /// Specifies how failing emits should be handled. /// public EmitEventFailureHandling EmitEventFailure { get; set; } @@ -292,7 +298,7 @@ public enum RegisterTemplateRecovery IndexAnyway = 1, ///// - ///// Keep buffering the data until it is written. be aware you might hit a limit here. + ///// Keep buffering the data until it is written. be aware you might hit a limit here. ///// //BufferUntilSuccess = 2, diff --git a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkState.cs b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkState.cs index 41aace7b..93718c2e 100644 --- a/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkState.cs +++ b/src/Serilog.Sinks.Elasticsearch/Sinks/ElasticSearch/ElasticsearchSinkState.cs @@ -1,11 +1,11 @@ // 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. @@ -28,14 +28,13 @@ internal class ElasticsearchSinkState public static ElasticsearchSinkState Create(ElasticsearchSinkOptions options) { if (options == null) - { - throw new ArgumentNullException("options"); - } + throw new ArgumentNullException(nameof(options)); return new ElasticsearchSinkState(options); } private readonly ElasticsearchSinkOptions _options; + readonly Func _indexDecider; private readonly ITextFormatter _formatter; @@ -43,16 +42,15 @@ public static ElasticsearchSinkState Create(ElasticsearchSinkOptions options) private readonly ElasticLowLevelClient _client; - readonly string _typeName; private readonly bool _registerTemplateOnStartup; private readonly string _templateName; private readonly string _templateMatchString; private static readonly Regex IndexFormatRegex = new Regex(@"^(.*)(?:\{0\:.+\})(.*)$"); - public ElasticsearchSinkOptions Options => this._options; - public IElasticLowLevelClient Client => this._client; - public ITextFormatter Formatter => this._formatter; - public ITextFormatter DurableFormatter => this._durableFormatter; + public ElasticsearchSinkOptions Options => _options; + public IElasticLowLevelClient Client => _client; + public ITextFormatter Formatter => _formatter; + public ITextFormatter DurableFormatter => _durableFormatter; public bool TemplateRegistrationSuccess { get; private set; } @@ -62,26 +60,25 @@ private ElasticsearchSinkState(ElasticsearchSinkOptions options) if (string.IsNullOrWhiteSpace(options.TypeName)) throw new ArgumentException("options.TypeName"); if (string.IsNullOrWhiteSpace(options.TemplateName)) throw new ArgumentException("options.TemplateName"); - this._templateName = options.TemplateName; - this._templateMatchString = IndexFormatRegex.Replace(options.IndexFormat, @"$1*$2"); + _templateName = options.TemplateName; + _templateMatchString = IndexFormatRegex.Replace(options.IndexFormat, @"$1*$2"); _indexDecider = options.IndexDecider ?? ((@event, offset) => string.Format(options.IndexFormat, offset)); - _typeName = options.TypeName; _options = options; Func serializerFactory = null; if (options.Serializer != null) - { serializerFactory = s => options.Serializer; - } - ConnectionConfiguration configuration = new ConnectionConfiguration(options.ConnectionPool, options.Connection, serializerFactory) + + var configuration = new ConnectionConfiguration(options.ConnectionPool, options.Connection, serializerFactory) .RequestTimeout(options.ConnectionTimeout); if (options.ModifyConnectionSettings != null) configuration = options.ModifyConnectionSettings(configuration); configuration.ThrowExceptions(); + _client = new ElasticLowLevelClient(configuration); _formatter = options.CustomFormatter ?? new ElasticsearchJsonFormatter( @@ -91,6 +88,7 @@ private ElasticsearchSinkState(ElasticsearchSinkOptions options) serializer: options.Serializer, inlineFields: options.InlineFields ); + _durableFormatter = options.CustomDurableFormatter ?? new ElasticsearchJsonFormatter( formatProvider: options.FormatProvider, renderMessage: true, @@ -113,8 +111,7 @@ public string GetIndexForEvent(LogEvent e, DateTimeOffset offset) { if (!TemplateRegistrationSuccess && _options.RegisterTemplateFailure == RegisterTemplateRecovery.IndexToDeadletterIndex) return string.Format(_options.DeadLetterIndexName, offset); - else - return this._indexDecider(e, offset); + return _indexDecider(e, offset); } /// @@ -122,21 +119,22 @@ public string GetIndexForEvent(LogEvent e, DateTimeOffset offset) /// public void RegisterTemplateIfNeeded() { - if (!this._registerTemplateOnStartup) return; + if (!_registerTemplateOnStartup) return; try { - if (!this._options.OverwriteTemplate) + if (!_options.OverwriteTemplate) { - var templateExistsResponse = this._client.IndicesExistsTemplateForAll(this._templateName); + var templateExistsResponse = _client.IndicesExistsTemplateForAll(_templateName); if (templateExistsResponse.HttpStatusCode == 200) { TemplateRegistrationSuccess = true; + return; } } - var result = this._client.IndicesPutTemplateForAll(this._templateName, GetTemplateData()); + var result = _client.IndicesPutTemplateForAll(_templateName, GetTemplateData()); if (!result.Success) { @@ -165,9 +163,7 @@ public void RegisterTemplateIfNeeded() private object GetTemplateData() { if (_options.GetTemplateContent != null) - { return _options.GetTemplateContent(); - } var settings = new Dictionary { @@ -180,94 +176,11 @@ private object GetTemplateData() if (_options.NumberOfReplicas.HasValue) settings.Add("number_of_replicas", _options.NumberOfReplicas.Value.ToString()); - return new - { - template = this._templateMatchString, - settings = settings, - mappings = new - { - _default_ = new - { - _all = new { enabled = true, omit_norms = true }, - dynamic_templates = new List - { - //when you use serilog as an adaptor for third party frameworks - //where you have no control over the log message they typically - //contain {0} ad infinitum, we force numeric property names to - //contain strings by default. - { - new - { - numerics_in_fields = new - { - path_match = @"fields\.[\d+]$", - match_pattern = "regex", - mapping = new - { - type = "string", - index = "analyzed", - omit_norms = true - } - } - } - }, - { - new - { - string_fields = new - { - match = "*", - match_mapping_type = "string", - mapping = new - { - type = "string", - index = "analyzed", - omit_norms = true, - fields = new - { - raw = new - { - type = "string", - index = "not_analyzed", - ignore_above = 256 - } - } - } - } - } - } - }, - properties = new Dictionary - { - {"message", new {type = "string", index = "analyzed"}}, - { - "exceptions", new - { - type = "nested", - properties = new Dictionary - { - {"Depth", new {type = "integer"}}, - {"RemoteStackIndex", new {type = "integer"}}, - {"HResult", new {type = "integer"}}, - {"StackTraceString", new {type = "string", index = "analyzed"}}, - {"RemoteStackTraceString", new {type = "string", index = "analyzed"}}, - { - "ExceptionMessage", new - { - type = "object", - properties = new Dictionary - { - {"MemberType", new {type = "integer"}}, - } - } - } - } - } - } - } - } - } - }; + return ElasticSearchTemplateProvider.GetTemplate( + settings, + _templateMatchString, + _options.AutoRegisterTemplateVersion); + } } } diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/Serilog.Sinks.Elasticsearch.Tests.csproj b/test/Serilog.Sinks.Elasticsearch.Tests/Serilog.Sinks.Elasticsearch.Tests.csproj index 54f0169e..89b9eaab 100644 --- a/test/Serilog.Sinks.Elasticsearch.Tests/Serilog.Sinks.Elasticsearch.Tests.csproj +++ b/test/Serilog.Sinks.Elasticsearch.Tests/Serilog.Sinks.Elasticsearch.Tests.csproj @@ -21,6 +21,15 @@ + + + + + + + + + diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/SendsTemplateTests.cs b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/SendsTemplateTests.cs index 22c55c7c..161d0bac 100644 --- a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/SendsTemplateTests.cs +++ b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/SendsTemplateTests.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Reflection; using FluentAssertions; using Newtonsoft.Json.Linq; @@ -14,6 +13,7 @@ public class SendsTemplateTests : ElasticsearchSinkTestsBase public SendsTemplateTests() { _options.AutoRegisterTemplate = true; + var loggerConfig = new LoggerConfiguration() .MinimumLevel.Debug() .Enrich.WithMachineName() @@ -31,18 +31,17 @@ public SendsTemplateTests() _templatePut = this._seenHttpPuts[0]; } - [Fact] public void ShouldRegisterTheCorrectTemplateOnRegistration() { var method = typeof(SendsTemplateTests).GetMethod(nameof(ShouldRegisterTheCorrectTemplateOnRegistration)); - this.JsonEquals(this._templatePut.Item2, method, "template"); + JsonEquals(_templatePut.Item2, method, "template"); } [Fact] public void TemplatePutToCorrectUrl() { - var uri = this._templatePut.Item1; + var uri = _templatePut.Item1; uri.AbsolutePath.Should().Be("/_template/serilog-events-template"); } @@ -54,13 +53,12 @@ protected void JsonEquals(string json, MethodBase method, string fileName = null var assembly = Assembly.GetExecutingAssembly(); #endif var expected = TestDataHelper.ReadEmbeddedResource(assembly, "template.json"); - + var nJson = JObject.Parse(json); var nOtherJson = JObject.Parse(expected); var equals = JToken.DeepEquals(nJson, nOtherJson); if (equals) return; expected.Should().BeEquivalentTo(json); - } } } \ No newline at end of file diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/Sendsv5TemplateTests.cs b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/Sendsv5TemplateTests.cs new file mode 100644 index 00000000..625dcc9d --- /dev/null +++ b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/Sendsv5TemplateTests.cs @@ -0,0 +1,66 @@ +using System; +using System.Reflection; +using FluentAssertions; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace Serilog.Sinks.Elasticsearch.Tests.Templating +{ + public class Sendsv5TemplateTests : ElasticsearchSinkTestsBase + { + private readonly Tuple _templatePut; + + public Sendsv5TemplateTests() + { + _options.AutoRegisterTemplate = true; + _options.AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv5; + + var loggerConfig = new LoggerConfiguration() + .MinimumLevel.Debug() + .Enrich.WithMachineName() + .WriteTo.ColoredConsole() + .WriteTo.Elasticsearch(_options); + + var logger = loggerConfig.CreateLogger(); + using (logger as IDisposable) + { + logger.Error("Test exception. Should not contain an embedded exception object."); + } + + this._seenHttpPosts.Should().NotBeNullOrEmpty().And.HaveCount(1); + this._seenHttpPuts.Should().NotBeNullOrEmpty().And.HaveCount(1); + _templatePut = this._seenHttpPuts[0]; + } + + [Fact] + public void ShouldRegisterTheCorrectTemplateOnRegistration() + { + + var method = typeof(Sendsv5TemplateTests).GetMethod(nameof(ShouldRegisterTheCorrectTemplateOnRegistration)); + JsonEquals(_templatePut.Item2, method, "template_v5.json"); + } + + [Fact] + public void TemplatePutToCorrectUrl() + { + var uri = _templatePut.Item1; + uri.AbsolutePath.Should().Be("/_template/serilog-events-template"); + } + + protected void JsonEquals(string json, MethodBase method, string fileName = null) + { +#if DOTNETCORE + var assembly = typeof(Sendsv5TemplateTests).GetTypeInfo().Assembly; +#else + var assembly = Assembly.GetExecutingAssembly(); +#endif + var expected = TestDataHelper.ReadEmbeddedResource(assembly, fileName ?? "template.json"); + + var nJson = JObject.Parse(json); + var nOtherJson = JObject.Parse(expected); + var equals = JToken.DeepEquals(nJson, nOtherJson); + if (equals) return; + expected.Should().BeEquivalentTo(json); + } + } +} \ No newline at end of file diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/Sendsv6TemplateTests.cs b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/Sendsv6TemplateTests.cs new file mode 100644 index 00000000..8764aae2 --- /dev/null +++ b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/Sendsv6TemplateTests.cs @@ -0,0 +1,66 @@ +using System; +using System.Reflection; +using FluentAssertions; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace Serilog.Sinks.Elasticsearch.Tests.Templating +{ + public class Sendsv6TemplateTests : ElasticsearchSinkTestsBase + { + private readonly Tuple _templatePut; + + public Sendsv6TemplateTests() + { + _options.AutoRegisterTemplate = true; + _options.AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv6; + + var loggerConfig = new LoggerConfiguration() + .MinimumLevel.Debug() + .Enrich.WithMachineName() + .WriteTo.ColoredConsole() + .WriteTo.Elasticsearch(_options); + + var logger = loggerConfig.CreateLogger(); + using (logger as IDisposable) + { + logger.Error("Test exception. Should not contain an embedded exception object."); + } + + this._seenHttpPosts.Should().NotBeNullOrEmpty().And.HaveCount(1); + this._seenHttpPuts.Should().NotBeNullOrEmpty().And.HaveCount(1); + _templatePut = this._seenHttpPuts[0]; + } + + [Fact] + public void ShouldRegisterTheCorrectTemplateOnRegistration() + { + + var method = typeof(Sendsv6TemplateTests).GetMethod(nameof(ShouldRegisterTheCorrectTemplateOnRegistration)); + JsonEquals(_templatePut.Item2, method, "template_v6.json"); + } + + [Fact] + public void TemplatePutToCorrectUrl() + { + var uri = _templatePut.Item1; + uri.AbsolutePath.Should().Be("/_template/serilog-events-template"); + } + + protected void JsonEquals(string json, MethodBase method, string fileName = null) + { +#if DOTNETCORE + var assembly = typeof(Sendsv6TemplateTests).GetTypeInfo().Assembly; +#else + var assembly = Assembly.GetExecutingAssembly(); +#endif + var expected = TestDataHelper.ReadEmbeddedResource(assembly, fileName ?? "template.json"); + + var nJson = JObject.Parse(json); + var nOtherJson = JObject.Parse(expected); + var equals = JToken.DeepEquals(nJson, nOtherJson); + if (equals) return; + expected.Should().BeEquivalentTo(json); + } + } +} \ No newline at end of file diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/template_v2.json b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/template_v2.json new file mode 100644 index 00000000..6a45a045 --- /dev/null +++ b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/template_v2.json @@ -0,0 +1,81 @@ +{ + "template": "logstash-*", + "settings": { + "index.refresh_interval": "5s" + }, + "mappings": { + "_default_": { + "_all": { + "enabled": true, + "omit_norms" : true + }, + "dynamic_templates": [ + { + "numerics_in_fields": { + "path_match":"fields\\.[\\d+]$", + "match_pattern":"regex", + "mapping": { + "type":"string", + "index":"analyzed", + "omit_norms":true + } + } + }, + { + "string_fields": { + "match": "*", + "match_mapping_type": "string", + "mapping": { + "type": "string", + "index": "analyzed", + "omit_norms": true, + "fields": { + "raw": { + "type": "string", + "index": "not_analyzed", + "ignore_above": 256 + } + } + } + } + } + ], + "properties": { + "message": { + "type": "string", + "index": "analyzed" + }, + "exceptions": { + "type": "nested", + "properties": { + "Depth": { + "type": "integer" + }, + "RemoteStackIndex": { + "type": "integer" + }, + "HResult": { + "type": "integer" + }, + "StackTraceString": { + "type": "string", + "index": "analyzed" + }, + "RemoteStackTraceString": { + "type": "string", + "index": "analyzed" + }, + "ExceptionMessage": { + "type": "object", + "properties": { + "MemberType": { + "type": "integer" + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/template_v5.json b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/template_v5.json new file mode 100644 index 00000000..cee50c8e --- /dev/null +++ b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/template_v5.json @@ -0,0 +1,81 @@ +{ + "template": "logstash-*", + "settings": { + "index.refresh_interval": "5s" + }, + "mappings": { + "_default_": { + "_all": { + "enabled": true, + "norms" : false + }, + "dynamic_templates": [ + { + "numerics_in_fields": { + "path_match":"fields\\.[\\d+]$", + "match_pattern":"regex", + "mapping": { + "type":"text", + "index":true, + "norms":false + } + } + }, + { + "string_fields": { + "match": "*", + "match_mapping_type": "string", + "mapping": { + "type": "text", + "index": true, + "norms": false, + "fields": { + "raw": { + "type": "keyword", + "index": true, + "ignore_above": 256 + } + } + } + } + } + ], + "properties": { + "message": { + "type": "text", + "index": "analyzed" + }, + "exceptions": { + "type": "nested", + "properties": { + "Depth": { + "type": "integer" + }, + "RemoteStackIndex": { + "type": "integer" + }, + "HResult": { + "type": "integer" + }, + "StackTraceString": { + "type": "text", + "index": "analyzed" + }, + "RemoteStackTraceString": { + "type": "text", + "index": "analyzed" + }, + "ExceptionMessage": { + "type": "object", + "properties": { + "MemberType": { + "type": "integer" + } + } + } + } + } + } + } + } +} diff --git a/test/Serilog.Sinks.Elasticsearch.Tests/Templating/template_v6.json b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/template_v6.json new file mode 100644 index 00000000..f604151e --- /dev/null +++ b/test/Serilog.Sinks.Elasticsearch.Tests/Templating/template_v6.json @@ -0,0 +1,77 @@ +{ + "template": "logstash-*", + "settings": { + "index.refresh_interval": "5s" + }, + "mappings": { + "_default_": { + "dynamic_templates": [ + { + "numerics_in_fields": { + "path_match":"fields\\.[\\d+]$", + "match_pattern":"regex", + "mapping": { + "type":"text", + "index":true, + "norms":false + } + } + }, + { + "string_fields": { + "match": "*", + "match_mapping_type": "string", + "mapping": { + "type": "text", + "index": true, + "norms": false, + "fields": { + "raw": { + "type": "keyword", + "index": true, + "ignore_above": 256 + } + } + } + } + } + ], + "properties": { + "message": { + "type": "text", + "index": "analyzed" + }, + "exceptions": { + "type": "nested", + "properties": { + "Depth": { + "type": "integer" + }, + "RemoteStackIndex": { + "type": "integer" + }, + "HResult": { + "type": "integer" + }, + "StackTraceString": { + "type": "text", + "index": "analyzed" + }, + "RemoteStackTraceString": { + "type": "text", + "index": "analyzed" + }, + "ExceptionMessage": { + "type": "object", + "properties": { + "MemberType": { + "type": "integer" + } + } + } + } + } + } + } + } +}