| File: BlobLoggerProvider.cs | Web Access |
| Project: src\aspnetcore\src\Logging.AzureAppServices\src\Microsoft.Extensions.Logging.AzureAppServices.csproj (Microsoft.Extensions.Logging.AzureAppServices) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Logging.AzureAppServices; /// <summary> /// The <see cref="ILoggerProvider"/> implementation that stores messages by appending them to Azure Blob in batches. /// </summary> [ProviderAlias("AzureAppServicesBlob")] public class BlobLoggerProvider : BatchingLoggerProvider { private readonly IOptionsMonitor<AzureBlobLoggerOptions> _options; private readonly Func<string, ICloudAppendBlob> _blobReferenceFactory; private readonly HttpClient _httpClient; /// <summary> /// Creates a new instance of <see cref="BlobLoggerProvider"/> /// </summary> /// <param name="options">The options to use when creating a provider.</param> [SuppressMessage("ApiDesign", "RS0022:Constructor make noninheritable base class inheritable", Justification = "Required for backwards compatibility")] public BlobLoggerProvider(IOptionsMonitor<AzureBlobLoggerOptions> options) : this(options, null) { _blobReferenceFactory = name => new BlobAppendReferenceWrapper( options.CurrentValue.ContainerUrl, name, _httpClient); } /// <summary> /// Creates a new instance of <see cref="BlobLoggerProvider"/> /// </summary> /// <param name="blobReferenceFactory">The container to store logs to.</param> /// <param name="options">Options to be used in creating a logger.</param> internal BlobLoggerProvider( IOptionsMonitor<AzureBlobLoggerOptions> options, Func<string, ICloudAppendBlob> blobReferenceFactory) : base(options) { _options = options; _blobReferenceFactory = blobReferenceFactory; _httpClient = new HttpClient(); } internal override async Task WriteMessagesAsync(IEnumerable<LogMessage> messages, CancellationToken cancellationToken) { var eventGroups = messages.GroupBy(GetBlobKey); var options = _options.CurrentValue; var identifier = options.ApplicationInstanceId + "_" + options.BlobName; foreach (var eventGroup in eventGroups) { var key = eventGroup.Key; string blobName = options.FileNameFormat(new AzureBlobLoggerContext( options.ApplicationName, identifier, new DateTimeOffset(key.Year, key.Month, key.Day, key.Hour, 0, 0, TimeSpan.Zero))); var blob = _blobReferenceFactory(blobName); using (var stream = new MemoryStream()) using (var writer = new StreamWriter(stream)) { foreach (var logEvent in eventGroup) { writer.Write(logEvent.Message); } writer.Flush(); var tryGetBuffer = stream.TryGetBuffer(out var buffer); System.Diagnostics.Debug.Assert(tryGetBuffer); await blob.AppendAsync(buffer, cancellationToken).ConfigureAwait(false); } } } private (int Year, int Month, int Day, int Hour) GetBlobKey(LogMessage e) { return (e.Timestamp.Year, e.Timestamp.Month, e.Timestamp.Day, e.Timestamp.Hour); } }