├── .github ├── CODEOWNERS ├── .github.csproj ├── workflows │ ├── pre-commit.yml │ ├── docs-cleanup.yml │ ├── github-commands-comment.yml │ ├── docs-build.yml │ ├── bootstrap │ │ └── action.yml │ ├── test-reporter.yml │ ├── test-docs.yml │ └── update-specs.yml ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── update-specs.yml ├── nuget-icon.png ├── tests ├── Elastic.CommonSchema.Tests │ ├── Specs │ │ └── spec_version.txt │ ├── Elastic.CommonSchema.Tests.csproj │ └── Repro │ │ ├── GithubIssue29.cs │ │ ├── GithubIssue178.cs │ │ ├── GithubIssue438.cs │ │ └── GithubIssue316.cs ├── .runsettings ├── Elastic.Apm.Test.Common │ ├── Elastic.Apm.Test.Common.csproj │ ├── NoopPayloadSender.cs │ └── TestApmAgent.cs ├── Elastic.Serilog.Sinks.Tests │ ├── ConfigurationBuilderExtensions.cs │ ├── Elastic.Serilog.Sinks.Tests.csproj │ └── JsonStringConfigSource.cs ├── Elastic.CommonSchema.Log4net.Tests │ ├── Elastic.CommonSchema.Log4net.Tests.csproj │ ├── TestAppender.cs │ └── LogTestsBase.cs ├── Elastic.Apm.SerilogEnricher.Tests │ └── Elastic.Apm.SerilogEnricher.Tests.csproj ├── Elastic.Apm.Disabled.Serilog.Tests │ └── Elastic.Apm.Disabled.Serilog.Tests.csproj ├── Elastic.Apm.NLog.Tests │ └── Elastic.Apm.NLog.Tests.csproj ├── Elastic.CommonSchema.NLog.Tests │ ├── Elastic.CommonSchema.NLog.Tests.csproj │ ├── EcsFieldsInTemplateTests.cs │ └── OutputTests.cs ├── Elastic.CommonSchema.Serilog.Tests │ ├── Repro │ │ ├── GithubIssue225.cs │ │ ├── GithubIssue31.cs │ │ └── GithubIssue30.cs │ └── OutputTests.cs └── Directory.Build.props ├── docs ├── reference │ ├── images │ │ └── ecs-dotnet-overview.png │ ├── _enrichers_2.md │ ├── data-shippers.md │ ├── intro_to_xyz.md │ ├── toc.yml │ └── _elasticsearch_security.md ├── docs.csproj └── docset.yml ├── global.json ├── nuget.config ├── examples ├── console-with-extensions-logging │ ├── example-elasticsearch-kibana.png │ ├── appsettings.json │ ├── console-with-extensions-logging.csproj │ └── docker-compose.yml ├── aspnetcore-with-extensions-logging │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── WeatherForecast.cs │ ├── aspnetcore-with-extensions-logging.csproj │ └── Program.cs ├── aspnetcore-with-serilog │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── WeatherForecast.cs │ ├── AspnetCoreExample.csproj │ ├── Controllers │ │ └── WeatherForecastController.cs │ └── Startup.cs ├── Elastic.Extensions.Logging.Example │ ├── appsettings.json │ ├── HighVolumeWorkSimulation.cs │ └── Elastic.Extensions.Logging.Example.csproj ├── playground │ └── playground.csproj ├── Elastic.Extensions.Logging.Console.Example │ ├── Elastic.Extensions.Logging.Console.Example.csproj │ ├── ExampleService.cs │ └── Program.cs ├── ecs-aot-smoketest │ ├── ecs-aot-smoketest.csproj │ └── SerilogExporter.cs └── Elastic.Serilog.Sinks.Example │ └── Elastic.Serilog.Sinks.Example.csproj ├── src ├── Specification │ ├── Specification.csproj │ ├── v8.11.0 │ │ └── composable │ │ │ └── component │ │ │ ├── ecs.json │ │ │ ├── base.json │ │ │ ├── data_stream.json │ │ │ ├── group.json │ │ │ ├── organization.json │ │ │ ├── related.json │ │ │ ├── tracing.json │ │ │ ├── device.json │ │ │ ├── error.json │ │ │ ├── agent.json │ │ │ ├── faas.json │ │ │ ├── registry.json │ │ │ └── rule.json │ ├── v8.3.1 │ │ └── composable │ │ │ └── component │ │ │ ├── ecs.json │ │ │ ├── base.json │ │ │ ├── data_stream.json │ │ │ ├── group.json │ │ │ ├── organization.json │ │ │ ├── related.json │ │ │ ├── tracing.json │ │ │ ├── error.json │ │ │ ├── agent.json │ │ │ ├── registry.json │ │ │ ├── faas.json │ │ │ └── rule.json │ ├── v8.4.0 │ │ └── composable │ │ │ └── component │ │ │ ├── ecs.json │ │ │ ├── base.json │ │ │ ├── data_stream.json │ │ │ ├── group.json │ │ │ ├── organization.json │ │ │ ├── related.json │ │ │ ├── tracing.json │ │ │ ├── error.json │ │ │ ├── agent.json │ │ │ ├── registry.json │ │ │ └── faas.json │ ├── v8.6.0 │ │ └── composable │ │ │ └── component │ │ │ ├── ecs.json │ │ │ ├── base.json │ │ │ ├── data_stream.json │ │ │ ├── group.json │ │ │ ├── organization.json │ │ │ ├── related.json │ │ │ ├── tracing.json │ │ │ ├── device.json │ │ │ ├── error.json │ │ │ ├── agent.json │ │ │ ├── registry.json │ │ │ └── faas.json │ ├── v9.0.0 │ │ └── composable │ │ │ └── component │ │ │ ├── ecs.json │ │ │ ├── base.json │ │ │ ├── data_stream.json │ │ │ ├── group.json │ │ │ ├── organization.json │ │ │ ├── tracing.json │ │ │ ├── related.json │ │ │ ├── error.json │ │ │ ├── device.json │ │ │ ├── agent.json │ │ │ ├── faas.json │ │ │ └── registry.json │ └── README.md ├── Elastic.Extensions.Logging.Common │ ├── README.md │ ├── LogEventJsonContext.cs │ ├── Elastic.Extensions.Logging.Common.csproj │ ├── ILogEventCreationOptions.cs │ └── LogEventToEcsHelper.cs ├── NullableExtensions.cs ├── Elastic.CommonSchema.Serilog │ ├── SpecialKeys.cs │ ├── Elastic.CommonSchema.Serilog.csproj │ ├── Adapters │ │ └── IHttpAdapter.cs │ └── ScalarPropertyExtensions.cs ├── Elastic.CommonSchema.NLog │ ├── NLogEcsJsonContext.cs │ ├── NlogEcsDocumentCreationOptions.cs │ └── Elastic.CommonSchema.NLog.csproj ├── Elastic.Serilog.Enrichers.Web │ ├── README.md │ └── Elastic.Serilog.Enrichers.Web.csproj ├── Elastic.CommonSchema │ ├── Entities.cs │ ├── MetadataDictionary.cs │ ├── Entities.ShouldSerialize.Generated.cs │ ├── Elastic.CommonSchema.csproj │ └── Serialization │ │ └── SnakeCaseJsonNamingPolicy.cs ├── Elastic.Ingest.Elasticsearch.CommonSchema │ └── Elastic.Ingest.Elasticsearch.CommonSchema.csproj ├── Elastic.Apm.SerilogEnricher │ ├── Elastic.Apm.SerilogEnricher.csproj │ └── ElasticApmEnricherExtension.cs ├── Elastic.Serilog.Sinks │ └── Elastic.Serilog.Sinks.csproj ├── Elastic.Extensions.Logging │ ├── ElasticsearchLoggerOptionsSetup.cs │ ├── Options │ │ ├── DataStreamNameOptions.cs │ │ ├── IndexNameOptions.cs │ │ └── NodePoolType.cs │ ├── IChannelProvider.cs │ ├── IChannelSetup.cs │ ├── InternalChannelSetup.cs │ └── Elastic.Extensions.Logging.csproj ├── Elastic.NLog.Targets │ ├── ElasticPoolType.cs │ └── Elastic.NLog.Targets.csproj ├── Elastic.CommonSchema.Log4net │ ├── Elastic.CommonSchema.Log4net.csproj │ └── EcsLayout.cs ├── Elastic.CommonSchema.BenchmarkDotNetExporter │ ├── Domain │ │ ├── BenchmarkSimplifiedWorkloadCounts.cs │ │ ├── BenchmarkMeasurementStage.cs │ │ ├── BenchmarkGit.cs │ │ ├── BenchmarkAgent.cs │ │ ├── BenchmarkJobConfig.cs │ │ └── BenchmarkEvent.cs │ └── Elastic.CommonSchema.BenchmarkDotNetExporter.csproj ├── Elastic.Apm.NLog │ ├── ApmSpanIdLayoutRenderer.cs │ ├── ApmServiceVersionLayoutRenderer.cs │ ├── ApmServiceNodeNameLayoutRenderer.cs │ ├── Elastic.Apm.NLog.csproj │ ├── ApmServiceNameLayoutRenderer.cs │ ├── ApmTraceIdLayoutRenderer.cs │ └── ApmTransactionIdLayoutRenderer.cs └── Elastic.Extensions.Logging.Console │ ├── README.md │ ├── Elastic.Extensions.Logging.Console.csproj │ ├── LoggingBuilderExtensions.cs │ └── EcsConsoleFormatterOptions.cs ├── .ci.runsettings ├── tests-integration ├── .runsettings ├── Elastic.NLog.Targets.IntegrationTests │ ├── LoggingCluster.cs │ └── Elastic.NLog.Targets.IntegrationTests.csproj ├── Elastic.Extensions.Logging.IntegrationTests │ ├── LoggingCluster.cs │ └── Elastic.Extensions.Logging.IntegrationTests.csproj ├── Elastic.CommonSchema.BenchmarkDotNetExporter.IntegrationTests │ ├── BenchmarkCluster.cs │ ├── Md5VsSha256.cs │ └── Elastic.CommonSchema.BenchmarkDotNetExporter.IntegrationTests.csproj ├── Elasticsearch.IntegrationDefaults │ └── Elasticsearch.IntegrationDefaults.csproj ├── Elastic.Ingest.Elasticsearch.CommonSchema.IntegrationTests │ ├── IngestionCluster.cs │ ├── IntegrationTestBase.cs │ ├── Elastic.Ingest.Elasticsearch.CommonSchema.IntegrationTests.csproj │ └── CustomEventWriter.cs ├── Elastic.Serilog.Sinks.IntegrationTests │ ├── Elastic.Serilog.Sinks.IntegrationTests.csproj │ └── SerilogTestBase.cs └── Directory.Build.props ├── tools ├── Elastic.CommonSchema.Benchmarks │ ├── Program.cs │ └── Elastic.CommonSchema.Benchmarks.csproj └── Elastic.CommonSchema.Generator │ ├── Projection │ ├── IndexComponent.cs │ └── IndexTemplate.cs │ ├── Schema │ ├── DTO │ │ ├── FieldLevel.cs │ │ ├── YamlSchemaReusedHere.cs │ │ ├── FieldAllowedValue.cs │ │ ├── FieldMultiField.cs │ │ └── FieldType.cs │ └── EcsSchema.cs │ ├── Views │ ├── CodeTemplatePage.cs │ ├── Entities.ShouldSerialize.Generated.cshtml │ ├── EcsJsonContext.Generated.cshtml │ └── AssignableInterfaces.Generated.cshtml │ └── CodeConfiguration.cs ├── .pre-commit-config.yaml ├── .gitattributes ├── dotnet-tools.json ├── issue_template.md ├── .gitignore └── Directory.Build.props /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | /.github/workflows @elastic/observablt-ci -------------------------------------------------------------------------------- /nuget-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/ecs-dotnet/HEAD/nuget-icon.png -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Tests/Specs/spec_version.txt: -------------------------------------------------------------------------------- 1 | 868cdfb178bc1959003c62aefed4d5b0c10af4c0 -------------------------------------------------------------------------------- /docs/reference/images/ecs-dotnet-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/ecs-dotnet/HEAD/docs/reference/images/ecs-dotnet-overview.png -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.100", 4 | "rollForward": "latestFeature", 5 | "allowPrerelease": false 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/console-with-extensions-logging/example-elasticsearch-kibana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/ecs-dotnet/HEAD/examples/console-with-extensions-logging/example-elasticsearch-kibana.png -------------------------------------------------------------------------------- /docs/docs.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | False 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.github/.github.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | False 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/aspnetcore-with-extensions-logging/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Information" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Specification/Specification.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | False 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging.Common/README.md: -------------------------------------------------------------------------------- 1 | # Elastic.Extensions.Logging.Common 2 | 3 | Transitive dependency for `Elastic.Extensions.Logging` and `Elastic.Extensions.Logging.Console`. 4 | 5 | Should not be installed directly. -------------------------------------------------------------------------------- /examples/aspnetcore-with-extensions-logging/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /.ci.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/NullableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace System; 4 | internal static class NullableStringExtensions { 5 | internal static bool IsNullOrEmpty([NotNullWhen(false)] this string? data) => 6 | string.IsNullOrEmpty(data); 7 | } 8 | -------------------------------------------------------------------------------- /tests-integration/.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | namespace Elastic.CommonSchema.Benchmarks; 4 | 5 | internal class Program 6 | { 7 | public static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); 8 | } 9 | -------------------------------------------------------------------------------- /examples/aspnetcore-with-serilog/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information", 7 | "Elastic.Apm": "Error" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/aspnetcore-with-serilog/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information", 7 | "Elastic.Apm": "Error" 8 | } 9 | }, 10 | "AllowedHosts": "*" 11 | } 12 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.Serilog/SpecialKeys.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | namespace Elastic.CommonSchema.Serilog; 6 | 7 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: pre-commit 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | - 1.* 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | pre-commit: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: elastic/oblt-actions/pre-commit@v1 -------------------------------------------------------------------------------- /tests/Elastic.Apm.Test.Common/Elastic.Apm.Test.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/reference/_enrichers_2.md: -------------------------------------------------------------------------------- 1 | --- 2 | mapped_pages: 3 | - https://www.elastic.co/guide/en/ecs-logging/dotnet/current/_enrichers_2.html 4 | --- 5 | 6 | # Enrichers [_enrichers_2] 7 | 8 | Enrichers can be installed next to `Log Formatters` and `Data Shippers` to automatically enrich the ECS json that gets produced. 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/docs-cleanup.yml: -------------------------------------------------------------------------------- 1 | name: docs-cleanup 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - closed 7 | 8 | jobs: 9 | docs-preview: 10 | uses: elastic/docs-builder/.github/workflows/preview-cleanup.yml@main 11 | permissions: 12 | contents: none 13 | id-token: write 14 | deployments: write 15 | -------------------------------------------------------------------------------- /examples/Elastic.Extensions.Logging.Example/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "Elasticsearch": { 4 | "ShipTo": { 5 | "NodePoolType": "Static", 6 | "NodeUris": [ "http://localhost:9200" ] 7 | } 8 | }, 9 | "LogLevel" : { 10 | "Default": "Trace", 11 | "Microsoft": "Warning" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /examples/aspnetcore-with-extensions-logging/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | namespace aspnetcore_with_extensions_logging; 2 | 3 | public class WeatherForecast 4 | { 5 | public DateTime Date { get; set; } 6 | 7 | public int TemperatureC { get; set; } 8 | 9 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 10 | 11 | public string? Summary { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | # GitHub actions 5 | - package-ecosystem: "github-actions" 6 | directories: 7 | - "/" 8 | - "/.github/workflows/*" 9 | schedule: 10 | interval: "weekly" 11 | day: "sunday" 12 | time: "22:00" 13 | groups: 14 | github-actions: 15 | patterns: 16 | - "*" 17 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v2.2.3 4 | hooks: 5 | - id: check-case-conflict 6 | - id: check-executables-have-shebangs 7 | - id: check-merge-conflict 8 | 9 | - repo: https://github.com/elastic/apm-pipeline-library 10 | rev: current 11 | hooks: 12 | - id: check-bash-syntax 13 | -------------------------------------------------------------------------------- /docs/docset.yml: -------------------------------------------------------------------------------- 1 | project: 'ECS Logging .NET' 2 | products: 3 | - id: ecs-logging 4 | cross_links: 5 | - apm-agent-dotnet 6 | - beats 7 | - docs-content 8 | - ecs 9 | - ecs-logging 10 | toc: 11 | - toc: reference 12 | subs: 13 | ecs-ref: "https://www.elastic.co/guide/en/ecs/current" 14 | stack: "Elastic Stack" 15 | es: "Elasticsearch" 16 | filebeat: "Filebeat" 17 | -------------------------------------------------------------------------------- /tests/Elastic.Serilog.Sinks.Tests/ConfigurationBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | 3 | namespace Elastic.Serilog.Sinks.Tests; 4 | 5 | internal static class ConfigurationBuilderExtensions 6 | { 7 | public static IConfigurationBuilder AddJsonString(this IConfigurationBuilder builder, string json) => 8 | builder.Add(new JsonStringConfigSource(json)); 9 | } 10 | -------------------------------------------------------------------------------- /.github/workflows/github-commands-comment.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: github-commands-comment 3 | 4 | on: 5 | pull_request_target: 6 | types: 7 | - opened 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | comment: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | pull-requests: write 17 | steps: 18 | - uses: elastic/oblt-actions/elastic/github-commands@v1 19 | -------------------------------------------------------------------------------- /examples/aspnetcore-with-serilog/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AspnetCoreExample 4 | { 5 | public class WeatherForecast 6 | { 7 | public DateTime Date { get; set; } 8 | 9 | public int TemperatureC { get; set; } 10 | 11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 12 | 13 | public string Summary { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.NLog/NLogEcsJsonContext.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace Elastic.CommonSchema.NLog; 4 | 5 | /// 6 | /// 7 | /// 8 | [JsonSerializable(typeof(EcsLayout.NLogEcsDocument))] 9 | [JsonSourceGenerationOptions(DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] 10 | public partial class NLogEcsJsonContext : JsonSerializerContext { } 11 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging.Common/LogEventJsonContext.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace Elastic.Extensions.Logging.Common; 4 | 5 | /// 6 | /// 7 | /// 8 | [JsonSerializable(typeof(LogEvent))] 9 | [JsonSourceGenerationOptions(DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] 10 | public partial class LogEventJsonContext : JsonSerializerContext; 11 | -------------------------------------------------------------------------------- /.github/workflows/docs-build.yml: -------------------------------------------------------------------------------- 1 | name: docs-build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request_target: ~ 8 | merge_group: ~ 9 | 10 | jobs: 11 | docs-preview: 12 | uses: elastic/docs-builder/.github/workflows/preview-build.yml@main 13 | with: 14 | path-pattern: docs/** 15 | permissions: 16 | deployments: write 17 | id-token: write 18 | contents: read 19 | pull-requests: write 20 | -------------------------------------------------------------------------------- /docs/reference/data-shippers.md: -------------------------------------------------------------------------------- 1 | --- 2 | mapped_pages: 3 | - https://www.elastic.co/guide/en/ecs-logging/dotnet/current/data-shippers.html 4 | --- 5 | 6 | # Data shippers [data-shippers] 7 | 8 | Our datashippers integrate with logging frameworks to facilitate sending events (such as logs) to various outputs. 9 | 10 | Currently these shippers support Elastic Cloud & Elasticsearch but other outputs are in the works. 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Elastic.Serilog.Enrichers.Web/README.md: -------------------------------------------------------------------------------- 1 | # Elastic.Serilog.Enrichers.Web 2 | 3 | Adds extension methods for ASP.NET (Core and Full Framework) to enrich emitted ECS data with important HTTP information. 4 | 5 | ```csharp 6 | .UseSerilog((ctx, config) => 7 | { 8 | // Ensure HttpContextAccessor is accessible 9 | var httpAccessor = ctx.Configuration.Get(); 10 | 11 | config 12 | .Enrich.WithEcsHttpContext(httpAccessor); 13 | ``` -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.NLog/NlogEcsDocumentCreationOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Elastic.CommonSchema.NLog; 2 | 3 | internal class NlogEcsDocumentCreationOptions : IEcsDocumentCreationOptions 4 | { 5 | public static NlogEcsDocumentCreationOptions Default { get; } = new(); 6 | public bool IncludeHost { get; set; } = true; 7 | public bool IncludeProcess { get; set; } = false; 8 | public bool IncludeUser { get; set; } = false; 9 | public bool IncludeActivityData { get; set; } = false; 10 | } 11 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/ecs.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-ecs.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "ecs": { 10 | "properties": { 11 | "version": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | } 15 | } 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/ecs.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-ecs.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "ecs": { 10 | "properties": { 11 | "version": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | } 15 | } 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/ecs.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-ecs.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "ecs": { 10 | "properties": { 11 | "version": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | } 15 | } 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/ecs.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-ecs.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "ecs": { 10 | "properties": { 11 | "version": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | } 15 | } 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/ecs.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-ecs.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "ecs": { 10 | "properties": { 11 | "version": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | } 15 | } 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto eol=lf 3 | 4 | # Set default behavior for command prompt diff. 5 | # This gives output on command line taking C# language constructs into consideration (e.g showing class name) 6 | *.cs text diff=csharp 7 | 8 | # Set windows specific files explicitly to crlf line ending 9 | *.cmd eol=crlf 10 | *.bat eol=crlf 11 | *.ps1 eol=crlf 12 | 13 | # Mark files specifically as binary to avoid line ending conversion 14 | *.snk binary 15 | *.png binary -------------------------------------------------------------------------------- /tests-integration/Elastic.NLog.Targets.IntegrationTests/LoggingCluster.cs: -------------------------------------------------------------------------------- 1 | using Elasticsearch.IntegrationDefaults; 2 | using Xunit; 3 | 4 | [assembly: TestFramework("Elastic.Elasticsearch.Xunit.Sdk.ElasticTestFramework", "Elastic.Elasticsearch.Xunit")] 5 | 6 | namespace NLog.Targets.Elastic.IntegrationTests; 7 | 8 | /// Declare our cluster that we want to inject into our test classes 9 | public class LoggingCluster : TestClusterBase 10 | { 11 | public LoggingCluster() : base(9201) { } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema/Entities.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | using Elastic.CommonSchema.Serialization; 3 | 4 | namespace Elastic.CommonSchema; 5 | 6 | // This file only contains manual additions to entities. 7 | // These should be exceptions and not the norm. 8 | // Most of the entities are generated under Entities.Generated.cs 9 | 10 | [JsonConverter(typeof(LogEntityJsonConverter))] 11 | public partial class Log { } 12 | [JsonConverter(typeof(EcsEntityJsonConverter))] 13 | public partial class Ecs { } 14 | 15 | -------------------------------------------------------------------------------- /tests-integration/Elastic.Extensions.Logging.IntegrationTests/LoggingCluster.cs: -------------------------------------------------------------------------------- 1 | using Elasticsearch.IntegrationDefaults; 2 | using Xunit; 3 | 4 | [assembly: TestFramework("Elastic.Elasticsearch.Xunit.Sdk.ElasticTestFramework", "Elastic.Elasticsearch.Xunit")] 5 | 6 | namespace Elastic.Extensions.Logging.IntegrationTests; 7 | 8 | /// Declare our cluster that we want to inject into our test classes 9 | public class LoggingCluster : TestClusterBase 10 | { 11 | public LoggingCluster() : base(9201) { } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Projection/IndexComponent.cs: -------------------------------------------------------------------------------- 1 | namespace Elastic.CommonSchema.Generator.Projection 2 | { 3 | public class IndexComponent 4 | { 5 | public string Name { get; } 6 | public string EcsName { get; } 7 | public string Component { get; } 8 | 9 | public IndexComponent(string name, string component, string schemaVersion) 10 | { 11 | Name = name.PascalCase(); 12 | EcsName = $"ecs_{schemaVersion}_{name}"; 13 | Component = component 14 | .Replace("\"", "\"\""); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema/MetadataDictionary.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | using Elastic.CommonSchema.Serialization; 4 | 5 | namespace Elastic.CommonSchema; 6 | 7 | /// 8 | /// A regular implementation that takes special care to not fail on (de)serialization 9 | /// and preserving the failures 10 | /// 11 | [JsonConverter(typeof(MetadataDictionaryConverter))] 12 | public class MetadataDictionary : Dictionary 13 | { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/Specification/README.md: -------------------------------------------------------------------------------- 1 | # Specification folder 2 | 3 | 4 | This folder provides a local copy of the ECS spec to this repository. 5 | 6 | Used by [`tools/Elastic.CommonSchemaGenerator`](../../tools/Elastic.CommonSchema.Generator) to generate source code under `src` 7 | 8 | No automation exist currently for generating/updating the spec. 9 | 10 | Simply run 11 | 12 | ```bash 13 | dotnet run -c Release --project tools/Elastic.CommonSchema.Generator 14 | ``` 15 | 16 | To kick of the interactive tool to download a new version of the spec and generate all codebases. -------------------------------------------------------------------------------- /src/Elastic.Ingest.Elasticsearch.CommonSchema/Elastic.Ingest.Elasticsearch.CommonSchema.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;netstandard2.1;net8.0 5 | True 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Elastic.Apm.SerilogEnricher/Elastic.Apm.SerilogEnricher.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0;net462;net8.0 4 | Elastic APM Serilog Enricher 5 | Enrich Serilog log messages with APM TraceId and TransactionId. 6 | True 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tests-integration/Elastic.CommonSchema.BenchmarkDotNetExporter.IntegrationTests/BenchmarkCluster.cs: -------------------------------------------------------------------------------- 1 | using Elasticsearch.IntegrationDefaults; 2 | using Xunit; 3 | 4 | [assembly: TestFramework("Elastic.Elasticsearch.Xunit.Sdk.ElasticTestFramework", "Elastic.Elasticsearch.Xunit")] 5 | 6 | namespace Elastic.CommonSchema.BenchmarkDotNetExporter.IntegrationTests 7 | { 8 | /// Declare our cluster that we want to inject into our test classes 9 | public class BenchmarkCluster : TestClusterBase 10 | { 11 | public BenchmarkCluster() : base(9203) { } 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Schema/DTO/FieldLevel.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Runtime.Serialization; 6 | 7 | namespace Elastic.CommonSchema.Generator.Schema.DTO 8 | { 9 | /// 10 | /// ECS level 11 | /// 12 | public enum FieldLevel 13 | { 14 | [EnumMember(Value = "core")] Core, 15 | [EnumMember(Value = "extended")] Extended 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Elastic.Serilog.Sinks/Elastic.Serilog.Sinks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;netstandard2.1;net8.0 5 | enable 6 | True 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/console-with-extensions-logging/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "Elasticsearch": { 4 | "Tags": [ "Development", "Example" ], 5 | "IndexOffset": "00:00", 6 | "IsEnabled": true, 7 | "IncludeScopes": true, 8 | "IncludeHost": true, 9 | "IncludeProcess": true, 10 | "IncludeUser": true, 11 | "ShipTo": { 12 | "NodePoolType": "SingleNode", 13 | "NodeUris": [ "http://localhost:9200" ] 14 | } 15 | }, 16 | "LogLevel" : { 17 | "Default": "Trace", 18 | "Microsoft": "Warning" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /examples/playground/playground.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Log4net.Tests/Elastic.CommonSchema.Log4net.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-base.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "@timestamp": { 10 | "type": "date" 11 | }, 12 | "labels": { 13 | "type": "object" 14 | }, 15 | "message": { 16 | "type": "match_only_text" 17 | }, 18 | "tags": { 19 | "ignore_above": 1024, 20 | "type": "keyword" 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-base.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "@timestamp": { 10 | "type": "date" 11 | }, 12 | "labels": { 13 | "type": "object" 14 | }, 15 | "message": { 16 | "type": "match_only_text" 17 | }, 18 | "tags": { 19 | "ignore_above": 1024, 20 | "type": "keyword" 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-base.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "@timestamp": { 10 | "type": "date" 11 | }, 12 | "labels": { 13 | "type": "object" 14 | }, 15 | "message": { 16 | "type": "match_only_text" 17 | }, 18 | "tags": { 19 | "ignore_above": 1024, 20 | "type": "keyword" 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-base.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "@timestamp": { 10 | "type": "date" 11 | }, 12 | "labels": { 13 | "type": "object" 14 | }, 15 | "message": { 16 | "type": "match_only_text" 17 | }, 18 | "tags": { 19 | "ignore_above": 1024, 20 | "type": "keyword" 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Benchmarks/Elastic.CommonSchema.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Tests/Elastic.CommonSchema.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Schema/DTO/YamlSchemaReusedHere.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Elastic.CommonSchema.Generator.Schema.DTO 4 | { 5 | [JsonObject(MemberSerialization.OptIn)] 6 | public class YamlSchemaReusedHere 7 | { 8 | [JsonProperty("full")] 9 | public string Full { get; set; } 10 | 11 | [JsonProperty("schema_name")] 12 | public string SchemaName { get; set; } 13 | 14 | [JsonProperty("short")] 15 | public string Short { get; set; } 16 | 17 | [JsonProperty("beta")] 18 | public string Beta { get; set; } 19 | 20 | [JsonProperty("normalize")] 21 | public string[] Normalize { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Tests/Repro/GithubIssue29.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using Xunit; 4 | 5 | namespace Elastic.CommonSchema.Tests.Repro 6 | { 7 | public class GithubIssue29 8 | { 9 | [Fact] 10 | public void Reproduce() 11 | { 12 | // Metadata properties with null values should be serialised 13 | var uniqueName = Guid.NewGuid().ToString(); 14 | var root = new EcsDocument 15 | { 16 | Metadata = new MetadataDictionary 17 | { 18 | { uniqueName, null } 19 | } 20 | }; 21 | 22 | var serialised = root.Serialize(); 23 | serialised.Should().Contain($"\"{uniqueName}\":null"); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests-integration/Elastic.Extensions.Logging.IntegrationTests/Elastic.Extensions.Logging.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/Elastic.Apm.Test.Common/NoopPayloadSender.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using Elastic.Apm.Api; 6 | using Elastic.Apm.Report; 7 | 8 | namespace Elastic.Apm.Test.Common 9 | { 10 | public class NoopPayloadSender : IPayloadSender 11 | { 12 | public void QueueError(IError error) { } 13 | 14 | public void QueueMetrics(IMetricSet metrics) { } 15 | 16 | public void QueueSpan(ISpan span) { } 17 | 18 | public void QueueTransaction(ITransaction transaction) { } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/bootstrap/action.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bootstrap Checkout 3 | description: Ensures an action that needs to build has access to git tags 4 | 5 | runs: 6 | using: "composite" 7 | steps: 8 | # Ensure we fetch all tags 9 | - shell: bash 10 | run: | 11 | git fetch --prune --unshallow --tags 12 | git tag --list 13 | 14 | # Install .NET version as mandated by global.json 15 | - uses: actions/setup-dotnet@v5 16 | with: 17 | global-json-file: global.json 18 | dotnet-version: | 19 | 6.x 20 | 8.x 21 | 22 | # Setup git config 23 | - uses: elastic/oblt-actions/git/setup@v1 24 | -------------------------------------------------------------------------------- /docs/reference/intro_to_xyz.md: -------------------------------------------------------------------------------- 1 | --- 2 | mapped_pages: 3 | - https://www.elastic.co/guide/en/ecs-logging/dotnet/current/intro_to_xyz.html 4 | --- 5 | 6 | # A note on the Metadata property [intro_to_xyz] 7 | 8 | The C# `EcsDocument` type includes a property called `Metadata` with the signature: 9 | 10 | ```csharp 11 | /// 12 | /// Container for additional metadata against this event. 13 | /// 14 | [JsonPropertyName("metadata"), DataMember(Name = "metadata")] 15 | public IDictionary Metadata { get; set; } 16 | ``` 17 | 18 | This property is not part of the ECS specification, but is included as a means to index supplementary information. 19 | 20 | -------------------------------------------------------------------------------- /examples/Elastic.Extensions.Logging.Console.Example/Elastic.Extensions.Logging.Console.Example.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-base.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "@timestamp": { 10 | "type": "date" 11 | }, 12 | "labels": { 13 | "type": "object" 14 | }, 15 | "message": { 16 | "type": "match_only_text" 17 | }, 18 | "tags": { 19 | "ignore_above": 1024, 20 | "synthetic_source_keep": "none", 21 | "type": "keyword" 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/data_stream.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-data_stream.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "data_stream": { 10 | "properties": { 11 | "dataset": { 12 | "type": "constant_keyword" 13 | }, 14 | "namespace": { 15 | "type": "constant_keyword" 16 | }, 17 | "type": { 18 | "type": "constant_keyword" 19 | } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/data_stream.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-data_stream.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "data_stream": { 10 | "properties": { 11 | "dataset": { 12 | "type": "constant_keyword" 13 | }, 14 | "namespace": { 15 | "type": "constant_keyword" 16 | }, 17 | "type": { 18 | "type": "constant_keyword" 19 | } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/data_stream.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-data_stream.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "data_stream": { 10 | "properties": { 11 | "dataset": { 12 | "type": "constant_keyword" 13 | }, 14 | "namespace": { 15 | "type": "constant_keyword" 16 | }, 17 | "type": { 18 | "type": "constant_keyword" 19 | } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/data_stream.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-data_stream.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "data_stream": { 10 | "properties": { 11 | "dataset": { 12 | "type": "constant_keyword" 13 | }, 14 | "namespace": { 15 | "type": "constant_keyword" 16 | }, 17 | "type": { 18 | "type": "constant_keyword" 19 | } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/data_stream.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-data_stream.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "data_stream": { 10 | "properties": { 11 | "dataset": { 12 | "type": "constant_keyword" 13 | }, 14 | "namespace": { 15 | "type": "constant_keyword" 16 | }, 17 | "type": { 18 | "type": "constant_keyword" 19 | } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging/ElasticsearchLoggerOptionsSetup.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using Elastic.Extensions.Logging.Options; 6 | using Microsoft.Extensions.Logging.Configuration; 7 | using Microsoft.Extensions.Options; 8 | 9 | namespace Elastic.Extensions.Logging; 10 | 11 | internal class ElasticsearchLoggerOptionsSetup(ILoggerProviderConfiguration providerConfiguration) 12 | : ConfigureFromConfigurationOptions(providerConfiguration.Configuration); 13 | -------------------------------------------------------------------------------- /src/Elastic.NLog.Targets/ElasticPoolType.cs: -------------------------------------------------------------------------------- 1 | using Elastic.Transport; 2 | 3 | namespace NLog.Targets 4 | { 5 | /// 6 | /// The type of connection pool for Elasticsearch 7 | /// 8 | public enum ElasticPoolType 9 | { 10 | /// Not configured 11 | Unknown = 0, 12 | /// 13 | SingleNode, 14 | /// 15 | Sniffing, 16 | /// 17 | Static, 18 | /// 19 | Sticky, 20 | /// 21 | StickySniffing, 22 | /// 23 | Cloud 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging/Options/DataStreamNameOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Elastic.Extensions.Logging.Options 2 | { 3 | /// 4 | /// Provides options to control the datastream to write Elasticsearch logs too 5 | /// 6 | public class DataStreamNameOptions 7 | { 8 | /// Generic type describing the data. Defaults to 'logs', not recommended to change this 9 | public string Type { get; set; } = "logs"; 10 | 11 | /// Describes the data ingested and its structure 12 | public string DataSet { get; set; } = "dotnet"; 13 | 14 | /// User-configurable arbitrary grouping 15 | public string Namespace { get; set; } = "default"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging/IChannelProvider.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using Elastic.Channels; 6 | 7 | namespace Elastic.Extensions.Logging 8 | { 9 | /// 10 | /// Instantiates and manages 11 | /// 12 | internal interface IChannelProvider 13 | { 14 | /// 15 | /// Provides instance managed by provider 16 | /// 17 | /// 18 | IBufferedChannel GetChannel(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests-integration/Elastic.NLog.Targets.IntegrationTests/Elastic.NLog.Targets.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | false 6 | NLog.Targets.Elastic.IntegrationTests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests-integration/Elasticsearch.IntegrationDefaults/Elasticsearch.IntegrationDefaults.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | Library 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.Log4net/Elastic.CommonSchema.Log4net.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;netstandard2.1;net462;net8.0 5 | Elastic Common Schema (ECS) log4net Layout 6 | log4net Layout that formats log events in accordance with Elastic Common Schema (ECS). 7 | True 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "minver-cli": { 6 | "version": "2.3.1", 7 | "commands": [ 8 | "minver" 9 | ], 10 | "rollForward": false 11 | }, 12 | "assembly-differ": { 13 | "version": "0.14.0", 14 | "commands": [ 15 | "assembly-differ" 16 | ], 17 | "rollForward": false 18 | }, 19 | "release-notes": { 20 | "version": "0.6.0", 21 | "commands": [ 22 | "release-notes" 23 | ], 24 | "rollForward": false 25 | }, 26 | "nupkg-validator": { 27 | "version": "0.7.0", 28 | "commands": [ 29 | "nupkg-validator" 30 | ], 31 | "rollForward": false 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/group.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-group.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "group": { 10 | "properties": { 11 | "domain": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "id": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "name": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | } 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/group.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-group.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "group": { 10 | "properties": { 11 | "domain": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "id": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "name": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | } 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/group.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-group.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "group": { 10 | "properties": { 11 | "domain": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "id": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "name": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | } 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/group.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-group.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "group": { 10 | "properties": { 11 | "domain": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "id": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "name": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | } 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/group.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-group.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "group": { 10 | "properties": { 11 | "domain": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "id": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "name": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | } 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/Elastic.Apm.SerilogEnricher.Tests/Elastic.Apm.SerilogEnricher.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/aspnetcore-with-extensions-logging/aspnetcore-with-extensions-logging.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | aspnetcore_with_extensions_logging 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Tests/Repro/GithubIssue178.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using Xunit; 4 | 5 | namespace Elastic.CommonSchema.Tests.Repro 6 | { 7 | public class GithubIssue178 8 | { 9 | [Fact] 10 | public void Reproduce() 11 | { 12 | var x = new EcsDocument 13 | { 14 | Timestamp = DateTime.UtcNow, 15 | Organization = new Organization { Id = Guid.NewGuid().ToString() } 16 | }; 17 | 18 | var serialized = x.Serialize(); 19 | var deserialized = EcsDocument.Deserialize(serialized); 20 | 21 | deserialized.Should().NotBeNull(); 22 | deserialized.Organization.Should().NotBeNull(); 23 | deserialized.Organization.Id.Should().NotBeNullOrEmpty(); 24 | deserialized.Agent.Should().BeNull(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Views/CodeTemplatePage.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System; 6 | using System.Threading.Tasks; 7 | using RazorLight; 8 | 9 | namespace Elastic.CommonSchema.Generator.Views 10 | { 11 | /// 12 | /// This only exists to make the IDE tooling happy, not actually used to render the templates. 13 | /// 14 | public class CodeTemplatePage : TemplatePage 15 | { 16 | public override Task ExecuteAsync() => throw new NotImplementedException(); 17 | 18 | public Task Execute() => Task.CompletedTask; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging/IChannelSetup.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using Elastic.Ingest.Elasticsearch; 6 | 7 | namespace Elastic.Extensions.Logging 8 | { 9 | /// 10 | /// Provide callbacks to further configure 11 | /// 12 | public interface IChannelSetup 13 | { 14 | /// 15 | /// Provide callbacks to further configure 16 | /// 17 | void ConfigureChannel(ElasticsearchChannelOptionsBase channelOptions); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests-integration/Elastic.Ingest.Elasticsearch.CommonSchema.IntegrationTests/IngestionCluster.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using Elasticsearch.IntegrationDefaults; 6 | using Xunit; 7 | 8 | [assembly: TestFramework("Elastic.Elasticsearch.Xunit.Sdk.ElasticTestFramework", "Elastic.Elasticsearch.Xunit")] 9 | 10 | namespace Elastic.Ingest.Elasticsearch.CommonSchema.IntegrationTests; 11 | 12 | /// Declare our cluster that we want to inject into our test classes 13 | public class IngestionCluster : TestClusterBase 14 | { 15 | public IngestionCluster() : base(9202) { } 16 | } 17 | -------------------------------------------------------------------------------- /docs/reference/toc.yml: -------------------------------------------------------------------------------- 1 | toc: 2 | - file: index.md 3 | - file: setup.md 4 | - file: ecs-dotnet.md 5 | children: 6 | - file: _usage.md 7 | - file: intro_to_xyz.md 8 | - file: _extending_ecsdocument.md 9 | - file: _formatters.md 10 | children: 11 | - file: serilog-formatter.md 12 | - file: nlog-formatter.md 13 | - file: log4net-formatter.md 14 | - file: data-shippers.md 15 | children: 16 | - file: _elasticsearch_security.md 17 | - file: ecs-ingest-channels.md 18 | - file: serilog-data-shipper.md 19 | - file: extensions-logging-data-shipper.md 20 | - file: benchmark-dotnet-data-shipper.md 21 | - file: _enrichers_2.md 22 | children: 23 | - file: apm-serilog-enricher.md 24 | - file: apm-nlog-enricher.md -------------------------------------------------------------------------------- /examples/console-with-extensions-logging/console-with-extensions-logging.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | latest 7 | enable 8 | 9 | 10 | 11 | 12 | PreserveNewest 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests-integration/Elastic.Ingest.Elasticsearch.CommonSchema.IntegrationTests/IntegrationTestBase.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using Elastic.Clients.Elasticsearch; 6 | using Elastic.Elasticsearch.Xunit.XunitPlumbing; 7 | using Xunit.Abstractions; 8 | 9 | namespace Elastic.Ingest.Elasticsearch.CommonSchema.IntegrationTests; 10 | 11 | public abstract class IntegrationTestBase : IClusterFixture 12 | { 13 | protected ElasticsearchClient Client { get; } 14 | 15 | protected IntegrationTestBase(IngestionCluster cluster, ITestOutputHelper output) => 16 | Client = cluster.CreateClient(output); 17 | } 18 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/organization.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-organization.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "organization": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "name": { 16 | "fields": { 17 | "text": { 18 | "type": "match_only_text" 19 | } 20 | }, 21 | "ignore_above": 1024, 22 | "type": "keyword" 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/organization.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-organization.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "organization": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "name": { 16 | "fields": { 17 | "text": { 18 | "type": "match_only_text" 19 | } 20 | }, 21 | "ignore_above": 1024, 22 | "type": "keyword" 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/organization.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-organization.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "organization": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "name": { 16 | "fields": { 17 | "text": { 18 | "type": "match_only_text" 19 | } 20 | }, 21 | "ignore_above": 1024, 22 | "type": "keyword" 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/organization.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-organization.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "organization": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "name": { 16 | "fields": { 17 | "text": { 18 | "type": "match_only_text" 19 | } 20 | }, 21 | "ignore_above": 1024, 22 | "type": "keyword" 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/organization.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-organization.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "organization": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "name": { 16 | "fields": { 17 | "text": { 18 | "type": "match_only_text" 19 | } 20 | }, 21 | "ignore_above": 1024, 22 | "type": "keyword" 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests-integration/Elastic.CommonSchema.BenchmarkDotNetExporter.IntegrationTests/Md5VsSha256.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace Elastic.CommonSchema.BenchmarkDotNetExporter.IntegrationTests 6 | { 7 | public class Md5VsSha256 8 | { 9 | private readonly SHA256 _sha256 = SHA256.Create(); 10 | private readonly MD5 _md5 = MD5.Create(); 11 | private byte[] _data; 12 | 13 | [Params(1000, 10000)] 14 | public int N; 15 | 16 | [GlobalSetup] 17 | public void Setup() 18 | { 19 | _data = new byte[N]; 20 | new Random(42).NextBytes(_data); 21 | } 22 | 23 | [Benchmark] 24 | public byte[] Sha256() => _sha256.ComputeHash(_data); 25 | 26 | [Benchmark] 27 | public byte[] Md5() => _md5.ComputeHash(_data); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **ECS integration/library project(s) (e.g. Elastic.CommonSchema.Serilog)**: 11 | 12 | **Is your feature request related to a problem? Please describe.** 13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 14 | 15 | **Describe the solution you'd like** 16 | A clear and concise description of what you want to happen. 17 | 18 | **Describe alternatives you've considered** 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | **Additional context** 22 | Add any other context or screenshots about the feature request here. 23 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.NLog/Elastic.CommonSchema.NLog.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;netstandard2.1;net462;net8.0 5 | Elastic Common Schema (ECS) NLog Layout 6 | NLog Layout that formats log events in accordance with Elastic Common Schema (ECS). 7 | True 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging/Options/IndexNameOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Elastic.Extensions.Logging.Options 4 | { 5 | /// 6 | /// Provides options to configure the naming of the index name to write too. 7 | /// 8 | public class IndexNameOptions 9 | { 10 | /// 11 | /// Gets or sets the format string for the Elastic search index. The current DateTimeOffset is passed as parameter 12 | /// 0. 13 | /// 14 | public string Format { get; set; } = "dotnet-{0:yyyy.MM.dd}"; 15 | 16 | /// 17 | /// Gets or sets the offset to use for the index DateTimeOffset. Default value is null, which uses the system local 18 | /// offset. Use "00:00" for UTC. 19 | /// 20 | public TimeSpan? IndexOffset { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests-integration/Elastic.Ingest.Elasticsearch.CommonSchema.IntegrationTests/Elastic.Ingest.Elasticsearch.CommonSchema.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.Serilog/Elastic.CommonSchema.Serilog.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | netstandard2.0;netstandard2.1;net462;net8.0 6 | Elastic Common Schema (ECS) Serilog Formatter 7 | Serilog TextFormatter that formats log events in accordance with Elastic Common Schema (ECS). 8 | True 9 | enable 10 | latest 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/related.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-related.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "related": { 10 | "properties": { 11 | "hash": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "hosts": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "ip": { 20 | "type": "ip" 21 | }, 22 | "user": { 23 | "ignore_above": 1024, 24 | "type": "keyword" 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/related.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-related.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "related": { 10 | "properties": { 11 | "hash": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "hosts": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "ip": { 20 | "type": "ip" 21 | }, 22 | "user": { 23 | "ignore_above": 1024, 24 | "type": "keyword" 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/related.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-related.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "related": { 10 | "properties": { 11 | "hash": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "hosts": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "ip": { 20 | "type": "ip" 21 | }, 22 | "user": { 23 | "ignore_above": 1024, 24 | "type": "keyword" 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.BenchmarkDotNetExporter/Domain/BenchmarkSimplifiedWorkloadCounts.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Runtime.Serialization; 6 | using System.Text.Json.Serialization; 7 | 8 | namespace Elastic.CommonSchema.BenchmarkDotNetExporter.Domain 9 | { 10 | /// 11 | public class BenchmarkSimplifiedWorkloadCounts 12 | { 13 | /// 14 | [JsonPropertyName("warmup"), DataMember(Name = "warmup")] 15 | public long Warmup { get; set; } 16 | 17 | /// 18 | [JsonPropertyName("measured"), DataMember(Name = "measured")] 19 | public long Measured { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/related.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-related.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "related": { 10 | "properties": { 11 | "hash": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "hosts": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "ip": { 20 | "type": "ip" 21 | }, 22 | "user": { 23 | "ignore_above": 1024, 24 | "type": "keyword" 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests-integration/Elastic.Serilog.Sinks.IntegrationTests/Elastic.Serilog.Sinks.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | latest 6 | False 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.github/workflows/test-reporter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ## Workflow to process the JUnit test results and add a report to the checks. 3 | name: test-reporter 4 | on: 5 | workflow_run: 6 | workflows: 7 | - test 8 | types: 9 | - completed 10 | 11 | permissions: 12 | contents: read 13 | actions: read 14 | checks: write 15 | 16 | jobs: 17 | report: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: elastic/oblt-actions/test-report@v1 21 | with: 22 | artifact: /test-results(.*)/ # artifact name pattern 23 | name: 'Test Report $1' # Name of the check run which will be created 24 | path: "junit-*.xml" # Path to test results (inside artifact .zip) 25 | reporter: java-junit # Format of test results 26 | list-suites: 'failed' 27 | list-tests: 'failed' 28 | -------------------------------------------------------------------------------- /src/Elastic.Apm.NLog/ApmSpanIdLayoutRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using NLog; 3 | using NLog.Config; 4 | using NLog.LayoutRenderers; 5 | 6 | namespace Elastic.Apm.NLog; 7 | 8 | /// 9 | /// Provides ElasticApmSpanId as special logging variable to render the current Elastic APM Span Id 10 | /// 11 | [LayoutRenderer(Name)] 12 | public class ApmSpanIdLayoutRenderer : LayoutRenderer 13 | { 14 | /// 15 | /// ElasticApmSpanId - the variable to use to inject into your logs 16 | /// 17 | public const string Name = "ElasticApmSpanId"; 18 | 19 | /// 20 | protected override void Append(StringBuilder builder, LogEventInfo logEvent) 21 | { 22 | if (!Agent.IsConfigured) return; 23 | if (!Agent.Config.Enabled) return; 24 | builder.Append(Agent.Tracer?.CurrentSpan?.Id); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Elastic.NLog.Targets/Elastic.NLog.Targets.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;netstandard2.1;net8.0 5 | Elasticsearch NLog Target 6 | NLog Target that exports directly to Elastic Cloud or individual Elasticsearch nodes 7 | NLog.Targets 8 | True 9 | enable 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/Elastic.Apm.Disabled.Serilog.Tests/Elastic.Apm.Disabled.Serilog.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Log4net.Tests/TestAppender.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using log4net.Appender; 8 | using log4net.Core; 9 | 10 | namespace Elastic.CommonSchema.Log4net.Tests; 11 | 12 | internal class TestAppender : AppenderSkeleton 13 | { 14 | public List Events { get; } = new(); 15 | 16 | protected override void Append(LoggingEvent loggingEvent) 17 | { 18 | using var writer = new StringWriter(); 19 | 20 | 21 | if (Layout == null) 22 | loggingEvent.WriteRenderedMessage(writer); 23 | else 24 | Layout.Format(writer, loggingEvent); 25 | 26 | Events.Add(writer.ToString()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/Elastic.Apm.Test.Common/TestApmAgent.cs: -------------------------------------------------------------------------------- 1 | namespace Elastic.Apm.Test.Common; 2 | 3 | public static class TestApmAgent 4 | { 5 | static TestApmAgent() 6 | { 7 | var configuration = new MockConfiguration("my-service", "my-service-node-name", "0.2.1", enabled: true); 8 | if (!Agent.IsConfigured) 9 | Agent.Setup(new AgentComponents(payloadSender: new NoopPayloadSender(), configurationReader: configuration)); 10 | } 11 | 12 | public static void Configure() { } 13 | } 14 | 15 | public static class TestDisabledApmAgent 16 | { 17 | static TestDisabledApmAgent() 18 | { 19 | var configuration = new MockConfiguration("my-service", "my-service-node-name", "0.2.1", enabled: false); 20 | if (!Agent.IsConfigured) 21 | Agent.Setup(new AgentComponents(payloadSender: new NoopPayloadSender(), configurationReader: configuration)); 22 | } 23 | public static void Configure() { } 24 | } 25 | -------------------------------------------------------------------------------- /src/Elastic.Apm.NLog/ApmServiceVersionLayoutRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using NLog; 3 | using NLog.Config; 4 | using NLog.LayoutRenderers; 5 | 6 | namespace Elastic.Apm.NLog; 7 | 8 | /// 9 | /// Provides ElasticApmServiceVersion as special logging variable to render the current Elastic APM Service Version 10 | /// 11 | [LayoutRenderer(Name)] 12 | [ThreadAgnostic] 13 | public class ApmServiceVersionLayoutRenderer : LayoutRenderer 14 | { 15 | /// 16 | /// ElasticApmServiceVersion - the variable to use to inject into your logs 17 | /// 18 | public const string Name = "ElasticApmServiceVersion"; 19 | 20 | /// 21 | protected override void Append(StringBuilder builder, LogEventInfo logEvent) 22 | { 23 | if (!Agent.IsConfigured) return; 24 | builder.Append(Agent.Config.ServiceVersion); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.BenchmarkDotNetExporter/Elastic.CommonSchema.BenchmarkDotNetExporter.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0;netstandard2.1 4 | true 5 | Elastic Common Schema (ECS) BenchmarkDotNet exporter 6 | Exports BenchmarkDotNet benchmarks to Elasticsearch using Elastic Common Schema (ECS) format 7 | latest 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging.Console/README.md: -------------------------------------------------------------------------------- 1 | # Elastic.Extensions.Logging.Console 2 | 3 | This package includes formatters and extension methods for `Microsoft.Extensions.Logging.Console` to make it easy to write ECS formatted logs to consoleoutput. 4 | 5 | May be used with `Elastic.Extensions.Logging` to write ECS documents directly to Elasticsearch / Elastic Cloud. 6 | 7 | 8 | ## Usage 9 | 10 | The console logging provider and formatter can be set up using a simple extension method. 11 | 12 | ```csharp 13 | .ConfigureLogging((_, loggingBuilder) => loggingBuilder.AddEcsConsole()) 14 | ``` 15 | 16 | Or indirectly using the types provided in this package: 17 | 18 | ```csharp 19 | .ConfigureLogging((_, loggingBuilder) => 20 | { 21 | loggingBuilder.AddConsole(c=> c.FormatterName = "ecs"); 22 | loggingBuilder.AddConsoleFormatter(); 23 | }) 24 | ``` -------------------------------------------------------------------------------- /src/Elastic.Apm.NLog/ApmServiceNodeNameLayoutRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using NLog; 3 | using NLog.Config; 4 | using NLog.LayoutRenderers; 5 | 6 | namespace Elastic.Apm.NLog; 7 | 8 | /// 9 | /// Provides ElasticApmServiceNodeName as special logging variable to render the current Elastic APM Service Node Name 10 | /// 11 | [LayoutRenderer(Name)] 12 | [ThreadAgnostic] 13 | public class ApmServiceNodeNameLayoutRenderer : LayoutRenderer 14 | { 15 | /// 16 | /// ElasticApmServiceNodeName - the variable to use to inject into your logs 17 | /// 18 | public const string Name = "ElasticApmServiceNodeName"; 19 | 20 | /// 21 | protected override void Append(StringBuilder builder, LogEventInfo logEvent) 22 | { 23 | if (!Agent.IsConfigured) return; 24 | 25 | builder.Append(Agent.Config.ServiceNodeName); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/Elastic.Extensions.Logging.Console.Example/ExampleService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace Elastic.Extensions.Logging.Console.Example; 5 | 6 | /// Simulate work that logs in low volume with some time in between each log call 7 | public class ExampleService : BackgroundService 8 | { 9 | private readonly ILogger _logger; 10 | 11 | public ExampleService(ILogger logger) => _logger = logger; 12 | 13 | protected override async Task ExecuteAsync(CancellationToken ctx) 14 | { 15 | for (var i = 0; i < 100; i++) 16 | { 17 | if (i % 10 == 0) 18 | _logger.LogWarning("We are logging way too much: {CustomData}", i); 19 | else 20 | _logger.LogInformation("We are logging way too much: {CustomData}", i); 21 | if (i % 100 == 0) 22 | await Task.Delay(1, ctx); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/Elastic.Extensions.Logging.Example/HighVolumeWorkSimulation.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Hosting; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Elastic.Extensions.Logging.Example 7 | { 8 | 9 | /// Simulate work that logs in low volume with some time in between each log call 10 | public class HighVolumeWorkSimulation : BackgroundService 11 | { 12 | private readonly ILogger _logger; 13 | 14 | public HighVolumeWorkSimulation(ILogger logger) => _logger = logger; 15 | 16 | protected override async Task ExecuteAsync(CancellationToken ctx) 17 | { 18 | for (var i = 0; i < 100_000; i++) 19 | { 20 | _logger.LogWarning($"We are logging way too much: {i}"); 21 | if (i % 100 == 0) 22 | await Task.Delay(1, ctx); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests-integration/Elastic.Ingest.Elasticsearch.CommonSchema.IntegrationTests/CustomEventWriter.cs: -------------------------------------------------------------------------------- 1 | using System.Buffers; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace Elastic.Ingest.Elasticsearch.CommonSchema.IntegrationTests; 6 | 7 | public class CustomEventWriter : IElasticsearchEventWriter 8 | { 9 | // ReSharper disable once StaticMemberInGenericType 10 | private static readonly JsonSerializerOptions s_serializerOptions = new() { Converters = { new JsonStringEnumConverter() } }; 11 | 12 | public Action, T>? WriteToArrayBuffer 13 | { 14 | get => throw new NotImplementedException(); 15 | set => throw new NotImplementedException(); 16 | } 17 | 18 | public Func? WriteToStreamAsync { get; set; } = 19 | (stream, doc, ctx) => JsonSerializer.SerializeAsync(stream, doc, s_serializerOptions, ctx); 20 | } 21 | -------------------------------------------------------------------------------- /tests/Elastic.Apm.NLog.Tests/Elastic.Apm.NLog.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Tests/Repro/GithubIssue438.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using Xunit; 4 | 5 | namespace Elastic.CommonSchema.Tests.Repro 6 | { 7 | public class GithubIssue438 8 | { 9 | [Fact] 10 | public void Reproduce() 11 | { 12 | // language=json 13 | var json = 14 | """ 15 | { 16 | "@timestamp":"2022-11-08T09:36:37.249Z", 17 | "log.level":"info", 18 | "message":"['vo_phi_pkg\\\\runtime_recon.py']", 19 | "ecs":{"version":"1.6.0"}, 20 | "log":{ 21 | "logger":"root", 22 | "origin":{"file":{"line":90,"name":"main.py"},"function":"prepare_logging"}, 23 | "original":"['vo_phi_pkg\\\\runtime_recon.py']"}, 24 | "process":{"name":"MainProcess","pid":35436,"thread":{"id":13180,"name":"MainThread"}} 25 | } 26 | """; 27 | var entry1 = System.Text.Json.JsonSerializer.Deserialize(json); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | 18 | **ECS integration/library project(s) (e.g. Elastic.CommonSchema.Serilog)**: 19 | 20 | **ECS schema version (e.g. 1.4.0)**: 21 | 22 | **ECS .NET assembly version (e.g. 1.4.2)**: 23 | 24 | **Elasticsearch version (if applicable)**: 25 | 26 | **.NET framework / OS**: 27 | 28 | **Description of the problem, including expected versus actual behavior**: 29 | 30 | **Steps to reproduce**: 31 | 1. 32 | 2. 33 | 3. 34 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/tracing.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-tracing.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "span": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | } 15 | } 16 | }, 17 | "trace": { 18 | "properties": { 19 | "id": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | } 23 | } 24 | }, 25 | "transaction": { 26 | "properties": { 27 | "id": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/tracing.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-tracing.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "span": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | } 15 | } 16 | }, 17 | "trace": { 18 | "properties": { 19 | "id": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | } 23 | } 24 | }, 25 | "transaction": { 26 | "properties": { 27 | "id": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/tracing.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-tracing.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "span": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | } 15 | } 16 | }, 17 | "trace": { 18 | "properties": { 19 | "id": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | } 23 | } 24 | }, 25 | "transaction": { 26 | "properties": { 27 | "id": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/tracing.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-tracing.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "span": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | } 15 | } 16 | }, 17 | "trace": { 18 | "properties": { 19 | "id": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | } 23 | } 24 | }, 25 | "transaction": { 26 | "properties": { 27 | "id": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/tracing.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-tracing.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "span": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | } 15 | } 16 | }, 17 | "trace": { 18 | "properties": { 19 | "id": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | } 23 | } 24 | }, 25 | "transaction": { 26 | "properties": { 27 | "id": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Schema/DTO/FieldAllowedValue.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using Newtonsoft.Json; 6 | 7 | namespace Elastic.CommonSchema.Generator.Schema.DTO 8 | { 9 | public class FieldAllowedValue 10 | { 11 | /// 12 | /// Name of the allowed value. 13 | /// 14 | [JsonProperty("name")] 15 | public string Name { get; set; } 16 | 17 | /// 18 | /// Description of the allowed value. 19 | /// 20 | [JsonProperty("description")] 21 | public string Description { get; set; } 22 | 23 | /// 24 | /// List of allowed values. 25 | /// 26 | [JsonProperty("expected_event_types")] 27 | public string[] ExpectedEventTypes { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging/Options/NodePoolType.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using Elastic.Transport; 6 | 7 | namespace Elastic.Extensions.Logging.Options 8 | { 9 | /// 10 | /// The type of connection pool to use 11 | /// 12 | public enum NodePoolType 13 | { 14 | /// Not configured 15 | Unknown = 0, 16 | /// 17 | SingleNode, 18 | /// 19 | Sniffing, 20 | /// 21 | Static, 22 | /// 23 | Sticky, 24 | /// 25 | StickySniffing, 26 | /// 27 | Cloud 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/Elastic.Extensions.Logging.Example/Elastic.Extensions.Logging.Example.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | latest 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | 14 | **ECS version**: 15 | 16 | **Elasticsearch version (if applicable)**: 17 | 18 | **.NET framework / OS**: 19 | 20 | **Description of the problem, including expected versus actual behavior**: 21 | 22 | **Steps to reproduce**: 23 | 1. 24 | 2. 25 | 3. 26 | 27 | 31 | 32 | **Describe the feature**: -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging/InternalChannelSetup.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System; 6 | using Elastic.Ingest.Elasticsearch; 7 | 8 | namespace Elastic.Extensions.Logging 9 | { 10 | /// 11 | public class ChannelSetup : IChannelSetup 12 | { 13 | private readonly Action> _configureChannel; 14 | 15 | /// 16 | public ChannelSetup(Action> configureChannel) => _configureChannel = configureChannel; 17 | 18 | /// 19 | public void ConfigureChannel(ElasticsearchChannelOptionsBase channelOptions) => 20 | _configureChannel(channelOptions); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Elastic.Apm.NLog/Elastic.Apm.NLog.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0;net462;net8.0 4 | Elastic APM NLog Layout Renderers 5 | Enrich NLog log messages with APM TraceId and TransactionId. 6 | True 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema/Entities.ShouldSerialize.Generated.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | /* 6 | IMPORTANT NOTE 7 | ============== 8 | This file has been generated. 9 | If you wish to submit a PR please modify the original csharp file and submit the PR with that change. Thanks! 10 | */ 11 | 12 | using System; 13 | using System.Collections.Generic; 14 | using System.Text.Json; 15 | using System.Text.Json.Serialization; 16 | 17 | namespace Elastic.CommonSchema; 18 | 19 | public partial class Log 20 | { 21 | [JsonIgnore] 22 | internal bool ShouldSerialize => 23 | FilePath != null || Logger != null || OriginFileLine != null || OriginFileName != null || OriginFunction != null; 24 | } 25 | public partial class Ecs 26 | { 27 | [JsonIgnore] 28 | internal bool ShouldSerialize => 29 | false; 30 | } 31 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging.Common/Elastic.Extensions.Logging.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;netstandard2.1;net8.0 5 | Common Abstactions For ECS For Microsoft.Extensions.Logging 6 | Transient dependency, do not install directly. Common Abstactions For ECS For Microsoft.Extensions.Logging 7 | Logging;LoggerProvider;Elasticsearch;Console;ELK;Kibana;Logstash;Tracing;Diagnostics;Log;Trace;ECS 8 | enable 9 | enable 10 | True 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/related.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-related.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "related": { 10 | "properties": { 11 | "hash": { 12 | "ignore_above": 1024, 13 | "synthetic_source_keep": "none", 14 | "type": "keyword" 15 | }, 16 | "hosts": { 17 | "ignore_above": 1024, 18 | "synthetic_source_keep": "none", 19 | "type": "keyword" 20 | }, 21 | "ip": { 22 | "type": "ip" 23 | }, 24 | "user": { 25 | "ignore_above": 1024, 26 | "synthetic_source_keep": "none", 27 | "type": "keyword" 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Schema/EcsSchema.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Elastic.CommonSchema.Generator.Schema.DTO; 3 | 4 | namespace Elastic.CommonSchema.Generator.Schema; 5 | 6 | public class EcsSchema 7 | { 8 | public IReadOnlyCollection Warnings { get; } 9 | public IReadOnlyDictionary Templates { get; } 10 | public IReadOnlyDictionary Components { get; } 11 | public string GitRef { get; } 12 | public string Version { get; } 13 | public IReadOnlyCollection
Entities { get; } 14 | 15 | public EcsSchema(IReadOnlyCollection
entities, 16 | IReadOnlyCollection warnings, 17 | Dictionary templates, 18 | Dictionary components, 19 | string gitRef, 20 | string version 21 | ) 22 | { 23 | Entities = entities; 24 | Warnings = warnings; 25 | Templates = templates; 26 | Components = components; 27 | GitRef = gitRef; 28 | Version = version; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.BenchmarkDotNetExporter/Domain/BenchmarkMeasurementStage.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Runtime.Serialization; 6 | using System.Text.Json.Serialization; 7 | 8 | namespace Elastic.CommonSchema.BenchmarkDotNetExporter.Domain 9 | { 10 | /// 11 | public class BenchmarkMeasurementStage 12 | { 13 | /// 14 | [JsonPropertyName("iteration_mode"), DataMember(Name = "iteration_mode")] 15 | public string IterationMode { get; set; } 16 | 17 | /// 18 | [JsonPropertyName("iteration_stage"), DataMember(Name = "iteration_stage")] 19 | public string IterationStage { get; set; } 20 | 21 | /// 22 | [JsonPropertyName("operations"), DataMember(Name = "operations")] 23 | public long Operations { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/device.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-device.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "device": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "manufacturer": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "model": { 20 | "properties": { 21 | "identifier": { 22 | "ignore_above": 1024, 23 | "type": "keyword" 24 | }, 25 | "name": { 26 | "ignore_above": 1024, 27 | "type": "keyword" 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/device.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-device.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "device": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "manufacturer": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "model": { 20 | "properties": { 21 | "identifier": { 22 | "ignore_above": 1024, 23 | "type": "keyword" 24 | }, 25 | "name": { 26 | "ignore_above": 1024, 27 | "type": "keyword" 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests-integration/Elastic.CommonSchema.BenchmarkDotNetExporter.IntegrationTests/Elastic.CommonSchema.BenchmarkDotNetExporter.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | false 7 | 8 | 9 | 9.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests-integration/Elastic.Serilog.Sinks.IntegrationTests/SerilogTestBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Elastic.Clients.Elasticsearch; 4 | using Elastic.Elasticsearch.Xunit.XunitPlumbing; 5 | using Elasticsearch.IntegrationDefaults; 6 | using Xunit.Abstractions; 7 | 8 | namespace Elastic.Serilog.Sinks.IntegrationTests; 9 | 10 | public abstract class SerilogTestBase : IClusterFixture 11 | where TCluster : TestClusterBase, new() 12 | { 13 | protected ElasticsearchClient Client { get; } 14 | 15 | protected SerilogTestBase(SerilogCluster cluster, ITestOutputHelper output, Func, ICollection>? alterNodes = null) => 16 | Client = cluster.CreateClient(output, alterNodes); 17 | } 18 | 19 | public abstract class SerilogTestBase : SerilogTestBase 20 | { 21 | protected SerilogTestBase(SerilogCluster cluster, ITestOutputHelper output, Func, ICollection>? alterNodes = null) 22 | : base(cluster, output, alterNodes) { } 23 | } 24 | -------------------------------------------------------------------------------- /examples/Elastic.Extensions.Logging.Console.Example/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | using Elastic.CommonSchema; 4 | using Elastic.Extensions.Logging.Console; 5 | using Elastic.Extensions.Logging.Console.Example; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Microsoft.Extensions.Hosting; 9 | using Microsoft.Extensions.Logging; 10 | using Host = Microsoft.Extensions.Hosting.Host; 11 | 12 | await Host.CreateDefaultBuilder(args) 13 | .UseConsoleLifetime() 14 | .ConfigureAppConfiguration((_, configurationBuilder) => 15 | { 16 | configurationBuilder.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); 17 | }) 18 | .ConfigureLogging((_, loggingBuilder) => loggingBuilder.AddEcsConsole(configure: c => 19 | { 20 | c.MapCustom = l => l.Organization = new Organization { Name = "my-organization" }; 21 | })) 22 | .ConfigureServices((_, services) => 23 | { 24 | services.AddHostedService(); 25 | }) 26 | .Build() 27 | .RunAsync(); 28 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.NLog.Tests/Elastic.CommonSchema.NLog.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | false 7 | NU1701 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging.Common/ILogEventCreationOptions.cs: -------------------------------------------------------------------------------- 1 | using Elastic.CommonSchema; 2 | 3 | namespace Elastic.Extensions.Logging.Common; 4 | 5 | /// 6 | /// 7 | /// 8 | public interface ILogEventCreationOptions : IEcsDocumentCreationOptions 9 | { 10 | /// 11 | /// Gets or sets additional tags to pass in the message, for example you can tag with the environment name ('Development', 12 | /// 'Production', etc). 13 | /// 14 | string[]? Tags { get; set; } 15 | 16 | /// 17 | /// Gets or sets the separate to use for IList semantic values. 18 | /// 19 | string ListSeparator { get; set; } 20 | } 21 | 22 | /// 23 | public interface ILogEventCreationOptions : ILogEventCreationOptions 24 | where TEcsDocument : EcsDocument, new() 25 | { 26 | /// 27 | /// Allows you to enrich using before its being formatted 28 | /// 29 | Action? MapCustom { get; set; } 30 | } 31 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/error.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-error.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "error": { 10 | "properties": { 11 | "code": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "id": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "message": { 20 | "type": "match_only_text" 21 | }, 22 | "stack_trace": { 23 | "fields": { 24 | "text": { 25 | "type": "match_only_text" 26 | } 27 | }, 28 | "type": "wildcard" 29 | }, 30 | "type": { 31 | "ignore_above": 1024, 32 | "type": "keyword" 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/error.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-error.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "error": { 10 | "properties": { 11 | "code": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "id": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "message": { 20 | "type": "match_only_text" 21 | }, 22 | "stack_trace": { 23 | "fields": { 24 | "text": { 25 | "type": "match_only_text" 26 | } 27 | }, 28 | "type": "wildcard" 29 | }, 30 | "type": { 31 | "ignore_above": 1024, 32 | "type": "keyword" 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/error.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-error.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "error": { 10 | "properties": { 11 | "code": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "id": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "message": { 20 | "type": "match_only_text" 21 | }, 22 | "stack_trace": { 23 | "fields": { 24 | "text": { 25 | "type": "match_only_text" 26 | } 27 | }, 28 | "type": "wildcard" 29 | }, 30 | "type": { 31 | "ignore_above": 1024, 32 | "type": "keyword" 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/error.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-error.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "error": { 10 | "properties": { 11 | "code": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "id": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "message": { 20 | "type": "match_only_text" 21 | }, 22 | "stack_trace": { 23 | "fields": { 24 | "text": { 25 | "type": "match_only_text" 26 | } 27 | }, 28 | "type": "wildcard" 29 | }, 30 | "type": { 31 | "ignore_above": 1024, 32 | "type": "keyword" 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/error.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-error.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "error": { 10 | "properties": { 11 | "code": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "id": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "message": { 20 | "type": "match_only_text" 21 | }, 22 | "stack_trace": { 23 | "fields": { 24 | "text": { 25 | "type": "match_only_text" 26 | } 27 | }, 28 | "type": "wildcard" 29 | }, 30 | "type": { 31 | "ignore_above": 1024, 32 | "type": "keyword" 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Elastic.Apm.NLog/ApmServiceNameLayoutRenderer.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Text; 6 | using NLog; 7 | using NLog.Config; 8 | using NLog.LayoutRenderers; 9 | 10 | namespace Elastic.Apm.NLog; 11 | 12 | /// 13 | /// Provides ElasticApmServiceName as special logging variable to render the current Elastic APM Service Name 14 | /// 15 | [LayoutRenderer(Name)] 16 | [ThreadAgnostic] 17 | public class ApmServiceNameLayoutRenderer : LayoutRenderer 18 | { 19 | /// 20 | /// ElasticApmServiceName - the variable to use to inject into your logs 21 | /// 22 | public const string Name = "ElasticApmServiceName"; 23 | 24 | /// 25 | protected override void Append(StringBuilder builder, LogEventInfo logEvent) 26 | { 27 | if (!Agent.IsConfigured) return; 28 | builder.Append(Agent.Config.ServiceName); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/Elastic.Serilog.Sinks.Tests/Elastic.Serilog.Sinks.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | preview 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Elastic.Apm.NLog/ApmTraceIdLayoutRenderer.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Text; 6 | using NLog; 7 | using NLog.Config; 8 | using NLog.LayoutRenderers; 9 | 10 | namespace Elastic.Apm.NLog; 11 | 12 | /// 13 | /// Provides ElasticApmTraceId as special logging variable to render the current Elastic APM Trace Id 14 | /// 15 | [LayoutRenderer(Name)] 16 | public class ApmTraceIdLayoutRenderer : LayoutRenderer 17 | { 18 | /// 19 | /// ElasticApmTraceId - the variable to use to inject into your logs 20 | /// 21 | public const string Name = "ElasticApmTraceId"; 22 | 23 | /// 24 | protected override void Append(StringBuilder builder, LogEventInfo logEvent) 25 | { 26 | if (!Agent.IsConfigured) return; 27 | if (!Agent.Config.Enabled) return; 28 | builder.Append(Agent.Tracer?.CurrentTransaction?.TraceId); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.BenchmarkDotNetExporter/Domain/BenchmarkGit.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Runtime.Serialization; 6 | using System.Text.Json.Serialization; 7 | 8 | namespace Elastic.CommonSchema.BenchmarkDotNetExporter.Domain 9 | { 10 | /// 11 | public class BenchmarkGit 12 | { 13 | /// 14 | [JsonPropertyName("branch"), DataMember(Name = "branch")] 15 | public string BranchName { get; set; } 16 | 17 | /// 18 | [JsonPropertyName("sha"), DataMember(Name = "sha")] 19 | public string Sha { get; set; } 20 | 21 | /// 22 | [JsonPropertyName("commit_message"), DataMember(Name = "commit_message")] 23 | public string CommitMessage { get; set; } 24 | 25 | /// 26 | [JsonPropertyName("repository"), DataMember(Name = "repository")] 27 | public string Repository { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/ecs-aot-smoketest/ecs-aot-smoketest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | ecs_aot_smoketest 7 | enable 8 | enable 9 | true 10 | false 11 | true 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Tests/Repro/GithubIssue316.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using Xunit; 4 | 5 | namespace Elastic.CommonSchema.Tests.Repro 6 | { 7 | public class GithubIssue316 8 | { 9 | [Fact] 10 | public void Reproduce() 11 | { 12 | var json = 13 | @"{""@timestamp"":""2022-11-08T09:36:37.249Z"",""log.level"":""info"",""message"":""['vo_phi_pkg\\\\runtime_recon.py']""" 14 | + @",""ecs"":{""version"":""1.6.0""},""log"":{""logger"":""root""" 15 | + @",""origin"":{""file"":{""line"":90,""name"":""main.py""},""function"":""prepare_logging""},""original"":""['vo_phi_pkg\\\\runtime_recon.py']""}" 16 | + @",""process"":{""name"":""MainProcess"",""pid"":35436,""thread"":{""id"":13180,""name"":""MainThread""}}}"; 17 | 18 | var doc = EcsDocument.Deserialize(json); 19 | 20 | doc.Log.Should().NotBeNull(); 21 | doc.Log.Logger.Should().Be("root"); 22 | doc.Log.Level.Should().Be("info"); 23 | doc.Log.OriginFunction.Should().Be("prepare_logging"); 24 | doc.Log.OriginFileName.Should().Be("main.py"); 25 | doc.Log.OriginFileLine.Should().Be(90); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/aspnetcore-with-serilog/AspnetCoreExample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | false 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.Log4net/EcsLayout.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.IO; 6 | using log4net.Core; 7 | using log4net.Layout; 8 | 9 | namespace Elastic.CommonSchema.Log4net; 10 | 11 | /// 12 | /// Formats log events into a JSON representation that adheres to Elastic Common Schema specification 13 | /// 14 | public class EcsLayout : LayoutSkeleton 15 | { 16 | /// 17 | public override string ContentType => "application/json"; 18 | 19 | /// 20 | public override void ActivateOptions() => IgnoresException = false; 21 | 22 | /// 23 | public override void Format(TextWriter writer, LoggingEvent loggingEvent) 24 | { 25 | var ecsEvent = loggingEvent.ToEcs(); 26 | writer.WriteLine(ecsEvent.Serialize()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Elastic.Apm.NLog/ApmTransactionIdLayoutRenderer.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Text; 6 | using NLog; 7 | using NLog.Config; 8 | using NLog.LayoutRenderers; 9 | 10 | namespace Elastic.Apm.NLog; 11 | 12 | /// 13 | /// Provides ElasticApmTransactionId as special logging variable to render the current Elastic APM Transaction Id 14 | /// 15 | [LayoutRenderer(Name)] 16 | public class ApmTransactionIdLayoutRenderer : LayoutRenderer 17 | { 18 | /// 19 | /// ElasticApmTransactionId - the variable to use to inject into your logs 20 | /// 21 | public const string Name = "ElasticApmTransactionId"; 22 | 23 | /// 24 | protected override void Append(StringBuilder builder, LogEventInfo logEvent) 25 | { 26 | if (!Agent.IsConfigured) return; 27 | if (!Agent.Config.Enabled) return; 28 | builder.Append(Agent.Tracer?.CurrentTransaction?.Id); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docs/reference/_elasticsearch_security.md: -------------------------------------------------------------------------------- 1 | --- 2 | mapped_pages: 3 | - https://www.elastic.co/guide/en/ecs-logging/dotnet/current/_elasticsearch_security.html 4 | --- 5 | 6 | # Elasticsearch security [_elasticsearch_security] 7 | 8 | If Elasticsearch’s security is enabled you will need to ensure you configure a user or API key with enough privileges 9 | 10 | ## Bootstrap [_bootstrap] 11 | 12 | In order for the datashippers to have enough privileges to bootstrap the target datastreams with all the ECS mappings, templates and settings the authenticated security principal needs the following minimum privileges: 13 | 14 | | Type | Privileges | 15 | | --- | --- | 16 | | Cluster | `monitor`, `manage_ilm`, `manage_index_templates`, `manage_pipeline` | 17 | | Index | `manage`, `create_doc` | 18 | 19 | 20 | ## No bootstrap [_no_bootstrap] 21 | 22 | If the datashippers are configured to skip bootstrapping the target destinations all together, the security principal requires the following minimum privileges to push data. 23 | 24 | | Type | Privileges | 25 | | --- | --- | 26 | | Cluster | `monitor` | 27 | | Index | `auto_configure` `create_doc` | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/device.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-device.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "device": { 10 | "properties": { 11 | "id": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "manufacturer": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "model": { 20 | "properties": { 21 | "identifier": { 22 | "ignore_above": 1024, 23 | "type": "keyword" 24 | }, 25 | "name": { 26 | "ignore_above": 1024, 27 | "type": "keyword" 28 | } 29 | } 30 | }, 31 | "serial_number": { 32 | "ignore_above": 1024, 33 | "type": "keyword" 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.userprefs 2 | *.local.xml 3 | *.sln.docstates 4 | *.obj 5 | *.swp 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.tss 12 | *.vspscc 13 | *_i.c 14 | *_p.c 15 | *.ncb 16 | *.suo 17 | *.tlb 18 | *.tlh 19 | *.bak 20 | *.cache 21 | *.ilk 22 | *.log 23 | *.nupkg 24 | *.ncrunchsolution 25 | [Bb]in 26 | [Dd]ebug/ 27 | test-results 28 | test-results/* 29 | *.lib 30 | *.sbr 31 | *.DotSettings.user 32 | obj/ 33 | [Rr]elease*/ 34 | _ReSharper*/ 35 | _NCrunch*/ 36 | [Tt]est[Rr]esult* 37 | 38 | .fake/* 39 | .fake 40 | packages/* 41 | paket.exe 42 | paket-files/*.cached 43 | 44 | build/* 45 | !build/tools 46 | !build/keys 47 | build/tools/* 48 | !build/tools/sn 49 | !build/tools/sn/* 50 | !build/tools/ilmerge 51 | !build/*.fsx 52 | !build/*.fsx 53 | !build/*.ps1 54 | !build/*.nuspec 55 | !build/*.png 56 | !build/*.targets 57 | !build/scripts 58 | 59 | !docs/build 60 | docs/node_modules 61 | doc/Help 62 | 63 | *.ncrunchproject 64 | Cache 65 | YamlCache 66 | tests.yaml 67 | 68 | *.DS_Store 69 | *.sln.ide 70 | 71 | launchSettings.json 72 | project.lock.json 73 | .vs 74 | .vs/* 75 | 76 | .idea/ 77 | *.sln.iml 78 | /src/.vs/restore.dg 79 | src/packages/ 80 | BenchmarkDotNet.Artifacts 81 | 82 | html_docs -------------------------------------------------------------------------------- /examples/Elastic.Serilog.Sinks.Example/Elastic.Serilog.Sinks.Example.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging.Console/Elastic.Extensions.Logging.Console.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;netstandard2.1;net8.0 5 | enable 6 | ECS Console Logger for Microsoft.Extensions.Logging 7 | ECS Console Logger for Microsoft.Extensions.Logging. Writes Elastic Common Schema (ECS), with semantic logging of structured data from message and scope values to console out, use filebeat/Elastic-Agent to send these to Elastic 8 | Logging;LoggerProvider;Elasticsearch;Console;ELK;Kibana;Logstash;Tracing;Diagnostics;Log;Trace;ECS 9 | enable 10 | True 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Schema/DTO/FieldMultiField.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using Newtonsoft.Json; 6 | 7 | namespace Elastic.CommonSchema.Generator.Schema.DTO 8 | { 9 | [JsonObject(MemberSerialization.OptIn)] 10 | public class FieldMultiField 11 | { 12 | /// 13 | /// Name of the field, defaults to multi_fields type (optional) 14 | /// 15 | [JsonProperty("name")] 16 | public string Name { get; set; } 17 | 18 | /// 19 | /// Type of the multi_fields (required) 20 | /// 21 | [JsonProperty("type", Required = Required.Always)] 22 | public string Type { get; set; } 23 | 24 | /// 25 | /// The name of this field, separated by dots. 26 | /// 27 | [JsonProperty("flat_name")] 28 | public string FlatName { get; set; } 29 | 30 | /// 31 | /// https://www.elastic.co/guide/en/elasticsearch/reference/current/norms.html 32 | /// 33 | [JsonProperty("norms")] 34 | public bool? Norms { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Serilog.Tests/Repro/GithubIssue225.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using FluentAssertions; 3 | using Serilog.Context; 4 | using Xunit; 5 | using Xunit.Abstractions; 6 | 7 | namespace Elastic.CommonSchema.Serilog.Tests.Repro 8 | { 9 | public class GithubIssue225 : LogTestsBase 10 | { 11 | public GithubIssue225(ITestOutputHelper output) : base(output) { } 12 | 13 | [Fact] 14 | public void Reproduce() => TestLogger((logger, getLogEvents) => 15 | { 16 | using (LogContext.PushProperty("ShipmentId", "my-shipment-id")) 17 | using (LogContext.PushProperty("ShipmentAmount", 2.3)) 18 | logger.Information("Logging something with log context"); 19 | 20 | var logEvents = getLogEvents(); 21 | logEvents.Should().HaveCount(1); 22 | 23 | var ecsEvents = ToEcsEvents(logEvents); 24 | 25 | var (_, info) = ecsEvents.First(); 26 | info.Message.Should().Be("Logging something with log context"); 27 | 28 | info.Labels.Should().NotBeNull().And.ContainKey("ShipmentId"); 29 | info.Labels["ShipmentId"].Should().Be("my-shipment-id"); 30 | 31 | info.Metadata.Should().NotBeNull().And.ContainKey("ShipmentAmount"); 32 | info.Metadata["ShipmentAmount"].Should().Be(2.3); 33 | 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/test-docs.yml: -------------------------------------------------------------------------------- 1 | # This workflow sets the 'test' status check to success in case it's a docs only PR and e2e.yml is not triggered 2 | # https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks 3 | name: test # The name must be the same as in test.yml 4 | 5 | on: 6 | pull_request: 7 | paths-ignore: # This expression needs to match the paths ignored on e2e.yml. 8 | - '**' 9 | - '!*.md' 10 | - '!*.asciidoc' 11 | - '!docs/**' 12 | 13 | permissions: 14 | contents: read 15 | 16 | ## Concurrency only allowed in the main branch. 17 | ## So old builds running for old commits within the same Pull Request are cancelled 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 21 | 22 | jobs: 23 | 24 | test-windows: 25 | runs-on: windows-latest 26 | 27 | steps: 28 | - run: 'echo "Not required for docs"' 29 | 30 | test-linux: 31 | runs-on: ubuntu-latest 32 | 33 | steps: 34 | - run: 'echo "Not required for docs"' -------------------------------------------------------------------------------- /src/Elastic.CommonSchema/Elastic.CommonSchema.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;netstandard2.1;net462;net8.0;net9.0 5 | Elastic Common Schema (ECS) Types 6 | Maps Elastic Common Schema (ECS) to .NET types including (de)serialization using System.Text.Json 7 | latest 8 | True 9 | enable 10 | 11 | 12 | true 13 | false 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/agent.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-agent.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "agent": { 10 | "properties": { 11 | "build": { 12 | "properties": { 13 | "original": { 14 | "ignore_above": 1024, 15 | "type": "keyword" 16 | } 17 | } 18 | }, 19 | "ephemeral_id": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | }, 23 | "id": { 24 | "ignore_above": 1024, 25 | "type": "keyword" 26 | }, 27 | "name": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | }, 31 | "type": { 32 | "ignore_above": 1024, 33 | "type": "keyword" 34 | }, 35 | "version": { 36 | "ignore_above": 1024, 37 | "type": "keyword" 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/agent.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-agent.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "agent": { 10 | "properties": { 11 | "build": { 12 | "properties": { 13 | "original": { 14 | "ignore_above": 1024, 15 | "type": "keyword" 16 | } 17 | } 18 | }, 19 | "ephemeral_id": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | }, 23 | "id": { 24 | "ignore_above": 1024, 25 | "type": "keyword" 26 | }, 27 | "name": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | }, 31 | "type": { 32 | "ignore_above": 1024, 33 | "type": "keyword" 34 | }, 35 | "version": { 36 | "ignore_above": 1024, 37 | "type": "keyword" 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/agent.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-agent.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "agent": { 10 | "properties": { 11 | "build": { 12 | "properties": { 13 | "original": { 14 | "ignore_above": 1024, 15 | "type": "keyword" 16 | } 17 | } 18 | }, 19 | "ephemeral_id": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | }, 23 | "id": { 24 | "ignore_above": 1024, 25 | "type": "keyword" 26 | }, 27 | "name": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | }, 31 | "type": { 32 | "ignore_above": 1024, 33 | "type": "keyword" 34 | }, 35 | "version": { 36 | "ignore_above": 1024, 37 | "type": "keyword" 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/agent.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-agent.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "agent": { 10 | "properties": { 11 | "build": { 12 | "properties": { 13 | "original": { 14 | "ignore_above": 1024, 15 | "type": "keyword" 16 | } 17 | } 18 | }, 19 | "ephemeral_id": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | }, 23 | "id": { 24 | "ignore_above": 1024, 25 | "type": "keyword" 26 | }, 27 | "name": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | }, 31 | "type": { 32 | "ignore_above": 1024, 33 | "type": "keyword" 34 | }, 35 | "version": { 36 | "ignore_above": 1024, 37 | "type": "keyword" 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/agent.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-agent.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "agent": { 10 | "properties": { 11 | "build": { 12 | "properties": { 13 | "original": { 14 | "ignore_above": 1024, 15 | "type": "keyword" 16 | } 17 | } 18 | }, 19 | "ephemeral_id": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | }, 23 | "id": { 24 | "ignore_above": 1024, 25 | "type": "keyword" 26 | }, 27 | "name": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | }, 31 | "type": { 32 | "ignore_above": 1024, 33 | "type": "keyword" 34 | }, 35 | "version": { 36 | "ignore_above": 1024, 37 | "type": "keyword" 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.Serilog/Adapters/IHttpAdapter.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | namespace Elastic.CommonSchema.Serilog.Adapters; 6 | 7 | /// 8 | /// Provides an abstraction that returns the current HTTP related information to be used to enrich 9 | /// 10 | public interface IHttpAdapter 11 | { 12 | /// The current information 13 | Client? Client { get; } 14 | /// The current information 15 | Http? Http { get; } 16 | /// The current information 17 | Server? Server { get; } 18 | /// The current information 19 | Url? Url { get; } 20 | /// The current information 21 | User? User { get; } 22 | /// The current information 23 | UserAgent? UserAgent { get; } 24 | 25 | /// Whether there is a context to infer information from 26 | bool HasContext { get; } 27 | } 28 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Schema/DTO/FieldType.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Runtime.Serialization; 6 | 7 | namespace Elastic.CommonSchema.Generator.Schema.DTO 8 | { 9 | /// 10 | /// The Elasticsearch field type. 11 | /// 12 | public enum FieldType 13 | { 14 | [EnumMember(Value = "keyword")] Keyword, 15 | [EnumMember(Value = "constant_keyword")] ConstantKeyword, 16 | [EnumMember(Value = "match_only_text")] MatchOnlyText, 17 | [EnumMember(Value = "flattened")] Flattened, 18 | [EnumMember(Value = "wildcard")] Wildcard, 19 | [EnumMember(Value = "long")] Long, 20 | [EnumMember(Value = "integer")] Integer, 21 | [EnumMember(Value = "scaled_float")] ScaledFloat, 22 | [EnumMember(Value = "date")] Date, 23 | [EnumMember(Value = "ip")] Ip, 24 | [EnumMember(Value = "object")] Object, 25 | [EnumMember(Value = "nested")] Nested, 26 | [EnumMember(Value = "text")] Text, 27 | [EnumMember(Value = "float")] Float, 28 | [EnumMember(Value = "geo_point")] GeoPoint, 29 | [EnumMember(Value = "boolean")] Boolean, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/ecs-aot-smoketest/SerilogExporter.cs: -------------------------------------------------------------------------------- 1 | using Elastic.Channels; 2 | using Elastic.Channels.Diagnostics; 3 | using Elastic.Ingest.Elasticsearch.DataStreams; 4 | using Elastic.Serilog.Sinks; 5 | using Elastic.Transport; 6 | using Serilog; 7 | using Serilog.Core; 8 | 9 | public class SerilogExporter(ITransport transport) 10 | { 11 | public Logger CreateSerilogLogger(out WaitHandle waitHandle, out IChannelDiagnosticsListener listener) 12 | { 13 | var countdown = new CountdownEvent(1); 14 | waitHandle = countdown.WaitHandle; 15 | 16 | IChannelDiagnosticsListener? listen = null; 17 | var options = new ElasticsearchSinkOptions(transport) 18 | { 19 | DataStream = new DataStreamName("logs", "serilog", "tests"), 20 | ConfigureChannel = c => 21 | { 22 | c.BufferOptions = new BufferOptions 23 | { 24 | WaitHandle = countdown, 25 | OutboundBufferMaxSize = 1 26 | }; 27 | }, 28 | ChannelDiagnosticsCallback = l => listen = l 29 | }; 30 | listener = listen ?? throw new Exception("No listener"); 31 | 32 | var loggerConfig = new LoggerConfiguration() 33 | .MinimumLevel.Information() 34 | .WriteTo.Elasticsearch(options); 35 | 36 | var logger = loggerConfig.CreateLogger(); 37 | return logger; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.BenchmarkDotNetExporter/Domain/BenchmarkAgent.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Linq; 6 | using System.Reflection; 7 | 8 | namespace Elastic.CommonSchema.BenchmarkDotNetExporter.Domain 9 | { 10 | /// 11 | public class BenchmarkAgent : Agent 12 | { 13 | private static readonly AssemblyName Reference = typeof(BenchmarkAgent).Assembly.GetName(); 14 | 15 | private static readonly AssemblyInformationalVersionAttribute Attribute = 16 | typeof(BenchmarkAgent) 17 | .Assembly 18 | .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false) 19 | .FirstOrDefault() as AssemblyInformationalVersionAttribute; 20 | 21 | /// 22 | public BenchmarkAgent() 23 | { 24 | Type = Reference.Name; 25 | Version = Attribute?.InformationalVersion ?? Reference.Version.ToString(); 26 | } 27 | 28 | // TODO should this be on Agent? 29 | /// 30 | public BenchmarkGit Git { get; set; } 31 | /// 32 | public BenchmarkLanguage Language { get; set; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.NLog.Tests/EcsFieldsInTemplateTests.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Linq; 6 | using FluentAssertions; 7 | using Xunit; 8 | using Xunit.Abstractions; 9 | 10 | namespace Elastic.CommonSchema.NLog.Tests 11 | { 12 | public class EcsFieldsInTemplateTests : LogTestsBase 13 | { 14 | public EcsFieldsInTemplateTests(ITestOutputHelper output) : base(output) { } 15 | 16 | [Fact] 17 | public void CanUseEcsFieldNamesAsTemplateProperty() => TestLogger((logger, getLogEvents) => 18 | { 19 | logger.Info($"Info {{TraceId}}: {{{LogTemplateProperties.FaasColdstart}}}", "my-trace-id", true); 20 | 21 | var logEvents = getLogEvents(); 22 | logEvents.Should().HaveCount(1); 23 | 24 | var ecsEvents = ToEcsEvents(logEvents); 25 | 26 | var (_, info) = ecsEvents.First(); 27 | info.Message.Should().Be("Info my-trace-id: true"); 28 | info.Labels.Should().BeNull(); 29 | info.Metadata.Should().BeNull(); 30 | 31 | info.TraceId.Should().Be("my-trace-id"); 32 | info.Faas.Should().NotBeNull(); 33 | info.Faas.Coldstart.Should().BeTrue(); 34 | }); 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/aspnetcore-with-serilog/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace AspnetCoreExample.Controllers 8 | { 9 | [ApiController] 10 | [Route("[controller]")] 11 | public class WeatherForecastController : ControllerBase 12 | { 13 | private static readonly string[] Summaries = { 14 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 15 | }; 16 | 17 | // ReSharper disable once NotAccessedField.Local 18 | private readonly ILogger _logger; 19 | 20 | public WeatherForecastController(ILogger logger) => _logger = logger; 21 | 22 | [HttpGet] 23 | public IEnumerable Get() 24 | { 25 | var rng = new Random(); 26 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 27 | { 28 | Date = DateTime.Now.AddDays(index), 29 | TemperatureC = rng.Next(-20, 55), 30 | Summary = Summaries[rng.Next(Summaries.Length)] 31 | }) 32 | .ToArray(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging.Console/LoggingBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace Elastic.Extensions.Logging.Console; 5 | 6 | /// Extensions to to ease setting up ECS formatted logs to console. 7 | public static class LoggingBuilderExtensions 8 | { 9 | /// Adds ECS output to console output 10 | [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Action is not bound")] 11 | [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "Action is not bound")] 12 | [UnconditionalSuppressMessage("AotAnalysis", "IL2092:DynamicallyAccessedMemberTypes", Justification = "More concrete then override")] 13 | public static ILoggingBuilder AddEcsConsole( 14 | this ILoggingBuilder builder, 15 | LogLevel stdErrorThreshold = LogLevel.Warning, 16 | Action? configure = null 17 | ) 18 | { 19 | builder.AddConsole(c=> 20 | { 21 | c.FormatterName = "ecs"; 22 | c.LogToStandardErrorThreshold = stdErrorThreshold; 23 | }); 24 | builder.AddConsoleFormatter(configure ?? (_ => { })); 25 | return builder; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema/Serialization/SnakeCaseJsonNamingPolicy.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Text; 6 | using System.Text.Json; 7 | 8 | namespace Elastic.CommonSchema.Serialization 9 | { 10 | internal class SnakeCaseJsonNamingPolicy : JsonNamingPolicy 11 | { 12 | public static string ToSnakeCase(string s) 13 | { 14 | if (string.IsNullOrEmpty(s)) return s; 15 | 16 | var sb = new StringBuilder(); 17 | for (var i = 0; i < s.Length; i++) 18 | { 19 | var c = s[i]; 20 | if (!char.IsUpper(c)) 21 | { 22 | sb.Append(c); 23 | continue; 24 | } 25 | // first 26 | if (i == 0) 27 | sb.Append(char.ToLowerInvariant(c)); 28 | else if (char.IsUpper(s[i - 1])) // WriteIO => write_io 29 | sb.Append(char.ToLowerInvariant(c)); 30 | else if (s[i - 1] == '_') // User_Id => user_id 31 | sb.Append(char.ToLowerInvariant(c)); 32 | else 33 | { 34 | sb.Append("_"); 35 | sb.Append(char.ToLowerInvariant(c)); 36 | } 37 | } 38 | return sb.ToString(); 39 | } 40 | 41 | public override string ConvertName(string name) => ToSnakeCase(name); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging.Console/EcsConsoleFormatterOptions.cs: -------------------------------------------------------------------------------- 1 | using Elastic.CommonSchema; 2 | using Elastic.Extensions.Logging.Common; 3 | using Microsoft.Extensions.Logging; 4 | using Microsoft.Extensions.Logging.Console; 5 | 6 | namespace Elastic.Extensions.Logging.Console; 7 | 8 | /// 9 | public class EcsConsoleFormatterOptions : ConsoleFormatterOptions, ILogEventCreationOptions 10 | { 11 | /// 12 | public bool IncludeHost { get; set; } = true; 13 | 14 | /// 15 | public bool IncludeProcess { get; set; } = true; 16 | 17 | /// 18 | public bool IncludeUser { get; set; } = true; 19 | 20 | /// 21 | public bool IncludeActivityData { get; set; } = true; 22 | 23 | /// 24 | public string[]? Tags { get; set; } 25 | 26 | /// 27 | public string ListSeparator { get; set; } = ", "; 28 | 29 | /// 30 | public Action? MapCustom { get; set; } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Serilog.Tests/Repro/GithubIssue31.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Text; 4 | using FluentAssertions; 5 | using Xunit; 6 | using Xunit.Abstractions; 7 | 8 | namespace Elastic.CommonSchema.Serilog.Tests.Repro 9 | { 10 | public class GithubIssue31 : LogTestsBase 11 | { 12 | public GithubIssue31(ITestOutputHelper output) : base(output) { } 13 | 14 | [Fact] 15 | public void Reproduce() => TestLogger((logger, getLogEvents) => 16 | { 17 | logger.Information("Язык {@Data}", new { Значение = "Русский" }); 18 | 19 | var logEvents = getLogEvents(); 20 | logEvents.Should().HaveCount(1); 21 | 22 | var ecsEvents = ToEcsEvents(logEvents); 23 | 24 | var (_, info) = ecsEvents.First(); 25 | info.Message.Should().Be("Язык { Значение: \"Русский\" }"); 26 | 27 | var infoString = info.Serialize(); 28 | infoString.Should().Contain("Язык"); 29 | infoString.Should().Contain("Значение"); 30 | infoString.Should().Contain("Русский"); 31 | 32 | var stream = new MemoryStream(); 33 | info.Serialize(stream); 34 | 35 | var streamString = Encoding.UTF8.GetString(stream.GetBuffer()); 36 | streamString.Should().Contain("Язык"); 37 | streamString.Should().Contain("Значение"); 38 | streamString.Should().Contain("Русский"); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.Serilog/ScalarPropertyExtensions.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Diagnostics.CodeAnalysis; 6 | using Serilog.Events; 7 | 8 | namespace Elastic.CommonSchema.Serilog 9 | { 10 | internal static class ScalarPropertyExtensions 11 | { 12 | public static bool TryGetScalarPropertyValue(this LogEvent e, string key, [NotNullWhen(true)]out ScalarValue? value) 13 | { 14 | if (!e.Properties.TryGetValue(key, out var scalarValue)) 15 | { 16 | value = null; 17 | return false; 18 | } 19 | 20 | if (scalarValue is not ScalarValue propertyValue) 21 | { 22 | value = null; 23 | return false; 24 | } 25 | 26 | value = propertyValue; 27 | return true; 28 | } 29 | 30 | public static bool TryGetScalarString(this LogEvent e, string key, [NotNullWhen(true)]out string? value) 31 | { 32 | value = null; 33 | if (!e.TryGetScalarPropertyValue(key, out var scalar) || scalar.Value == null) 34 | return false; 35 | 36 | value = scalar.Value.ToString(); 37 | if (!string.IsNullOrWhiteSpace(value)) return true; 38 | 39 | value = null; 40 | return false; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/console-with-extensions-logging/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Docker Compose file for E-K stack 2 | # Run with: 3 | # docker-compose up -d 4 | 5 | version: '3.7' 6 | 7 | services: 8 | 9 | elasticsearch: 10 | image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.6.1 11 | container_name: elasticsearch 12 | ports: 13 | - "9200:9200" 14 | environment: 15 | - node.name=elasticsearch 16 | - cluster.initial_master_nodes=elasticsearch 17 | - bootstrap.memory_lock=true 18 | - "ES_JAVA_OPTS=-Xms512m -Xmx512m" 19 | ulimits: 20 | memlock: 21 | soft: -1 22 | hard: -1 23 | nofile: 24 | soft: "65536" 25 | hard: "65536" 26 | volumes: 27 | - elasticsearch-data:/usr/share/elasticsearch/data 28 | networks: 29 | - elastic-network 30 | 31 | kibana: 32 | image: docker.elastic.co/kibana/kibana-oss:7.6.1 33 | container_name: kibana 34 | ports: 35 | - "5601:5601" 36 | environment: 37 | ELASTICSEARCH_URL: http://elasticsearch:9200 38 | ELASTICSEARCH_HOSTS: http://elasticsearch:9200 39 | depends_on: 40 | - elasticsearch 41 | networks: 42 | - elastic-network 43 | 44 | networks: 45 | elastic-network: 46 | driver: bridge 47 | 48 | volumes: 49 | elasticsearch-data: 50 | driver: local 51 | -------------------------------------------------------------------------------- /examples/aspnetcore-with-serilog/Startup.cs: -------------------------------------------------------------------------------- 1 | using Elastic.Apm.AspNetCore; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Hosting; 7 | 8 | namespace AspnetCoreExample 9 | { 10 | public class Startup 11 | { 12 | public Startup(IConfiguration configuration) => Configuration = configuration; 13 | 14 | public IConfiguration Configuration { get; } 15 | 16 | // This method gets called by the runtime. Use this method to add services to the container. 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | // Ensure that we make the HttpContextAccessor resolvable through the configuration 20 | services.AddHttpContextAccessor(); 21 | 22 | services.AddControllers(); 23 | } 24 | 25 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 26 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 27 | { 28 | if (env.IsDevelopment()) 29 | app.UseDeveloperExceptionPage(); 30 | 31 | app.UseRouting(); 32 | app.UseElasticApm(); 33 | 34 | app.UseAuthorization(); 35 | 36 | app.UseEndpoints(endpoints => 37 | { 38 | endpoints.MapControllers(); 39 | }); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/faas.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-faas.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "faas": { 10 | "properties": { 11 | "coldstart": { 12 | "type": "boolean" 13 | }, 14 | "execution": { 15 | "ignore_above": 1024, 16 | "type": "keyword" 17 | }, 18 | "id": { 19 | "ignore_above": 1024, 20 | "type": "keyword" 21 | }, 22 | "name": { 23 | "ignore_above": 1024, 24 | "type": "keyword" 25 | }, 26 | "trigger": { 27 | "properties": { 28 | "request_id": { 29 | "ignore_above": 1024, 30 | "type": "keyword" 31 | }, 32 | "type": { 33 | "ignore_above": 1024, 34 | "type": "keyword" 35 | } 36 | } 37 | }, 38 | "version": { 39 | "ignore_above": 1024, 40 | "type": "keyword" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/faas.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-faas.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "faas": { 10 | "properties": { 11 | "coldstart": { 12 | "type": "boolean" 13 | }, 14 | "execution": { 15 | "ignore_above": 1024, 16 | "type": "keyword" 17 | }, 18 | "id": { 19 | "ignore_above": 1024, 20 | "type": "keyword" 21 | }, 22 | "name": { 23 | "ignore_above": 1024, 24 | "type": "keyword" 25 | }, 26 | "trigger": { 27 | "properties": { 28 | "request_id": { 29 | "ignore_above": 1024, 30 | "type": "keyword" 31 | }, 32 | "type": { 33 | "ignore_above": 1024, 34 | "type": "keyword" 35 | } 36 | } 37 | }, 38 | "version": { 39 | "ignore_above": 1024, 40 | "type": "keyword" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/registry.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-registry.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "registry": { 10 | "properties": { 11 | "data": { 12 | "properties": { 13 | "bytes": { 14 | "ignore_above": 1024, 15 | "type": "keyword" 16 | }, 17 | "strings": { 18 | "type": "wildcard" 19 | }, 20 | "type": { 21 | "ignore_above": 1024, 22 | "type": "keyword" 23 | } 24 | } 25 | }, 26 | "hive": { 27 | "ignore_above": 1024, 28 | "type": "keyword" 29 | }, 30 | "key": { 31 | "ignore_above": 1024, 32 | "type": "keyword" 33 | }, 34 | "path": { 35 | "ignore_above": 1024, 36 | "type": "keyword" 37 | }, 38 | "value": { 39 | "ignore_above": 1024, 40 | "type": "keyword" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/registry.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-registry.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "registry": { 10 | "properties": { 11 | "data": { 12 | "properties": { 13 | "bytes": { 14 | "ignore_above": 1024, 15 | "type": "keyword" 16 | }, 17 | "strings": { 18 | "type": "wildcard" 19 | }, 20 | "type": { 21 | "ignore_above": 1024, 22 | "type": "keyword" 23 | } 24 | } 25 | }, 26 | "hive": { 27 | "ignore_above": 1024, 28 | "type": "keyword" 29 | }, 30 | "key": { 31 | "ignore_above": 1024, 32 | "type": "keyword" 33 | }, 34 | "path": { 35 | "ignore_above": 1024, 36 | "type": "keyword" 37 | }, 38 | "value": { 39 | "ignore_above": 1024, 40 | "type": "keyword" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/registry.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-registry.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "registry": { 10 | "properties": { 11 | "data": { 12 | "properties": { 13 | "bytes": { 14 | "ignore_above": 1024, 15 | "type": "keyword" 16 | }, 17 | "strings": { 18 | "type": "wildcard" 19 | }, 20 | "type": { 21 | "ignore_above": 1024, 22 | "type": "keyword" 23 | } 24 | } 25 | }, 26 | "hive": { 27 | "ignore_above": 1024, 28 | "type": "keyword" 29 | }, 30 | "key": { 31 | "ignore_above": 1024, 32 | "type": "keyword" 33 | }, 34 | "path": { 35 | "ignore_above": 1024, 36 | "type": "keyword" 37 | }, 38 | "value": { 39 | "ignore_above": 1024, 40 | "type": "keyword" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Specification/v9.0.0/composable/component/registry.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-registry.html", 4 | "ecs_version": "9.0.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "registry": { 10 | "properties": { 11 | "data": { 12 | "properties": { 13 | "bytes": { 14 | "ignore_above": 1024, 15 | "type": "keyword" 16 | }, 17 | "strings": { 18 | "type": "wildcard" 19 | }, 20 | "type": { 21 | "ignore_above": 1024, 22 | "type": "keyword" 23 | } 24 | } 25 | }, 26 | "hive": { 27 | "ignore_above": 1024, 28 | "type": "keyword" 29 | }, 30 | "key": { 31 | "ignore_above": 1024, 32 | "type": "keyword" 33 | }, 34 | "path": { 35 | "ignore_above": 1024, 36 | "type": "keyword" 37 | }, 38 | "value": { 39 | "ignore_above": 1024, 40 | "type": "keyword" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.NLog.Tests/OutputTests.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System; 6 | using System.Linq; 7 | using FluentAssertions; 8 | using Xunit; 9 | using Xunit.Abstractions; 10 | 11 | namespace Elastic.CommonSchema.NLog.Tests 12 | { 13 | public class OutputTests : LogTestsBase 14 | { 15 | public OutputTests(ITestOutputHelper output) : base(output) { } 16 | 17 | [Fact] 18 | public void LogMultiple() => TestLogger((logger, getLogEvents) => 19 | { 20 | logger.Info("My log message!"); 21 | logger.Info("Test output to NLog!"); 22 | void sketchy() => throw new Exception("I threw up."); 23 | var exception = Record.Exception(sketchy); 24 | logger.Error(exception, "Here is an error."); 25 | Assert.NotNull(exception); 26 | 27 | var logEvents = getLogEvents(); 28 | logEvents.Should().HaveCount(3); 29 | 30 | var ecsEvents = ToEcsEvents(logEvents); 31 | var (_, error) = ecsEvents.Last(); 32 | error.Log.Level.Should().Be("Error"); 33 | error.Error.Should().NotBeNull(); 34 | 35 | var (_, info) = ecsEvents.First(); 36 | info.Log.Level.Should().Be("Info"); 37 | info.Error.Should().BeNull(); 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Serilog.Tests/Repro/GithubIssue30.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using FluentAssertions; 3 | using Serilog; 4 | using Xunit; 5 | using Xunit.Abstractions; 6 | 7 | namespace Elastic.CommonSchema.Serilog.Tests.Repro 8 | { 9 | public class GithubIssue30 : LogTestsBase 10 | { 11 | public GithubIssue30(ITestOutputHelper output) : base(output) => 12 | LoggerConfiguration = LoggerConfiguration 13 | .Enrich.WithThreadId() 14 | .Enrich.WithThreadName() 15 | .Enrich.WithMachineName() 16 | .Enrich.WithProcessId() 17 | .Enrich.WithProcessName() 18 | .Enrich.WithEnvironmentUserName(); 19 | 20 | [Fact] 21 | public void DoesNotCaptureSurroundingDoubleQuotes() => TestLogger((logger, getLogEvents) => 22 | { 23 | logger.Information("My log message!"); 24 | 25 | var logEvents = getLogEvents(); 26 | logEvents.Should().HaveCount(1); 27 | 28 | var ecsEvents = ToEcsEvents(logEvents); 29 | 30 | var (_, info) = ecsEvents.First(); 31 | info.Log.Level.Should().Be("Information"); 32 | info.Error.Should().BeNull(); 33 | 34 | info.Host.Name.Should().NotBeEmpty().And.NotContain("\""); 35 | info.Process.Name.Should().NotBeEmpty().And.NotContain("\""); 36 | info.Process.Pid.Should().BeGreaterThan(0); 37 | info.Process.ThreadId.Should().NotBeNull().And.NotBe(info.Process.Pid); 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/registry.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-registry.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "registry": { 10 | "properties": { 11 | "data": { 12 | "properties": { 13 | "bytes": { 14 | "ignore_above": 1024, 15 | "type": "keyword" 16 | }, 17 | "strings": { 18 | "type": "wildcard" 19 | }, 20 | "type": { 21 | "ignore_above": 1024, 22 | "type": "keyword" 23 | } 24 | } 25 | }, 26 | "hive": { 27 | "ignore_above": 1024, 28 | "type": "keyword" 29 | }, 30 | "key": { 31 | "ignore_above": 1024, 32 | "type": "keyword" 33 | }, 34 | "path": { 35 | "ignore_above": 1024, 36 | "type": "keyword" 37 | }, 38 | "value": { 39 | "ignore_above": 1024, 40 | "type": "keyword" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Elastic and contributors 5 | Elasticsearch BV 6 | Apache-2.0 7 | https://github.com/elastic/ecs-dotnet 8 | https://github.com/elastic/ecs-dotnet 9 | https://github.com/elastic/ecs-dotnet/releases 10 | False 11 | 12 | 13 | 14 | canary 15 | 0.1 16 | 17 | latest 18 | true 19 | $(DefineConstants);FULLFRAMEWORK 20 | 21 | 22 | 23 | 25 | 26 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.BenchmarkDotNetExporter/Domain/BenchmarkJobConfig.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Runtime.Serialization; 6 | using System.Text.Json.Serialization; 7 | 8 | namespace Elastic.CommonSchema.BenchmarkDotNetExporter.Domain 9 | { 10 | /// 11 | public class BenchmarkJobConfig 12 | { 13 | /// 14 | [JsonPropertyName("platform"), DataMember(Name = "platform")] 15 | public string Platform { get; set; } 16 | 17 | /// 18 | [JsonPropertyName("runtime"), DataMember(Name = "runtime")] 19 | public string RunTime { get; set; } 20 | 21 | /// 22 | [JsonPropertyName("jit"), DataMember(Name = "jit")] 23 | public string Jit { get; set; } 24 | 25 | /// 26 | [JsonPropertyName("gc"), DataMember(Name = "gc")] 27 | public BenchmarkGcInfo Gc { get; set; } 28 | 29 | /// 30 | [JsonPropertyName("id"), DataMember(Name = "id")] 31 | public string Id { get; set; } 32 | 33 | /// 34 | [JsonPropertyName("launch"), DataMember(Name = "launch")] 35 | public BenchmarkLaunchInformation Launch { get; set; } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Elastic.Apm.SerilogEnricher/ElasticApmEnricherExtension.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System; 6 | using Serilog; 7 | using Serilog.Configuration; 8 | 9 | namespace Elastic.Apm.SerilogEnricher 10 | { 11 | /// Provides configuration methods to 12 | public static class ElasticApmEnricherExtension 13 | { 14 | /// 15 | /// Enrich log events with a trace and transaction id properties containing the 16 | /// current ids that the Elastic APM .NET Agent generated. 17 | /// 18 | /// Logger enrichment configuration. 19 | /// Configuration object allowing method chaining. 20 | /// If is null. 21 | public static LoggerConfiguration WithElasticApmCorrelationInfo(this LoggerEnrichmentConfiguration enrichmentConfiguration) 22 | { 23 | if (enrichmentConfiguration == null) 24 | throw new ArgumentNullException(nameof(enrichmentConfiguration)); 25 | 26 | return enrichmentConfiguration.With(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/faas.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-faas.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "faas": { 10 | "properties": { 11 | "coldstart": { 12 | "type": "boolean" 13 | }, 14 | "execution": { 15 | "ignore_above": 1024, 16 | "type": "keyword" 17 | }, 18 | "id": { 19 | "ignore_above": 1024, 20 | "type": "keyword" 21 | }, 22 | "name": { 23 | "ignore_above": 1024, 24 | "type": "keyword" 25 | }, 26 | "trigger": { 27 | "properties": { 28 | "request_id": { 29 | "ignore_above": 1024, 30 | "type": "keyword" 31 | }, 32 | "type": { 33 | "ignore_above": 1024, 34 | "type": "keyword" 35 | } 36 | }, 37 | "type": "nested" 38 | }, 39 | "version": { 40 | "ignore_above": 1024, 41 | "type": "keyword" 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Specification/v8.4.0/composable/component/faas.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-faas.html", 4 | "ecs_version": "8.4.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "faas": { 10 | "properties": { 11 | "coldstart": { 12 | "type": "boolean" 13 | }, 14 | "execution": { 15 | "ignore_above": 1024, 16 | "type": "keyword" 17 | }, 18 | "id": { 19 | "ignore_above": 1024, 20 | "type": "keyword" 21 | }, 22 | "name": { 23 | "ignore_above": 1024, 24 | "type": "keyword" 25 | }, 26 | "trigger": { 27 | "properties": { 28 | "request_id": { 29 | "ignore_above": 1024, 30 | "type": "keyword" 31 | }, 32 | "type": { 33 | "ignore_above": 1024, 34 | "type": "keyword" 35 | } 36 | }, 37 | "type": "nested" 38 | }, 39 | "version": { 40 | "ignore_above": 1024, 41 | "type": "keyword" 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Specification/v8.6.0/composable/component/faas.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-faas.html", 4 | "ecs_version": "8.6.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "faas": { 10 | "properties": { 11 | "coldstart": { 12 | "type": "boolean" 13 | }, 14 | "execution": { 15 | "ignore_above": 1024, 16 | "type": "keyword" 17 | }, 18 | "id": { 19 | "ignore_above": 1024, 20 | "type": "keyword" 21 | }, 22 | "name": { 23 | "ignore_above": 1024, 24 | "type": "keyword" 25 | }, 26 | "trigger": { 27 | "properties": { 28 | "request_id": { 29 | "ignore_above": 1024, 30 | "type": "keyword" 31 | }, 32 | "type": { 33 | "ignore_above": 1024, 34 | "type": "keyword" 35 | } 36 | }, 37 | "type": "nested" 38 | }, 39 | "version": { 40 | "ignore_above": 1024, 41 | "type": "keyword" 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Serilog.Tests/OutputTests.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System; 6 | using System.Linq; 7 | using FluentAssertions; 8 | using Xunit; 9 | using Xunit.Abstractions; 10 | 11 | namespace Elastic.CommonSchema.Serilog.Tests 12 | { 13 | public class OutputTests : LogTestsBase 14 | { 15 | public OutputTests(ITestOutputHelper output) : base(output) { } 16 | 17 | [Fact] 18 | public void LogMultiple() => TestLogger((logger, getLogEvents) => 19 | { 20 | logger.Information("My log message!"); 21 | logger.Information("Test output to Serilog!"); 22 | Action sketchy = () => throw new Exception("I threw up."); 23 | var exception = Record.Exception(sketchy); 24 | logger.Error(exception, "Here is an error."); 25 | Assert.NotNull(exception); 26 | 27 | var logEvents = getLogEvents(); 28 | logEvents.Should().HaveCount(3); 29 | 30 | var ecsEvents = ToEcsEvents(logEvents); 31 | var (_, error) = ecsEvents.Last(); 32 | error.Log.Level.Should().Be("Error"); 33 | error.Error.Should().NotBeNull(); 34 | 35 | var (_, info) = ecsEvents.First(); 36 | info.Log.Level.Should().Be("Information"); 37 | info.Error.Should().BeNull(); 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Elastic.Serilog.Enrichers.Web/Elastic.Serilog.Enrichers.Web.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0;net462 5 | enable 6 | enable 7 | Elastic Common Schema (ECS) Serilog Enricher for Web proeprties 8 | Serilog enricher for ASP.NET (Core) to inject more data in emitted Elastic Common Schema (ECS) documents. 9 | True 10 | enable 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging.Common/LogEventToEcsHelper.cs: -------------------------------------------------------------------------------- 1 | using Elastic.CommonSchema; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace Elastic.Extensions.Logging.Common 5 | { 6 | /// Extensions for so they can be projected into ECS format in different formats 7 | public static class LogLevelExtensions 8 | { 9 | /// projects to 10 | public static int ToEcsSeverity(this LogLevel logLevel) => 11 | logLevel switch 12 | { 13 | LogLevel.Critical => 2, 14 | LogLevel.Error => 3, 15 | LogLevel.Warning => 4, 16 | LogLevel.Information => 6, 17 | LogLevel.Trace => 7, 18 | LogLevel.Debug => 7, 19 | LogLevel.None => 8, 20 | _ => 7 21 | }; 22 | 23 | /// projects to 24 | public static string ToEcsLogLevelString(this LogLevel logLevel) => 25 | logLevel switch 26 | { 27 | LogLevel.Critical => nameof(LogLevel.Critical), 28 | LogLevel.Error => nameof(LogLevel.Error), 29 | LogLevel.Warning => nameof(LogLevel.Warning), 30 | LogLevel.Information => nameof(LogLevel.Information), 31 | LogLevel.Trace => nameof(LogLevel.Trace), 32 | LogLevel.Debug => nameof(LogLevel.Debug), 33 | LogLevel.None => nameof(LogLevel.None), 34 | _ => "Unknown" 35 | }; 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/aspnetcore-with-extensions-logging/Program.cs: -------------------------------------------------------------------------------- 1 | // -- Start an Elasticsearch Instance -- 2 | 3 | using Elastic.Clients.Elasticsearch; 4 | using Elastic.Elasticsearch.Ephemeral; 5 | using Elastic.Extensions.Logging; 6 | 7 | using var cluster = new EphemeralCluster("9.0.0"); 8 | var client = CreateClient(cluster); 9 | //check if an instance is already running before starting 10 | if (!(await client.InfoAsync()).IsValidResponse) 11 | cluster.Start(TimeSpan.FromMinutes(1)); 12 | else Console.WriteLine("Using already running Elasticsearch instance"); 13 | var builder = WebApplication.CreateBuilder(args); 14 | 15 | // Add services to the container. 16 | 17 | builder.Services.AddControllers(); 18 | builder.Services.AddEndpointsApiExplorer(); 19 | 20 | builder.Logging.AddElasticsearch(client.Transport, log => 21 | { 22 | log.Tags = new[] { "debug" }; 23 | }, channel => 24 | { 25 | channel.ExportResponseCallback = (response, buffer) => Console.WriteLine($"Written {buffer.Count} logs to Elasticsearch: {response.ApiCallDetails.HttpStatusCode}"); 26 | }); 27 | var app = builder.Build(); 28 | 29 | app.UseAuthorization(); 30 | app.MapControllers(); 31 | app.Run(); 32 | 33 | 34 | static ElasticsearchClient CreateClient(EphemeralCluster cluster) 35 | { 36 | var settings = new ElasticsearchClientSettings(cluster.NodesUris().First()) 37 | .EnableDebugMode(); 38 | return new ElasticsearchClient(settings); 39 | } 40 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Views/Entities.ShouldSerialize.Generated.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Collections.Generic 2 | @using System.Globalization 3 | @using System.Linq 4 | @inherits Elastic.CommonSchema.Generator.Views.CodeTemplatePage 5 | // Licensed to Elasticsearch B.V under one or more agreements. 6 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 7 | // See the LICENSE file in the project root for more information 8 | 9 | /* 10 | IMPORTANT NOTE 11 | ============== 12 | This file has been generated. 13 | If you wish to submit a PR please modify the original csharp file and submit the PR with that change. Thanks! 14 | */ 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | using System.Text.Json; 19 | using System.Text.Json.Serialization; 20 | 21 | namespace Elastic.CommonSchema; 22 | 23 | @foreach (var kv in Model.EntitiesWithPropertiesAtRoot) 24 | { 25 | var entity = kv.Key; 26 | var fields = entity.BaseFieldSet.ValueProperties.Where(field => !kv.Value.Contains(field.JsonProperty)).ToList(); 27 | var emptyCheck = string.Join(" || ", fields.Select(f => $"{f.Name} != null").ToList()); 28 | if (string.IsNullOrEmpty(emptyCheck)) 29 | { 30 | emptyCheck = "false"; 31 | } 32 | 33 | public partial class @entity.Name 34 | { 35 | [JsonIgnore] 36 | internal bool ShouldSerialize => 37 | @Raw(emptyCheck); 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/Elastic.Extensions.Logging/Elastic.Extensions.Logging.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;netstandard2.1 5 | Elasticsearch Logger Provider 6 | Elasticsearch logger provider for Microsoft.Extensions.Logging. Writes direct to Elasticsearch using the Elastic Common Schema (ECS), with semantic logging of structured data from message and scope values, for use with the Elasticsearch-Logstash-Kibana (ELK) stack. The results can be viewed and queried in the Kibana console. 7 | Logging;LoggerProvider;Elasticsearch;ELK;Kibana;Logstash;Tracing;Diagnostics;Log;Trace;ECS 8 | enable 9 | True 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.github/workflows/update-specs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Send PRs to the subscribed ECS Agents if the spec files (JSON) are modified 3 | name: update-specs 4 | 5 | on: 6 | workflow_dispatch: 7 | schedule: 8 | - cron: '0 6 * * *' 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | bump: 15 | runs-on: ubuntu-latest 16 | steps: 17 | 18 | - uses: actions/checkout@v6 19 | 20 | - name: Get token 21 | id: get_token 22 | uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2.1.0 23 | with: 24 | app_id: ${{ secrets.OBS_AUTOMATION_APP_ID }} 25 | private_key: ${{ secrets.OBS_AUTOMATION_APP_PEM }} 26 | permissions: >- 27 | { 28 | "contents": "write", 29 | "pull_requests": "write" 30 | } 31 | 32 | - uses: elastic/oblt-actions/updatecli/run@v1 33 | with: 34 | command: "--experimental apply --config .github/update-specs.yml" 35 | env: 36 | GITHUB_TOKEN: ${{ steps.get_token.outputs.token }} 37 | 38 | - if: failure() 39 | uses: elastic/oblt-actions/slack/send@v1 40 | with: 41 | bot-token: ${{ secrets.SLACK_BOT_TOKEN }} 42 | channel-id: "#apm-agent-dotnet" 43 | message: ":traffic_cone: updatecli failed for `${{ github.repository }}@${{ github.ref_name }}`, @robots-ci please look what's going on " 44 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Projection/IndexTemplate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace Elastic.CommonSchema.Generator.Projection 5 | { 6 | public class IndexTemplate 7 | { 8 | public string Name { get; } 9 | public string Template { get; } 10 | public int Priority { get; } 11 | 12 | public IndexTemplate(string name, string template, string schemaVersion) 13 | { 14 | var v = schemaVersion.Split('.') 15 | .Select(s => uint.Parse(s)) 16 | .ToArray(); 17 | 18 | uint versionInteger = 0; 19 | versionInteger |= v[0] << 16; 20 | versionInteger |= v[1] << 8; 21 | versionInteger |= v[2]; 22 | 23 | Priority = (int)versionInteger; 24 | 25 | Name = name.PascalCase(); 26 | Template = 27 | //Regex.Replace(template, @"\r\n?|\n", "") 28 | template 29 | // ensure our template beats out builtin templates or elastic agent integrations 30 | // force datastreams for new index templates 31 | 32 | .Replace("\"priority\": 1,", $"\"priority\": {Priority},\r\n \"data_stream\": {{}},") 33 | .Replace("Sample composable template that includes all ECS fields", 34 | $"Template installed by ECS.NET {schemaVersion} (https://github.com/elastic/ecs-dotnet)") 35 | .Replace("\"limit\": 2000", "\"limit\": 2500") 36 | .Replace("\"", "\"\"") 37 | .Replace("_vulnerability\"\"", "_vulnerability\"\"\" + userComponents + @\"") 38 | .Replace("try-ecs-*", "\" + indexPattern + @\""); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.github/update-specs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: update specs 3 | 4 | scms: 5 | githubConfig: 6 | kind: github 7 | spec: 8 | user: '{{ requiredEnv "GITHUB_ACTOR" }}' 9 | owner: elastic 10 | repository: ecs-dotnet 11 | token: '{{ requiredEnv "GITHUB_TOKEN" }}' 12 | username: '{{ requiredEnv "GITHUB_ACTOR" }}' 13 | branch: main 14 | commitusingapi: true 15 | 16 | actions: 17 | ecs-dotnet: 18 | kind: github/pullrequest 19 | scmid: githubConfig 20 | sourceid: sha 21 | spec: 22 | automerge: false 23 | labels: 24 | - dependencies 25 | title: 'synchronize ecs-logging spec' 26 | description: |- 27 | ### What 28 | 29 | ECS logging specs automatic sync 30 | 31 | ### Why 32 | 33 | *Changeset* 34 | * https://github.com/elastic/ecs-logging/commit/{{ source "sha" }} 35 | 36 | sources: 37 | spec.json: 38 | name: Get specs from json 39 | kind: file 40 | spec: 41 | file: https://raw.githubusercontent.com/elastic/ecs-logging/main/spec/spec.json 42 | 43 | sha: 44 | name: Get commit 45 | kind: json 46 | spec: 47 | file: 'https://api.github.com/repos/elastic/ecs-logging/commits?path=spec%2Fspec.json&page=1&per_page=1' 48 | key: ".[0].sha" 49 | 50 | targets: 51 | spec.json-update: 52 | name: 'synchronize ecs-logging spec' 53 | kind: file 54 | sourceid: spec.json 55 | scmid: githubConfig 56 | spec: 57 | file: tests/Elastic.CommonSchema.Tests/Specs/spec.json 58 | -------------------------------------------------------------------------------- /src/Elastic.CommonSchema.BenchmarkDotNetExporter/Domain/BenchmarkEvent.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System.Collections.Generic; 6 | using System.Runtime.Serialization; 7 | using System.Text.Json.Serialization; 8 | 9 | namespace Elastic.CommonSchema.BenchmarkDotNetExporter.Domain 10 | { 11 | /// 12 | public class BenchmarkEvent : Event 13 | { 14 | /// 15 | [JsonPropertyName("description"), DataMember(Name = "description")] 16 | public string Description { get; set; } 17 | 18 | /// 19 | [JsonPropertyName("parameters"), DataMember(Name = "parameters")] 20 | public string Parameters { get; set; } 21 | 22 | /// 23 | [JsonPropertyName("method"), DataMember(Name = "method")] 24 | public string Method { get; set; } 25 | 26 | /// 27 | [JsonPropertyName("measurement_stages"), DataMember(Name = "measurement_stages")] 28 | public IEnumerable MeasurementStages { get; set; } 29 | 30 | /// 31 | [JsonPropertyName("repetitions"), DataMember(Name = "repetitions")] 32 | public BenchmarkSimplifiedWorkloadCounts Repetitions { get; set; } 33 | 34 | /// 35 | [JsonPropertyName("job_config"), DataMember(Name = "job_config")] 36 | public BenchmarkJobConfig JobConfig { get; set; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/Elastic.CommonSchema.Log4net.Tests/LogTestsBase.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using Elastic.CommonSchema.Tests.Specs; 9 | using log4net; 10 | using log4net.Core; 11 | using log4net.Repository.Hierarchy; 12 | 13 | namespace Elastic.CommonSchema.Log4net.Tests; 14 | 15 | public abstract class LogTestsBase 16 | { 17 | private static readonly object _lock = new(); 18 | protected List<(string Json, EcsDocument Base)> ToEcsEvents(List logEvents) => 19 | logEvents.Select(s => (s, EcsDocument.Deserialize(s))) 20 | .ToList(); 21 | 22 | protected void TestLogger(Action>> act) 23 | { 24 | lock (_lock) 25 | { 26 | var repositoryId = Guid.NewGuid().ToString(); 27 | var hierarchy = (Hierarchy)LogManager.CreateRepository(repositoryId); 28 | var appender = new TestAppender 29 | { 30 | Layout = new EcsLayout() 31 | }; 32 | hierarchy.Root.AddAppender(appender); 33 | hierarchy.Root.Level = Level.All; 34 | hierarchy.Configured = true; 35 | 36 | List GetAndValidateLogEvents() 37 | { 38 | foreach (var log in appender.Events) 39 | Spec.Validate(log); 40 | 41 | return appender.Events; 42 | } 43 | 44 | var log = LogManager.GetLogger(repositoryId, GetType().Name); 45 | act(log, GetAndValidateLogEvents); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Views/EcsJsonContext.Generated.cshtml: -------------------------------------------------------------------------------- 1 | @* ReSharper disable once RedundantUsingDirective *@ 2 | @using System 3 | @inherits Elastic.CommonSchema.Generator.Views.CodeTemplatePage 4 | // Licensed to Elasticsearch B.V under one or more agreements. 5 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 6 | // See the LICENSE file in the project root for more information 7 | 8 | 9 | /* 10 | IMPORTANT NOTE 11 | ============== 12 | This file has been generated. 13 | If you wish to submit a PR please modify the original csharp file and submit the PR with that change. Thanks! 14 | */ 15 | 16 | using System.Text.Json.Serialization; 17 | 18 | namespace Elastic.CommonSchema.Serialization; 19 | 20 | /// An implementation of that could be used to be combined with user data 21 | [JsonSerializable(typeof(EcsDocument))] 22 | [JsonSerializable(typeof(Labels))] 23 | @foreach (var property in Model.Base.EntityProperties) 24 | { 25 | [JsonSerializable(typeof(@property.Entity.Name))] 26 | 27 | } 28 | @foreach (var entity in Model.EntityClasses) 29 | { 30 | [JsonSerializable(typeof(@entity.Name))] 31 | 32 | } 33 | [JsonSerializable(typeof(ParserIntermediary.LogOriginInvalid))] 34 | [JsonSerializable(typeof(ParserIntermediary.LogFileOriginInvalid))] 35 | [JsonSourceGenerationOptions(DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] 36 | public partial class EcsJsonContext : JsonSerializerContext { } 37 | -------------------------------------------------------------------------------- /tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(MSBuildThisFileDirectory)\.runsettings 6 | True 7 | embedded 8 | 9 | true 10 | ..\..\build\keys\keypair.snk 11 | xUnit1041 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/Views/AssignableInterfaces.Generated.cshtml: -------------------------------------------------------------------------------- 1 | @* ReSharper disable once RedundantUsingDirective *@ 2 | @using System 3 | @using System.Linq 4 | @inherits Elastic.CommonSchema.Generator.Views.CodeTemplatePage 5 | // Licensed to Elasticsearch B.V under one or more agreements. 6 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 7 | // See the LICENSE file in the project root for more information 8 | 9 | /* 10 | IMPORTANT NOTE 11 | ============== 12 | This file has been generated. 13 | If you wish to submit a PR please modify the original csharp file and submit the PR with that change. Thanks! 14 | */ 15 | 16 | // ReSharper disable RedundantUsingDirective 17 | using System; 18 | using System.Collections.Generic; 19 | using System.Threading; 20 | using System.Threading.Tasks; 21 | using System.Linq; 22 | using System.Net; 23 | using System.Runtime.Serialization; 24 | using System.Text.Json.Serialization; 25 | 26 | #nullable enable 27 | namespace Elastic.CommonSchema 28 | { 29 | @foreach (var inlineObject in Model.AssignableInterfaces) 30 | { 31 | var prop = inlineObject.Property; 32 | var implementations = string.Join(", ", inlineObject.Entities.Select(e=>e.Name)); 33 | 34 | /// Interface for entities that can assign an @(inlineObject.Name): @(implementations) 35 | public interface @inlineObject.Name { 36 | ///@prop.JsonProperty 37 | public @prop.ClrType? @prop.Name { get; set; } 38 | } 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Elastic.Serilog.Sinks.Tests/JsonStringConfigSource.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.Configuration.Json; 3 | 4 | namespace Elastic.Serilog.Sinks.Tests; 5 | 6 | public class JsonStringConfigSource : IConfigurationSource 7 | { 8 | private readonly string _json; 9 | 10 | public JsonStringConfigSource(string json) => _json = json; 11 | 12 | public IConfigurationProvider Build(IConfigurationBuilder builder) => 13 | new JsonStringConfigProvider(_json); 14 | 15 | public static IConfigurationSection LoadSection(string json, string section) => 16 | new ConfigurationBuilder().Add(new JsonStringConfigSource(json)).Build().GetSection(section); 17 | 18 | public static IDictionary LoadData(string json) 19 | { 20 | var provider = new JsonStringConfigProvider(json); 21 | provider.Load(); 22 | return provider.Data; 23 | } 24 | 25 | private class JsonStringConfigProvider : JsonConfigurationProvider 26 | { 27 | private readonly string _json; 28 | 29 | public JsonStringConfigProvider(string json) : base(new JsonConfigurationSource { Optional = true }) => _json = json; 30 | 31 | public new IDictionary Data => base.Data; 32 | 33 | public override void Load() => Load(StringToStream(_json)); 34 | 35 | private static Stream StringToStream(string str) 36 | { 37 | var memStream = new MemoryStream(); 38 | var textWriter = new StreamWriter(memStream); 39 | textWriter.Write(str); 40 | textWriter.Flush(); 41 | memStream.Seek(0, SeekOrigin.Begin); 42 | 43 | return memStream; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests-integration/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(MSBuildThisFileDirectory)\.runsettings 6 | True 7 | embedded 8 | 9 | true 10 | ..\..\build\keys\keypair.snk 11 | xUnit1041 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tools/Elastic.CommonSchema.Generator/CodeConfiguration.cs: -------------------------------------------------------------------------------- 1 | // Licensed to Elasticsearch B.V under one or more agreements. 2 | // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. 3 | // See the LICENSE file in the project root for more information 4 | 5 | using System; 6 | using System.IO; 7 | 8 | namespace Elastic.CommonSchema.Generator; 9 | 10 | public static class CodeConfiguration 11 | { 12 | static CodeConfiguration() 13 | { 14 | var rootInfo = new DirectoryInfo(Directory.GetCurrentDirectory()); 15 | do 16 | { 17 | var file = new FileInfo(Path.Combine(rootInfo.FullName, "license.txt")); 18 | if (file.Exists) break; 19 | rootInfo = rootInfo.Parent; 20 | 21 | } while (rootInfo != null && rootInfo != rootInfo.Root); 22 | 23 | if (rootInfo == null) 24 | throw new Exception("Can not resolve folder structure for ECS.NET codebase"); 25 | 26 | Root = rootInfo.FullName; 27 | SourceFolder = Path.Combine(Root, "src"); 28 | ToolFolder = Path.Combine(Root, "tools"); 29 | ElasticCommonSchemaGeneratedFolder = Path.Combine(SourceFolder, "Elastic.CommonSchema"); 30 | SpecificationFolder = Path.Combine(SourceFolder, "Specification"); 31 | ViewFolder = Path.Combine(ToolFolder, "Elastic.CommonSchema.Generator", "Views"); 32 | } 33 | 34 | public static string Root { get; } 35 | 36 | private static string SourceFolder { get; } 37 | private static string ToolFolder { get; } 38 | 39 | public static string ElasticCommonSchemaGeneratedFolder { get; } 40 | public static string SpecificationFolder { get; } 41 | public static string ViewFolder { get; } 42 | } 43 | -------------------------------------------------------------------------------- /src/Specification/v8.11.0/composable/component/rule.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-rule.html", 4 | "ecs_version": "8.11.0" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "rule": { 10 | "properties": { 11 | "author": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "category": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "description": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | }, 23 | "id": { 24 | "ignore_above": 1024, 25 | "type": "keyword" 26 | }, 27 | "license": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | }, 31 | "name": { 32 | "ignore_above": 1024, 33 | "type": "keyword" 34 | }, 35 | "reference": { 36 | "ignore_above": 1024, 37 | "type": "keyword" 38 | }, 39 | "ruleset": { 40 | "ignore_above": 1024, 41 | "type": "keyword" 42 | }, 43 | "uuid": { 44 | "ignore_above": 1024, 45 | "type": "keyword" 46 | }, 47 | "version": { 48 | "ignore_above": 1024, 49 | "type": "keyword" 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Specification/v8.3.1/composable/component/rule.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-rule.html", 4 | "ecs_version": "8.3.1" 5 | }, 6 | "template": { 7 | "mappings": { 8 | "properties": { 9 | "rule": { 10 | "properties": { 11 | "author": { 12 | "ignore_above": 1024, 13 | "type": "keyword" 14 | }, 15 | "category": { 16 | "ignore_above": 1024, 17 | "type": "keyword" 18 | }, 19 | "description": { 20 | "ignore_above": 1024, 21 | "type": "keyword" 22 | }, 23 | "id": { 24 | "ignore_above": 1024, 25 | "type": "keyword" 26 | }, 27 | "license": { 28 | "ignore_above": 1024, 29 | "type": "keyword" 30 | }, 31 | "name": { 32 | "ignore_above": 1024, 33 | "type": "keyword" 34 | }, 35 | "reference": { 36 | "ignore_above": 1024, 37 | "type": "keyword" 38 | }, 39 | "ruleset": { 40 | "ignore_above": 1024, 41 | "type": "keyword" 42 | }, 43 | "uuid": { 44 | "ignore_above": 1024, 45 | "type": "keyword" 46 | }, 47 | "version": { 48 | "ignore_above": 1024, 49 | "type": "keyword" 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | --------------------------------------------------------------------------------