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));
 }
Example #2
0
        /// <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);
        }
Example #3
0
 /// <summary>
 /// The name that will be constructed is:
 /// <c>DD-{ProductFamily}-{Product}-{ComponentGroup}-{ProcessName}-{Date}[_Index].log</c>
 /// </summary>
 /// <remarks>Specify an <c>index</c> smaller than zero to avoid including the index component.</remarks>
 public static string ConstructFilename(FilenameBaseInfo filenameBaseInfo, DateTimeOffset timestamp, int index)
 {
     FilenameBaseInfo.EnsureValidAsParam(filenameBaseInfo);
     return(FileLogSink.ConstructFilename(filenameBaseInfo.LogFilenameBase, timestamp, index));
 }
 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);
        }