Skip to content

Commit dbf2106

Browse files
authored
Assign WorkloadIdentityClientId from ClientIdentity (#156)
* Assign WorkloadIdentityClientId from ClientIdentity * Updated unit-test dependencies * AzureDataTables - NLogEntity - Skip AggregateException.Flatten when not needed * AzureDataTables - Override Layout default value to just ${message} * AzureDataTables - Added documentation about Column Value size limits * Updated unit-test dependencies * Explicit specify RetryDelayMilliseconds to avoid default of 500ms * Removed NLog.Extensions.AzureAccessToken from solution-file * BlobStorageTarget - Handle invalid empty BlobName + ContainerName * DataTablesTarget - Handle invalid empty TableName * QueueStorageTarget - Handle invalid empty QueueName * Updated to Azure.Messaging.EventGrid ver. 4.24.1 * Removed User delegation SAS since it confuses * Microsoft.NET.Test.Sdk ver. 17.13.0
1 parent 4a58c75 commit dbf2106

File tree

31 files changed

+173
-97
lines changed

31 files changed

+173
-97
lines changed

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
| Package Name | NuGet | Description | Documentation |
66
| ------------------------------------- | :-------------------: | ----------- | ------------- |
77
| **NLog.Extensions.AzureBlobStorage** | [![NuGet](https://img.shields.io/nuget/v/NLog.Extensions.AzureBlobStorage.svg)](https://www.nuget.org/packages/NLog.Extensions.AzureBlobStorage/) | Azure Blob Storage | [![](https://img.shields.io/badge/Readme-Docs-blue)](src/NLog.Extensions.AzureBlobStorage/README.md) |
8-
| **NLog.Extensions.AzureDataTables** | [![NuGet](https://img.shields.io/nuget/v/NLog.Extensions.AzureDataTables.svg)](https://www.nuget.org/packages/NLog.Extensions.AzureDataTables/) | Azure Table Storage or Azure CosmosDb Tables | [![](https://img.shields.io/badge/Readme-Docs-blue)](src/NLog.Extensions.AzureDataTables/README.md) |
8+
| **NLog.Extensions.AzureDataTables** | [![NuGet](https://img.shields.io/nuget/v/NLog.Extensions.AzureDataTables.svg)](https://www.nuget.org/packages/NLog.Extensions.AzureDataTables/) | Azure Table Storage or Azure CosmosDb Tables | [![](https://img.shields.io/badge/Readme-Docs-blue)](src/NLog.Extensions.AzureDataTables/README.md) |
99
| **NLog.Extensions.AzureEventHub** | [![NuGet](https://img.shields.io/nuget/v/NLog.Extensions.AzureEventHub.svg)](https://www.nuget.org/packages/NLog.Extensions.AzureEventHub/) | Azure EventHubs | [![](https://img.shields.io/badge/Readme-Docs-blue)](src/NLog.Extensions.AzureEventHub/README.md) |
10-
| **NLog.Extensions.AzureEventGrid** | [![NuGet](https://img.shields.io/nuget/v/NLog.Extensions.AzureEventGrid.svg)](https://www.nuget.org/packages/NLog.Extensions.AzureEventGrid/) | Azure Event Grid | [![](https://img.shields.io/badge/Readme-Docs-blue)](src/NLog.Extensions.AzureEventGrid/README.md) |
10+
| **NLog.Extensions.AzureEventGrid** | [![NuGet](https://img.shields.io/nuget/v/NLog.Extensions.AzureEventGrid.svg)](https://www.nuget.org/packages/NLog.Extensions.AzureEventGrid/) | Azure Event Grid | [![](https://img.shields.io/badge/Readme-Docs-blue)](src/NLog.Extensions.AzureEventGrid/README.md) |
1111
| **NLog.Extensions.AzureQueueStorage** | [![NuGet](https://img.shields.io/nuget/v/NLog.Extensions.AzureQueueStorage.svg)](https://www.nuget.org/packages/NLog.Extensions.AzureQueueStorage/) | Azure Queue Storage | [![](https://img.shields.io/badge/Readme-Docs-blue)](src/NLog.Extensions.AzureQueueStorage/README.md) |
12-
| **NLog.Extensions.AzureServiceBus** | [![NuGet](https://img.shields.io/nuget/v/NLog.Extensions.AzureServiceBus.svg)](https://www.nuget.org/packages/NLog.Extensions.AzureServiceBus/) | Azure Service Bus | [![](https://img.shields.io/badge/Readme-Docs-blue)](src/NLog.Extensions.AzureServiceBus/README.md) |
12+
| **NLog.Extensions.AzureServiceBus** | [![NuGet](https://img.shields.io/nuget/v/NLog.Extensions.AzureServiceBus.svg)](https://www.nuget.org/packages/NLog.Extensions.AzureServiceBus/) | Azure Service Bus | [![](https://img.shields.io/badge/Readme-Docs-blue)](src/NLog.Extensions.AzureServiceBus/README.md) |
1313
| **NLog.Extensions.AzureAccessToken** | [![NuGet](https://img.shields.io/nuget/v/NLog.Extensions.AzureAccessToken.svg)](https://www.nuget.org/packages/NLog.Extensions.AzureAccessToken/) | Azure App Authentication Access Token for Managed Identity | [![](https://img.shields.io/badge/Readme-Docs-blue)](src/NLog.Extensions.AzureAccessToken/README.md) |
1414

1515
Initially all NLog targets was bundled into a single nuget-package called [NLog.Extensions.AzureStorage](https://www.nuget.org/packages/NLog.Extensions.AzureStorage/).
@@ -27,7 +27,6 @@ and so [NLog.Extensions.AzureCosmosTable](https://www.nuget.org/packages/NLog.Ex
2727
<add assembly="NLog.Extensions.AzureEventHub" />
2828
<add assembly="NLog.Extensions.AzureEventGrid" />
2929
<add assembly="NLog.Extensions.AzureServiceBus" />
30-
<add assembly="NLog.Extensions.AzureAccessToken" />
3130
</extensions>
3231

3332
<targets async="true">

appveyor.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ build_script:
1010
- cmd: msbuild /t:Pack src\NLog.Extensions.AzureEventGrid /p:Configuration=Release /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg /p:ContinuousIntegrationBuild=true /p:EmbedUntrackedSources=true /p:PublishRepositoryUrl=true /verbosity:minimal
1111
- cmd: msbuild /t:Pack src\NLog.Extensions.AzureEventHub /p:Configuration=Release /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg /p:ContinuousIntegrationBuild=true /p:EmbedUntrackedSources=true /p:PublishRepositoryUrl=true /verbosity:minimal
1212
- cmd: msbuild /t:Pack src\NLog.Extensions.AzureServiceBus /p:Configuration=Release /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg /p:ContinuousIntegrationBuild=true /p:EmbedUntrackedSources=true /p:PublishRepositoryUrl=true /verbosity:minimal
13-
- cmd: msbuild /t:Pack src\NLog.Extensions.AzureAccessToken /p:Configuration=Release /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg /p:ContinuousIntegrationBuild=true /p:EmbedUntrackedSources=true /p:PublishRepositoryUrl=true /verbosity:minimal
1413

1514
test_script:
1615
- cmd: dotnet test test\NLog.Extensions.AzureBlobStorage.Tests /p:Configuration=Release --verbosity minimal
@@ -19,7 +18,6 @@ test_script:
1918
- cmd: dotnet test test\NLog.Extensions.AzureEventGrid.Tests /p:Configuration=Release --verbosity minimal
2019
- cmd: dotnet test test\NLog.Extensions.AzureEventHub.Tests /p:Configuration=Release --verbosity minimal
2120
- cmd: dotnet test test\NLog.Extensions.AzureServiceBus.Tests /p:Configuration=Release --verbosity minimal
22-
- cmd: dotnet test test\NLog.Extensions.AzureAccessToken.Tests /p:Configuration=Release --verbosity minimal
2321

2422
artifacts:
2523
- path: '**\NLog.Extensions.Azure*.nupkg'

src/NLog.Extensions.AzureBlobStorage/BlobStorageTarget.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public sealed class BlobStorageTarget : AsyncTaskTarget
4949
public Layout ResourceIdentity { get; set; }
5050

5151
/// <summary>
52-
/// Alternative to ConnectionString, when using <see cref="ServiceUri"/> with ManagedIdentityClientId
52+
/// Alternative to ConnectionString, when using <see cref="ServiceUri"/> with ManagedIdentityClientId / WorkloadIdentityClientId
5353
/// </summary>
5454
public Layout ClientIdentity { get; set; }
5555

@@ -95,6 +95,7 @@ internal BlobStorageTarget(ICloudBlobService cloudBlobService)
9595
{
9696
TaskDelayMilliseconds = 200;
9797
BatchSize = 100;
98+
RetryDelayMilliseconds = 100;
9899

99100
BlobMetadata = new List<TargetPropertyWithContext>();
100101
BlobTags = new List<TargetPropertyWithContext>();
@@ -405,7 +406,7 @@ public Task AppendFromByteArrayAsync(string containerName, string blobName, stri
405406

406407
var blob = _appendBlob;
407408
var container = _container;
408-
if (containerName == null || container?.Name != containerName || blobName == null || blob?.Name != blobName)
409+
if (string.IsNullOrEmpty(containerName) || container?.Name != containerName || string.IsNullOrEmpty(blobName) || blob?.Name != blobName)
409410
{
410411
return InitializeAndCacheBlobAsync(containerName, blobName, contentType, cancellationToken).ContinueWith(async (t, s) => await t.Result.AppendBlockAsync((System.IO.Stream)s, null).ConfigureAwait(false), stream, cancellationToken);
411412
}
@@ -420,7 +421,7 @@ async Task<AppendBlobClient> InitializeAndCacheBlobAsync(string containerName, s
420421
try
421422
{
422423
var container = _container;
423-
if (containerName == null || container?.Name != containerName)
424+
if (string.IsNullOrEmpty(containerName) || container?.Name != containerName)
424425
{
425426
container = await InitializeContainer(containerName, cancellationToken).ConfigureAwait(false);
426427
if (container != null)
@@ -431,7 +432,7 @@ async Task<AppendBlobClient> InitializeAndCacheBlobAsync(string containerName, s
431432
}
432433

433434
var blob = _appendBlob;
434-
if (blobName == null || blob?.Name != blobName)
435+
if (string.IsNullOrEmpty(blobName) || blob?.Name != blobName)
435436
{
436437
blob = await InitializeBlob(blobName, container, contentType, cancellationToken).ConfigureAwait(false);
437438
if (blob != null && ReferenceEquals(container, _container))

src/NLog.Extensions.AzureBlobStorage/NLog.Extensions.AzureBlobStorage.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
<RepositoryUrl>https://github.com/JDetmar/NLog.Extensions.AzureStorage.git</RepositoryUrl>
1919
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2020
<PackageReleaseNotes>
21-
- Updated dependency Azure.Identity v1.11.4 because of security issues.
22-
- Updated dependency Azure.Storage.Blobs v12.19.1
21+
- Assign WorkloadIdentityClientId from ClientIdentity
2322

2423
Docs: https://github.com/JDetmar/NLog.Extensions.AzureStorage/blob/master/src/NLog.Extensions.AzureBlobStorage/README.md
2524
</PackageReleaseNotes>

src/NLog.Extensions.AzureBlobStorage/README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,21 @@ _name_ - Name of the target.
3131

3232
_layout_ - Text to be rendered. [Layout](https://github.com/NLog/NLog/wiki/Layouts) Required.
3333

34-
_blobName_ - BlobName. [Layout](https://github.com/NLog/NLog/wiki/Layouts)
34+
_blobName_ - BlobName. [Layout](https://github.com/NLog/NLog/wiki/Layouts) Required.
3535

36-
_container_ - Azure blob container name. [Layout](https://github.com/NLog/NLog/wiki/Layouts)
36+
_container_ - Azure blob container name. [Layout](https://github.com/NLog/NLog/wiki/Layouts) Required.
3737

3838
_contentType_ - Azure blob ContentType (Default = text/plain)
3939

4040
_connectionString_ - Azure storage connection string. Ex. `UseDevelopmentStorage=true;`
4141

42-
_serviceUri_ - Alternative to ConnectionString, where Managed Identiy is acquired from DefaultAzureCredential for User delegation SAS.
42+
_serviceUri_ - Alternative to ConnectionString, where Managed Identiy is acquired from DefaultAzureCredential.
4343

44-
_tenantIdentity_ - Alternative to ConnectionString. Used together with ServiceUri. Input for DefaultAzureCredential.
44+
_clientIdentity_ - Alternative to ConnectionString. Used together with ServiceUri. Input for DefaultAzureCredential as ManagedIdentityClientId.
4545

4646
_resourceIdentity_ - Alternative to ConnectionString. Used together with ServiceUri. Input for DefaultAzureCredential as ManagedIdentityResourceId.
4747

48-
_clientIdentity_ - Alternative to ConnectionString. Used together with ServiceUri. Input for DefaultAzureCredential as ManagedIdentityClientId.
48+
_tenantIdentity_ - Alternative to ConnectionString. Used together with ServiceUri. Input for DefaultAzureCredential.
4949

5050
_sharedAccessSignature_ - Alternative to ConnectionString. Used together with ServiceUri. Input for AzureSasCredential
5151

@@ -81,6 +81,13 @@ Azure.RequestFailedException: This feature is not currently supported by the Sto
8181

8282
Instead one can try an alternative Azure Storage Emulator like [Azurite](https://github.com/azure/azurite)
8383

84+
## Azure Identity Environment
85+
When using `ServiceUri` (Instead of ConnectionString), then `DefaultAzureCredential` is used for Azure Identity which supports environment variables:
86+
- `AZURE_CLIENT_ID` - For ManagedIdentityClientId / WorkloadIdentityClientId
87+
- `AZURE_TENANT_ID` - For TenantId
88+
89+
See also: [Set up Your Environment for Authentication](https://github.com/Azure/azure-sdk-for-go/wiki/Set-up-Your-Environment-for-Authentication)
90+
8491
## Azure ConnectionString
8592

8693
NLog Layout makes it possible to retrieve settings from [many locations](https://nlog-project.org/config/?tab=layout-renderers).

src/NLog.Extensions.AzureDataTables/DataTablesTarget.cs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ namespace NLog.Targets
1717
[Target("AzureDataTables")]
1818
public sealed class DataTablesTarget : AsyncTaskTarget
1919
{
20+
internal const int ColumnStringValueMaxSize = 32768;
21+
2022
private readonly ICloudTableService _cloudTableService;
2123
private string _machineName;
2224
private readonly AzureStorageNameCache _containerNameCache = new AzureStorageNameCache();
@@ -79,7 +81,7 @@ public override int GetHashCode()
7981
public Layout ResourceIdentity { get; set; }
8082

8183
/// <summary>
82-
/// Alternative to ConnectionString, when using <see cref="ServiceUri"/> with ManagedIdentityClientId
84+
/// Alternative to ConnectionString, when using <see cref="ServiceUri"/> with ManagedIdentityClientId / WorkloadIdentityClientId
8385
/// </summary>
8486
public Layout ClientIdentity { get; set; }
8587

@@ -117,12 +119,14 @@ public override int GetHashCode()
117119
public DataTablesTarget()
118120
:this(new CloudTableService())
119121
{
122+
Layout = "${message}"; // Override default Layout, since splitting into columns
120123
}
121124

122125
internal DataTablesTarget(ICloudTableService cloudTableService)
123126
{
124127
TaskDelayMilliseconds = 200;
125128
BatchSize = 100;
129+
RetryDelayMilliseconds = 100;
126130

127131
RowKey = Layout.FromMethod(l => string.Concat((DateTime.MaxValue.Ticks - l.TimeStamp.Ticks).ToString("d19"), "__", Guid.NewGuid().ToString()), LayoutRenderOptions.ThreadAgnostic);
128132

@@ -298,18 +302,32 @@ private ITableEntity CreateTableEntity(LogEventInfo logEvent, string partitionKe
298302
if (string.IsNullOrEmpty(contextproperty.Name))
299303
continue;
300304

301-
var propertyValue = contextproperty.Layout != null ? RenderLogEvent(contextproperty.Layout, logEvent) : string.Empty;
305+
var propertyValue = RenderLogEvent(contextproperty.Layout, logEvent) ?? string.Empty;
302306
if (logTimeStampOverridden && i == 0 && string.IsNullOrEmpty(propertyValue))
303307
continue;
304308

309+
if (!contextproperty.IncludeEmptyValue && string.IsNullOrEmpty(propertyValue))
310+
continue;
311+
312+
if (propertyValue.Length >= ColumnStringValueMaxSize)
313+
{
314+
InternalLogger.Debug("AzureDataTablesTarget(Name={0}): Truncating value from column '{1}', because string-length above 32K", Name, contextproperty.Name);
315+
propertyValue = propertyValue.Substring(0, ColumnStringValueMaxSize - 1);
316+
}
317+
305318
entity.Add(contextproperty.Name, propertyValue);
306319
}
307320

308321
return entity;
309322
}
310323
else
311324
{
312-
var layoutMessage = RenderLogEvent(Layout, logEvent);
325+
var layoutMessage = RenderLogEvent(Layout, logEvent) ?? string.Empty;
326+
if (layoutMessage.Length >= ColumnStringValueMaxSize)
327+
{
328+
layoutMessage = layoutMessage.Substring(0, ColumnStringValueMaxSize - 1);
329+
InternalLogger.Debug("AzureDataTablesTarget(Name={0}): Truncating value from Layout, because string-length above 32K", Name);
330+
}
313331
return new NLogEntity(logEvent, layoutMessage, _machineName, partitionKey, rowKey, LogTimeStampFormat);
314332
}
315333
}
@@ -390,7 +408,7 @@ public void Connect(string connectionString, string serviceUri, string tenantIde
390408
public Task SubmitTransactionAsync(string tableName, IEnumerable<TableTransactionAction> tableTransaction, CancellationToken cancellationToken)
391409
{
392410
var table = _table;
393-
if (tableName == null || table?.Name != tableName)
411+
if (string.IsNullOrEmpty(tableName) || table?.Name != tableName)
394412
{
395413
return InitializeAndCacheTableAsync(tableName, cancellationToken).ContinueWith(async (t, operation) => await t.Result.SubmitTransactionAsync((IEnumerable<TableTransactionAction>)operation).ConfigureAwait(false), tableTransaction, cancellationToken);
396414
}

src/NLog.Extensions.AzureDataTables/NLog.Extensions.AzureDataTables.csproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
<RepositoryUrl>https://github.com/JDetmar/NLog.Extensions.AzureStorage.git</RepositoryUrl>
1919
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2020
<PackageReleaseNotes>
21-
- Updated dependency Azure.Identity v1.11.4 because of security issues.
22-
- Updated dependency Azure.Data.Tables v12.8.3
21+
- Assign WorkloadIdentityClientId from ClientIdentity
22+
- Changed Layout default-value to ${message} since LogEvent is split into columns
23+
- Added automatic truncate when column-values has string-length above 32K
24+
- Skips adding column values when empty string and configured IncludeEmptyValue = false
2325

2426
Docs: https://github.com/JDetmar/NLog.Extensions.AzureStorage/blob/master/src/NLog.Extensions.AzureDataTables/README.md
2527
</PackageReleaseNotes>

src/NLog.Extensions.AzureDataTables/NLogEntity.cs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ public class NLogEntity: ITableEntity
2222

2323
public NLogEntity(LogEventInfo logEvent, string layoutMessage, string machineName, string partitionKey, string rowKey, string logTimeStampFormat)
2424
{
25-
FullMessage = layoutMessage;
25+
FullMessage = TruncateWhenTooBig(layoutMessage);
2626
Level = logEvent.Level.Name;
2727
LoggerName = logEvent.LoggerName;
28-
Message = logEvent.Message;
28+
Message = TruncateWhenTooBig(logEvent.Message);
2929
LogTimeStamp = logEvent.TimeStamp.ToString(logTimeStampFormat);
3030
MachineName = machineName;
3131
if(logEvent.Exception != null)
@@ -34,28 +34,44 @@ public NLogEntity(LogEventInfo logEvent, string layoutMessage, string machineNam
3434
var innerException = exception.InnerException;
3535
if (exception is AggregateException aggregateException)
3636
{
37-
var innerExceptions = aggregateException.Flatten();
38-
if (innerExceptions.InnerExceptions?.Count == 1)
37+
if (aggregateException.InnerExceptions?.Count == 1 && !(aggregateException.InnerExceptions[0] is AggregateException))
3938
{
40-
exception = innerExceptions.InnerExceptions[0];
41-
innerException = null;
39+
exception = aggregateException.InnerExceptions[0];
40+
innerException = exception.InnerException;
4241
}
4342
else
4443
{
45-
innerException = innerExceptions;
44+
var flatten = aggregateException.Flatten();
45+
if (flatten.InnerExceptions?.Count == 1)
46+
{
47+
exception = flatten.InnerExceptions[0];
48+
innerException = exception.InnerException;
49+
}
50+
else
51+
{
52+
innerException = flatten;
53+
}
4654
}
4755
}
4856

4957
Exception = string.Concat(exception.Message, " - ", exception.GetType().ToString());
50-
StackTrace = exception.StackTrace;
58+
StackTrace = TruncateWhenTooBig(exception.StackTrace);
5159
if (innerException != null)
5260
{
53-
InnerException = innerException.ToString();
61+
var innerExceptionText = innerException.ToString();
62+
InnerException = TruncateWhenTooBig(innerExceptionText);
5463
}
5564
}
5665
RowKey = rowKey;
5766
PartitionKey = partitionKey;
5867
}
68+
69+
private static string TruncateWhenTooBig(string stringValue)
70+
{
71+
return stringValue?.Length >= Targets.DataTablesTarget.ColumnStringValueMaxSize ?
72+
stringValue.Substring(0, Targets.DataTablesTarget.ColumnStringValueMaxSize - 1) : stringValue;
73+
}
74+
5975
public NLogEntity() { }
6076
}
6177
}

0 commit comments

Comments
 (0)