public static bool TryCreateNewFileLogSink(FilenameBaseInfo filenameBaseInfo, Guid logGroupId, string preferredLogFileDirectory, DefaultFormat.Options formatOptions, out FileLogSink newLogSink) { return(TryCreateNewFileLogSink(filenameBaseInfo, logGroupId, preferredLogFileDirectory, FileLogSink.RotateLogFileWhenLargerBytesDefault, formatOptions, out newLogSink)); }
private FileLogSink(LogGroupMutex logGroupMutex, string logFileDir, string logFileNameBase, int rotateLogFileWhenLargerBytes, FileStream logStream, int initialRotationIndex, DefaultFormat.Options formatOptions) { _logSessionId = Guid.NewGuid(); _logGroupMutex = logGroupMutex; _logFileDir = logFileDir; _logFileNameBase = logFileNameBase; _rotateLogFileWhenLargerBytes = (rotateLogFileWhenLargerBytes <= 0) ? -1 : rotateLogFileWhenLargerBytes; _logStream = logStream; _logWriter = new StreamWriter(logStream, LogTextEncoding); _rotationIndex = initialRotationIndex; _formatOptions = formatOptions ?? DefaultFormatOptions; }
/// <summary> /// Attention: All loggers from all processes that write to the same /// (<c>productFamily</c> - <c>product</c> - <c>componentGroup</c> - <c>processName</c>) /// MUST use the same value for <c>rotateLogFileWhenLargerBytes</c>! /// </summary> /// <param name="filenameBaseInfo">Info required to construct the base file name. /// Use the non-default (aka paramaterized) ctor to create valid <c>FilenameBaseInfo</c> instances.</param> /// <param name="logGroupId">A unique ID for all loggers across all processes that write to the same file (or a set of rotating files). /// Used for inter-process synchronization.</param> /// <param name="preferredLogFileDirectory">Target folder for the log file. /// Specify <c>null</c> to use default.</param> /// <param name="rotateLogFileWhenLargerBytes">Log files will be rotated (new index used) when the file uses the specified size. /// Specify a nagative value to disable size-based file rotation. /// All loggers that write to the same file must use the same value for this parameter. /// Use <c>FileLogSink.RotateLogFileWhenLargerBytesDefault</c> as a default.</param> /// <param name="formatOptions">Formatting options for the log file. /// Specify <c>null</c> to use default.</param> /// <param name="newLogSink">OUT parameter containing the newly created <c>FileLogSink</c>.</param> /// <returns><c>True</c> is a new <c>FileLogSink</c> was created and initialized, <c>False</c> otherwise.</returns> public static bool TryCreateNewFileLogSink( FilenameBaseInfo filenameBaseInfo, Guid logGroupId, string preferredLogFileDirectory, int rotateLogFileWhenLargerBytes, DefaultFormat.Options formatOptions, out FileLogSink newLogSink) { FilenameBaseInfo.EnsureValidAsParam(filenameBaseInfo); // If user speficied a log file directory, we try to use it. If it fails we fry to fall back to defaults. if (!String.IsNullOrWhiteSpace(preferredLogFileDirectory)) { if (FileLogSink.TryCreateNew(preferredLogFileDirectory, filenameBaseInfo.LogFilenameBase, logGroupId, rotateLogFileWhenLargerBytes, formatOptions, out newLogSink)) { return(true); } } // If specified and accessible, use the Env Var for the log folder: { string userSetDdTraceLogDir = ReadEnvironmentVariable(DdTraceLogDirectoryEnvVarName); if (FileLogSink.TryCreateNew(userSetDdTraceLogDir, filenameBaseInfo.LogFilenameBase, logGroupId, rotateLogFileWhenLargerBytes, formatOptions, out newLogSink)) { return(true); } } // If accessible, use the default for the log folder: { string defaultProductFamilyLogDir; try { if (FileLogSink.IsWindowsFileSystem) { string commonAppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); defaultProductFamilyLogDir = Path.Combine( commonAppDataDir, WindowsDefaultLogDirectory, filenameBaseInfo.ProductFamily ?? FilenameMissingComponentFallback); } else { defaultProductFamilyLogDir = Path.Combine(NixDefaultLogDirectory, (filenameBaseInfo.ProductFamily ?? FilenameMissingComponentFallback).ToLower()); } } catch { defaultProductFamilyLogDir = null; } if (FileLogSink.TryCreateNew(defaultProductFamilyLogDir, filenameBaseInfo.LogFilenameBase, logGroupId, rotateLogFileWhenLargerBytes, formatOptions, out newLogSink)) { return(true); } } // If we could not use the above folders, try using the application folder, is accessible: { string appDir; try { appDir = Environment.CurrentDirectory; } catch { appDir = null; } if (FileLogSink.TryCreateNew(appDir, filenameBaseInfo.LogFilenameBase, logGroupId, rotateLogFileWhenLargerBytes, formatOptions, out newLogSink)) { return(true); } } // As last resort, we will try using the temp directory: { string tempDir; try { tempDir = Path.GetTempPath(); } catch { tempDir = null; } if (FileLogSink.TryCreateNew(tempDir, filenameBaseInfo.LogFilenameBase, logGroupId, rotateLogFileWhenLargerBytes, formatOptions, out newLogSink)) { return(true); } } // We could not write logs into any of the abofe folders. Give up. newLogSink = null; return(false); }
public static bool TryCreateNew(string logFileDir, string logFileNameBase, Guid logGroupId, DefaultFormat.Options formatOptions, out FileLogSink newSink) { return(TryCreateNew(logFileDir, logFileNameBase, logGroupId, FileLogSink.RotateLogFileWhenLargerBytesDefault, formatOptions, out newSink)); }
/// <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); }