nreco / logging

Generic file logger for .NET Core (FileLoggerProvider) with minimal dependencies
MIT License
284 stars 56 forks source link

ASP .NET Core 5 usage: cannot read log file content - The process cannot access the file '...' because it is being used by another process #28

Closed bairog closed 2 years ago

bairog commented 2 years ago

Hello. I use your library in ASP .NET Core 5 Web app. In Startup.cs inside ConfigureServices(IServiceCollection services) I have:

services.AddLogging(loggingBuilder => {
                loggingBuilder.AddFile("Logs/app.log", options => {
                   options.Append = true;
                    options.MinLevel = LogLevel.Warning;
                    options.FileSizeLimitBytes = 5 * 1024 * 1024;
                    options.MaxRollingFiles = 1000;
                    });
            });

In Program.cs I resolve Ilogger via host.Services.GetService<ILogger<TelegramBot>>() and pass it to the constructor of a TelegramBot class. Inside the constructor logger is saved in local variable that is later used to log some events with logger.LogWarning() (specifically - bot start\stop events). On some page in my application I'm trying to read log file content with the following code (start\stop events are definitely doesn't happend and logger.LogWarning() is definitely not called at that moment):

            try
            {
                using (FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                ....
            }
            catch (IOException ex)
            {
                //Here I get 'The process cannot access the file '...' because it is being used by another process'
            }

but I get IOException

The process cannot access the file '...' because it is being used by another process

So what's wrong with my library usage? How can I properly read log file content? Can it be that logger unblocks log file only on Dispose() event? Should it live as short as possible (resolve->write log->dispose)?

VitaliyMF commented 2 years ago

I'm not sure that I understand how your code snippet is related to NReco.Logging.File at all. I don't see any ILogger calls here. It seems IOException is caused by your code that opens some file.

bairog commented 2 years ago

Ok, let me clarify:

It seems IOException is caused by your code that opens some file.

Yes IOException is caused by my code when I try to read a file where NReco.Logging.File logger is set to write log to.

I don't see any ILogger calls here.

My ILogger calls are pretty simple like

var _logger = services.GetRequiredService<ILogger<TelegramBot>>();
_logger.LogWarning("test");

I've even tried scoped approach like

using (var scope = _host.Services.CreateScope())
{
        var services = scope.ServiceProvider;
        var _logger = services.GetRequiredService<ILogger<TelegramBot>>();
        _logger.LogWarning("test");
}

In both cases log file stays locked even after leaving that blocks of code (your logging library doesn't close log file immediately).

P. S. I've just tried another file logging library Karambolo.Extensions.Logging.File. It behaves the same way by default but it has special options.FileAccessMode = LogFileAccessMode.OpenTemporarily option:

Opens the log file only when an entry needs to be written and then closes it immediately. (Provides the worst performance but log files won't be locked by the process.)

With this setting my problem goes away and I can access log file for reading it. I like you library - is there a similar option in it?

VitaliyMF commented 2 years ago

In both cases log file stays locked even after leaving that blocks of code (your logging library doesn't close log file immediately).

This is correct behavior. For performance purposes log file always remains open, and log entries are written (periodically) from the queue (this is performed in a special thread). When you call "LogWarning" this places a log entry into the queue -- that guarantees almost zero performance overhead and that thread that calls "LogWarning" will not be stopped because file logger internals.

With this setting my problem goes away and I can access log file for reading it. I like you library - is there a similar option in it?

When log file is opened for write you should be able to read it from your code with correct FileShare value: it should be FileShare.Read instead of FileShare.None (which declines sharing of the file, and as result you get 'The process cannot access the file' exception).

bairog commented 2 years ago

When log file is opened for write you should be able to read it from your code with correct FileShare value: it should be FileShare.Read instead of FileShare.None (which declines sharing of the file, and as result you get 'The process cannot access the file' exception).

That was just a misprint in my question's text (I've already updated it, thank you) - actually in my code I use FileShare.Read and IOException is raised even with that option. BTW Karambolo.Extensions.Logging.File. logging library behaves the same with default option (options.FileAccessMode = LogFileAccessMode.KeepOpenAndAutoFlush) but special options.FileAccessMode = LogFileAccessMode.OpenTemporarily option solves the problem there..

bairog commented 2 years ago

@VitaliyMF Ok, here is a sample repo for ASP .NET Core 5.0 Razor Pages Web Application to reproduce the problem. I simply have:

public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();

            ILogger logger = host.Services.GetService<ILogger<Program>>();
            logger.LogWarning("Test warning");

            host.Run();
        }

And after that on main page there is a button which tries to read from a log:

internal static string ReadLogFile(string filePath)
        {
            try
            {
                using (FileStream stream = System.IO.File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                using (StreamReader reader = new StreamReader(stream))
                {
                    return reader.ReadToEnd();
                }
            }
            catch (IOException ex)
            {
                //the file is unavailable because it is:
                //still being written to
                //or being processed by another thread
                //or does not exist (has already been processed)
                return ex.ToString();
            }
        }

Just compile, run and get an IOException by yourself.

bairog commented 2 years ago

@VitaliyMF So is there any workaround for this issue?

VitaliyMF commented 2 years ago

@bairog I'm rather busy last weeks so unfortunately didn't find some time to investigate why this happens and propose a workaround. JFYI, I was able to open an 'active' log file (when .net app is started) with, say, notepad -- so in fact it is not locked (for read) for other processes, but maybe it remains locked for the same process?..

bairog commented 2 years ago

JFYI, I was able to open an 'active' log file (when .net app is started) with, say, notepad

Yes, I know - opening log file with notepad++ was the first thing that I've tired..

-- so in fact it is not locked (for read) for other processes, but maybe it remains locked for the same process?..

I've just added new console application to my sample repo - unfortunately reading log file from it also fails with same error..

zoran-petrovic-87 commented 2 years ago

When using var log = await File.ReadAllTextAsync("app.log"); I get "The process cannot access the file '...' because it is being used by another process"

But this does work for me:

var log = "";
await using (var fileStream = new FileStream("app.log", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    using (var reader = new StreamReader(fileStream))
    {
        log = await reader.ReadToEndAsync();
    }
}

The problem here is that some logs are still not written to the file, so sometimes I end up with log that is not complete... I need to read log file when my console app is done with execution, so I did this:

// Force file logger to finish writing logs to file and release lock.
var fileProvider = serviceProvider.GetService(typeof(ILoggerProvider)) as FileLoggerProvider;
fileProvider?.Dispose();
var log = await File.ReadAllTextAsync("app.log");

Ugly but it works in my specific case. I think that library should provide a better way to handle this.

@VitaliyMF thanks for this library, I hope that you will continue to maintain it for a long time :)

LeeReid1 commented 2 years ago

Just to add to the mix, I find myself here because I've begun to see this repeatedly during app startup both locally and on the server itself. It's a fairly substantial issue because this causes startup to fail, meaning it takes down the entire web app.

Unlike @bairog I am not reading the log at all which suggests that the library is somehow not releasing the file during shutdown or object disposal and blocking itself (however doubtful that sounds). Once I hit this error, it occurs upon every app boot until I manually delete the file. If the error happens, I can't even open the file in notepad.

I will be taking a look today at some kind of workaround, though I'm not sure how much diagnostic progress I'll make because what I have been seeing is quite hard to replicate. Thanks to @bairog for setting something up that can at least cause the exception to be thrown 👍

For the record, my startup is fairly innocuous

services.AddLogging(logging =>
{
    // Logging via N.Reco.Logging to a file or two
    var loggingSection = Configuration.GetSection("Logging");
    logging.AddFile(loggingSection, config=>
        {
            config.FormatLogEntry = CustomErrorLoggingFormatter.FormatLogMessage; // an innocuous formatting method 
        });
   // NB Another logger appears here that does not use the file system
});

and my appSettings include the following

  "Logging": {
    "LogLevel": {
      "Default": "Error",
      "Microsoft": "Error",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "File": {
      "Path": "Logs/log.txt",
      "Append": "True",
      "MinLevel": "Warning", 
      "FileSizeLimitBytes": 10000000,
      "MaxRollingFiles": 3 
    }
  }
VitaliyMF commented 2 years ago

@LeeReid1 log file is opened when you call "AddFile" method in Startup.cs so you definitely can handle the exception and do something more reliable. If file is locked (for any reason) and cannot be opened with File.Open FileLoggingProvider cannot work, and moving opening the file in the background will not change this fact (at least, for now you can handle this situation).

If a log file is not locked (opened for write by another programs, and .NET app has only 1 running instance) I don't see what in the current implementation is incorrect and can cause a file lock inside FileLoggingProvider (as it implements Dispose and closes the file on shutdown). Even if .NET app is crushed (= Dispose is not called), in theory OS should release all its file handles -- but on Windows this is not always true, unfortunately.

Just to say, FileLoggingProvider is used in my SaaS app for 5 years (!) and I never experienced any issues with MVC Core app start because of locked log file (however, hosting environment is Linux, not Windows). And I can access 'active' (opened for write) log file with SSH without any problems.

I'm not sure that I understand what is wrong with opened files (with .NET File.Open) on Windows, and therefore have no idea how to change FileLoggingProvider to deal with that. Your ideas are welcome!

BTW, it seems in NET6 FileStream was re-written, so maybe this issue disappear in NET6 apps (didn't checked that yet).

LeeReid1 commented 2 years ago

@VitaliyMF thanks for the response.

I wonder if the launch process itself has not yet released the file before the asp.net app tries to gain write access to it. As in, Azure or VS build have copied some files into a new location upon restart and haven't yet released the file. It doesn't explain everything but I'm not seeing much in your code that could cause an issue.

How would you feel if I were to shuffle things so that it trys to open the file and, failing that, moves onto the next one (assuming maxrollingfiles>1). It's not exactly a solution but it might make it slightly more robust to temporary issues.

LeeReid1 commented 2 years ago

@bairog The issue is that what is opening the file needs to have FileShare.ReadWrite (as suggested by @zoran-petrovic-87). This will allow the file to be written to while you are reading it. The docs description is a tad misleading on this but essentially if the file is already open for writing, and you're only willing to share with others reading it when you try to open it, you come off second best. Note that FileShare.Read seems to be the default in .NET 5 if you're not explicit.

Why I end up with the file not even readable by the likes of Notepad still is a mystery to me.

There's a unit test in the above pull request that confirms that with FileShare.ReadWrite you can read the file while it is open.

bairog commented 2 years ago

@bairog The issue is that what is opening the file needs to have FileShare.ReadWrite (as suggested by @zoran-petrovic-87). This will allow the file to be written to while you are reading it.

Thank you, It's working now.

TeamPolisadministratieEnAdviseur commented 1 year ago

Same issue for me; but my setup is a bit more complex since I have two background processes which log:

Every time I put a message on de queue the message handler is activated and I get the exception shown below. Since I remove the file before starting I suspect logging system is blocking it self. A quick test shows that using FileShare.ReadWrite when opening the file will probably fix this. But I am not sure this is the right fix since the logging system could/should probably use the exiting stream.

System.IO.IOException HResult=0x80070020 Message=The process cannot access the file 'C:\logdata\pbipublisher\PbiPublisher_2023-05-05.log' because it is being used by another process. Source=System.Private.CoreLib StackTrace: at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options) at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable1 unixCreateMode) at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable1 unixCreateMode) at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable1 unixCreateMode) at System.IO.FileStream..ctor(String path, FileMode mode) at Program.<>c.<<Main>$>b__0_7(FileError x) in C:\git\atlas-pbipublisher-backend\Voogd.PbiPublisher.DomainService\Program.cs:line 49 at NReco.Logging.File.FileLoggerProvider.FileWriter.OpenFile(Boolean append) at NReco.Logging.File.FileLoggerProvider.FileWriter..ctor(FileLoggerProvider fileLogPrv) at NReco.Logging.File.FileLoggerProvider..ctor(String fileName, FileLoggerOptions options) at Microsoft.Extensions.Logging.FileLoggerExtensions.<>c__DisplayClass1_0.<AddFile>b__0(IServiceProvider srvPrv) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType) at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func2 valueFactory) at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider) at Microsoft.EntityFrameworkCore.Diagnostics.Internal.ScopedLoggerFactory.Create(IServiceProvider internalServiceProvider, IDbContextOptions contextOptions) at Microsoft.EntityFrameworkCore.Internal.ServiceProviderCache.<GetOrAdd>g__BuildServiceProvider|4_1(IDbContextOptions _, ValueTuple2 arguments) at Microsoft.EntityFrameworkCore.Internal.ServiceProviderCache.<>c.b4_0(IDbContextOptions contextOptions, ValueTuple2 tuples) at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd[TArg](TKey key, Func3 valueFactory, TArg factoryArgument) at Microsoft.EntityFrameworkCore.Internal.ServiceProviderCache.GetOrAdd(IDbContextOptions options, Boolean providerRequired) at Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions options) at Voogd.PbiPublisher.Infrastructure.Database.Models.ViaContext..ctor(DbContextOptions1 options) in C:\git\atlas-pbipublisher-backend\Voogd.PbiPublisher.Infrastructure.Database\Models\ViaContext.cs:line 12 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void* arguments, Signature sig, Boolean isConstructor) at System.Reflection.ConstructorInvoker.Invoke(Object obj, IntPtr args, BindingFlags invokeAttr) at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.b0(ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider) at MassTransit.DependencyInjection.ConsumeScopeProvider.CreatedScopeContextFactory[TConsumer,T](ConsumeContext1 consumeContext, IServiceScope serviceScope, IDisposable disposable) at MassTransit.DependencyInjection.BaseConsumeScopeProvider.GetScopeContext[TScopeContext,TPipeContext](TPipeContext context, Func4 existingScopeContextFactory, Func4 createdScopeContextFactory, Func4 pipeContextFactory)

VitaliyMF commented 1 year ago

@TeamPolisadministratieEnAdviseur

but my setup is a bit more complex since I have two background processes which log:

If these 2 background processes are 2 separate .NET apps then each one should use its own log file, 2 processes cannot write to the same log file.

TeamPolisadministratieEnAdviseur commented 1 year ago

It is a single app with the following in startup:

services.AddMassTransit services.AddHostedService

I've tested with a modified version of nreco logging with FileShare.ReadWrite added, and this solves the exception.

VitaliyMF commented 1 year ago

services.AddMassTransit services.AddHostedService

then you need to check why 2 instances of FileLoggerProvider are created in your application to determine why log file is already opened (by another FileLoggerProvider instance) when you get "The process cannot access the file .... because it is being used by another process."

I've tested with a modified version of nreco logging with FileShare.ReadWrite added, and this solves the exception.

FileLoggerProvider is not designed for concurrent writes to the same log file; it opens a file once and closes it only when app is about to shutdown. "ReadWrite" option will not help in fact as you can get a mess of writes from 2 (or more) concurrent FileLoggerProvider instances that try to write to a same file.

LeeReid1 commented 1 year ago

It is standard for two web apps to run simultaneously in a variety of scenarios. For example, in Azure restarting a web app will begin the second app before shutting down the first to ensure no down time. This happens multiple times per day automatically and this cannot be turned off. It also occurs every time you push code. Given that most people running Web apps do so in modern hosting environments and there seems to be no intention to support these environments, perhaps it would be helpful to be clear to state this in the readme?

I similarly don't suggest shared readwrite because it can lead to corrupted log entries.

On Fri, 5 May 2023, at 01:42, Vitaliy Fedorchenko wrote:

services.AddMassTransit services.AddHostedService

then you need to check why 2 instances of FileLoggerProvider are created in your application to determine why log file is already opened (by another FileLoggerProvider instance) when you get "The process cannot access the file .... because it is being used by another process."

I've tested with a modified version of nreco logging with FileShare.ReadWrite added, and this solves the exception.

FileLoggerProvider is not designed for concurrent writes to the same log file; it opens a file once and closes it only when app is about to shutdown. "ReadWrite" option will not help in fact as you can get a mess of writes from 2 (or more) concurrent FileLoggerProvider instances that try to write to a same file.

— Reply to this email directly, view it on GitHub https://github.com/nreco/logging/issues/28#issuecomment-1535926902, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGN7MFCCDLK4XD672I6MA7LXES4P5ANCNFSM5ERLRG2Q. You are receiving this because you were mentioned.Message ID: @.***>

VitaliyMF commented 1 year ago

It is standard for two web apps to run simultaneously in a variety of scenarios

No problems with that, however each app's instance needs to use its own log file. You have full control over that:

lmoelleb commented 1 year ago

If hosting on Azure Microsoft.Extensions.Logging.AzureAppServices might be a better choice than logfiles. Or if you have a more complicated setup consider a stack for log aggregation - for example through OpenTelemetry as Microsoft builds that into the framework these days - though that one is taking forever to get the standard finalized for logging.

LeeReid1 commented 1 year ago

Yep, that's exactly what I personally went for when my proposed solution was pushed back on a while back. Can confirm that using the built-in / MS stuff works just fine. I was just trying here to help other community members avoid headaches by suggesting the repo is either fixed or its limits are clearly labelled. IMO the worst case scenario for an error logger should be to not report anything, rather than take down an app in production.

On Fri, 5 May 2023, at 07:43, Lars Møllebjerg wrote:

If hosting on Azure Microsoft.Extensions.Logging.AzureAppServices might be a better choice than logfiles. Or if you have a more complicated setup consider a stack for log aggregation - for example through OpenTelemetry as Microsoft builds that into the framework these days - though that one is taking forever to get the standard finalized for logging.

— Reply to this email directly, view it on GitHub https://github.com/nreco/logging/issues/28#issuecomment-1536368253, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGN7MFBNYL6LSNRGUXGQTL3XEUG2BANCNFSM5ERLRG2Q. You are receiving this because you were mentioned.Message ID: @.***>

VitaliyMF commented 1 year ago

@LeeReid1

IMO the worst case scenario for an error logger should be to not report anything, rather than take down an app in production.

How app's developer will know that something is wrong with file logging? How to get more details about the error? I think that default silent 'try...catch..do-nothing' is no good and bad practice in general.

To avoid app's shutdown because of log file access error you can define your error handler (see https://github.com/nreco/logging#file-errors-handling). I don't see any headache in this regard: app explicitly defines what to do if app's log file is not accessible.

TeamPolisadministratieEnAdviseur commented 1 year ago

Since we're migrating our logging from file to application-insights (azure), I just removed file logging completely. Funny thing is though: the exception message that the file is locked is written into the locked file it self.