Skip to content

Commit

Permalink
Ensure Elastic.Extensions.Logging can set auth through config (#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mpdreamz committed Jun 23, 2023
1 parent 53a382d commit bdee3fa
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 18 deletions.
1 change: 1 addition & 0 deletions ecs-dotnet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7610B796-BB3E-4CB2-8296-79BBFF6D23FC}"
ProjectSection(SolutionItems) = preProject
src\Directory.Build.props = src\Directory.Build.props
src\NullableExtensions.cs = src\NullableExtensions.cs
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{3582B07D-C2B0-49CC-B676-EAF806EB010E}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<Description>Serilog TextFormatter that formats log events in accordance with Elastic Common Schema (ECS).</Description>
<IsPackable>True</IsPackable>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="Lib\UAParser.regexes.yaml" />
Expand All @@ -20,13 +21,12 @@
<ProjectReference Include="..\Elastic.CommonSchema\Elastic.CommonSchema.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="PolySharp" Version="1.13.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Serilog" Version="2.9.0.0" />
<PackageReference Condition="$(DefineConstants.Contains(NETSTANDARD))" Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.1.0.0" />
<PackageReference Condition="$(DefineConstants.Contains(NETSTANDARD))" Include="Microsoft.AspNetCore.Http.Extensions" Version="2.1.0.0" />
<Reference Condition="$(DefineConstants.Contains(FULLFRAMEWORK))" Include="System.Web" />
<PackageReference Include="PolySharp" Version="1.13.2" PrivateAssets="all">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
11 changes: 7 additions & 4 deletions src/Elastic.Extensions.Logging/Elastic.Extensions.Logging.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@
<Title>Elasticsearch Logger Provider</Title>
<Description>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.</Description>
<PackageTags>Logging;LoggerProvider;Elasticsearch;ELK;Kibana;Logstash;Tracing;Diagnostics;Log;Trace;ECS</PackageTags>
<LangVersion>8</LangVersion>
<Nullable>enable</Nullable>
<IsPackable>True</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="2.1.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Elastic.CommonSchema\Elastic.CommonSchema.csproj" />
<ProjectReference Include="..\Elastic.Ingest.Elasticsearch.CommonSchema\Elastic.Ingest.Elasticsearch.CommonSchema.csproj" />
<PackageReference Include="PolySharp" Version="1.13.2" PrivateAssets="all">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<Compile Include="..\NullableExtensions.cs" />
</ItemGroup>

</Project>
39 changes: 33 additions & 6 deletions src/Elastic.Extensions.Logging/ElasticsearchLoggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,26 @@ private static NodePool CreateNodePool(ElasticsearchLoggerOptions loggerOptions)
return new StaticNodePool(nodeUris);
// case NodePoolType.StickySniffing:
case NodePoolType.Cloud:
if (!string.IsNullOrEmpty(shipTo.ApiKey))
if (shipTo.CloudId.IsNullOrEmpty())
throw new Exception($"Cloud {nameof(CloudNodePool)} requires '{nameof(ShipToOptions.CloudId)}' to be provided as well");

if (!shipTo.ApiKey.IsNullOrEmpty())
{
var apiKeyCredentials = new ApiKey(shipTo.ApiKey);
return new CloudNodePool(shipTo.CloudId, apiKeyCredentials);
}

var basicAuthCredentials = new BasicAuthentication(shipTo.Username, shipTo.Password);
return new CloudNodePool(shipTo.CloudId, basicAuthCredentials);
if (!shipTo.Username.IsNullOrEmpty() && !shipTo.Password.IsNullOrEmpty())
{
var basicAuthCredentials = new BasicAuthentication(shipTo.Username, shipTo.Password);
return new CloudNodePool(shipTo.CloudId, basicAuthCredentials);
}
throw new Exception(
$"Cloud requires either '{nameof(ShipToOptions.ApiKey)}' or"
+ $"'{nameof(ShipToOptions.Username)}' and '{nameof(ShipToOptions.Password)}"
);
default:
throw new ArgumentException($"Unrecognised connection pool type '{connectionPool}' specified in the configuration.", nameof(connectionPool));
throw new ArgumentException($"Unrecognised connection pool type '{connectionPool}' specified in the configuration.",
nameof(connectionPool));
}
}

Expand All @@ -120,12 +130,29 @@ private static HttpTransport CreateTransport(ElasticsearchLoggerOptions loggerOp
// TODO: Check if Uri has changed before recreating
// TODO: Injectable factory? Or some way of testing.
if (loggerOptions.Transport != null) return loggerOptions.Transport;

var connectionPool = CreateNodePool(loggerOptions);
var config = new TransportConfiguration(connectionPool, productRegistration: new ElasticsearchProductRegistration());
// Cloud sets authentication as required parameter in the constructor
if (loggerOptions.ShipTo.NodePoolType != NodePoolType.Cloud)
config = SetAuthenticationOnTransport(loggerOptions, config);

var transport = new DefaultHttpTransport<TransportConfiguration>(config);
return transport;
}

private static TransportConfiguration SetAuthenticationOnTransport(ElasticsearchLoggerOptions loggerOptions, TransportConfiguration config)
{
var apiKey = loggerOptions.ShipTo.ApiKey;
var username = loggerOptions.ShipTo.Username;
var password = loggerOptions.ShipTo.Password;
if (!username.IsNullOrEmpty() && !password.IsNullOrEmpty())
config = config.Authentication(new BasicAuthentication(username, password));
else if (!apiKey.IsNullOrEmpty())
config = config.Authentication(new ApiKey(apiKey));
return config;
}

private void ReloadShipper(ElasticsearchLoggerOptions loggerOptions)
{
var newShipper = CreatIngestChannel(loggerOptions);
Expand Down Expand Up @@ -157,7 +184,7 @@ private IBufferedChannel<LogEvent> CreatIngestChannel(ElasticsearchLoggerOptions
WriteEvent = async (stream, ctx, logEvent) => await logEvent.SerializeAsync(stream, ctx).ConfigureAwait(false),
};
SetupChannelOptions(_channelConfigurations, indexChannelOptions);
var channel = new EcsDataStreamChannel<LogEvent>(indexChannelOptions);
var channel = new EcsDataStreamChannel<LogEvent>(indexChannelOptions);
channel.BootstrapElasticsearch(loggerOptions.BootstrapMethod);
return channel;
}
Expand Down
8 changes: 4 additions & 4 deletions src/Elastic.Extensions.Logging/Options/ShipToOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ public class ShipToOptions
/// <summary>
/// Gets or sets the API Key, where connection pool type is Cloud, and authenticating via API Key.
/// </summary>
public string ApiKey { get; set; } = "";
public string? ApiKey { get; set; }

/// <summary>
/// Gets or sets the cloud ID, where connection pool type is Cloud.
/// </summary>
public string CloudId { get; set; } = "";
public string? CloudId { get; set; }

/// <summary>
/// Gets or sets the connection pool type. Default for multiple nodes is <c>Sniffing</c>; other supported values are
Expand All @@ -36,11 +36,11 @@ public class ShipToOptions
/// <summary>
/// Gets or sets the password, where connection pool type is Cloud, and authenticating via username/password.
/// </summary>
public string Password { get; set; } = "";
public string? Password { get; set; } = "";

/// <summary>
/// Gets or sets the username, where connection pool type is Cloud, and authenticating via username/password.
/// </summary>
public string Username { get; set; } = "";
public string? Username { get; set; } = "";
}
}
7 changes: 7 additions & 0 deletions src/NullableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using System.Diagnostics.CodeAnalysis;

namespace System;
internal static class NullableStringExtensions {
internal static bool IsNullOrEmpty([NotNullWhen(false)] this string? data) =>
string.IsNullOrEmpty(data);
}

0 comments on commit bdee3fa

Please sign in to comment.