public void Dispose() { if (_logStream == null && _logWriter == null) { // Already disposed. return; } // If this sink is already disposed, then TryLogInfo(..) will fail to aquire the _logGroupMutex and will gracefully return false. this.TryLogInfo(SelfLogSourceInfo.WithCallInfo().WithAssemblyName(), "Finishing logging session", new object[] { "LogSessionId", LogSessionId }); // If we can acquire the file mutex, we will dispose while holding it, so that concurrent log writes are not affected. // But eventually we will dispose regardless. bool hasMutex = _logGroupMutex.TryAcquire(out LogGroupMutex.Handle logGroupMutexHandle); try { SafeDisposeAndSetToNull(ref _logWriter); SafeDisposeAndSetToNull(ref _logStream); } finally { if (hasMutex) { logGroupMutexHandle.Dispose(); } } _logGroupMutex.Dispose(); }
/// <summary> /// Attention: All loggers from all processes that write to the same <c>logFileNameBase</c> MUST use the same value for <c>rotateLogFileWhenLargerBytes</c>! /// </summary> public static bool TryCreateNew( string logFileDir, string logFileNameBase, Guid logGroupId, int rotateLogFileWhenLargerBytes, DefaultFormat.Options formatOptions, out FileLogSink newSink) { // Bad usage - throw. if (logFileNameBase == null) { throw new ArgumentNullException(nameof(logFileNameBase)); } if (String.IsNullOrWhiteSpace(logFileNameBase)) { throw new ArgumentException($"{nameof(logFileNameBase)} may not be white-space only.", nameof(logFileNameBase)); } // Ok usage, but bad state - do not throw and return false. newSink = null; if (String.IsNullOrWhiteSpace(logFileDir)) { return(false); } // Normalize in respect to final dir separator: logFileDir = Path.GetDirectoryName(Path.Combine(logFileDir, ".")); // Ensure the directory exists: if (!EnsureDirectoryExists(logFileDir, out DirectoryInfo logFileDirInfo)) { return(false); } LogGroupMutex logGroupMutex = null; try { logGroupMutex = new LogGroupMutex(logGroupId); if (!logGroupMutex.TryAcquire(out LogGroupMutex.Handle logGroupMutexHandle)) { logGroupMutex.Dispose(); return(false); } using (logGroupMutexHandle) { DateTimeOffset now = DateTimeOffset.Now; int rotationIndex = FindLatestRotationIndex(logFileDirInfo, logFileNameBase, now); string logFileName = ConstructFilename(logFileNameBase, now, rotationIndex); string logFilePath = Path.Combine(logFileDir, logFileName); FileStream logStream = new FileStream(logFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); newSink = new FileLogSink(logGroupMutex, logFileDir, logFileNameBase, rotateLogFileWhenLargerBytes, logStream, rotationIndex, formatOptions); } if (newSink.TryLogInfo( SelfLogSourceInfo.WithCallInfo().WithAssemblyName(), "Logging session started", new object[] { "LogGroupId", newSink.LogGroupId, "LogSessionId", newSink.LogSessionId, "RotateLogFileWhenLargerBytes", newSink.RotateLogFileWhenLargerBytes })) { return(true); } } catch { } // If we did not succeed, the sink may be still constructed (e.g. TryLogInfo(..) returned false). // We need to dispose the sink before giving up, but be brepaed for it to sbe null. try { if (newSink != null) { newSink.Dispose(); // This will also dispose the logGroupMutex owned by the newSink. } else { logGroupMutex.Dispose(); } } catch { } newSink = null; return(false); }