private void OpenOrCreate_NewFile(LogFilePurpose purpose, LogFileWriteMode writeMode) { string backingFilePath = Path.Combine(Environment.CurrentDirectory, "FileBackedLogMessageCollectionBuffer.gplog"); // delete the file to work with to ensure that the collection creates a new one File.Delete(backingFilePath); Assert.False(File.Exists(backingFilePath)); try { using (var collection = FileBackedLogMessageCollection.OpenOrCreate(backingFilePath, purpose, writeMode)) { Assert.True(File.Exists(backingFilePath)); Assert.Equal(backingFilePath, collection.FilePath); TestCollectionPropertyDefaults(collection, 0, false); } // the file should persist after disposing the collection Assert.True(File.Exists(backingFilePath)); } finally { File.Delete(backingFilePath); } }
/// <summary> /// Opens an existing log file in read/write mode, creates a new log file, if the file does not exist, yet. /// </summary> /// <param name="path">Log file to open/create.</param> /// <param name="purpose"> /// Purpose of the log file determining whether the log file is primarily used for recording or for analysis /// (does not have any effect, if the log file exists already). /// </param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <exception cref="LogFileException">Opening the log file failed (see message and inner exception for details).</exception> public static LogFile OpenOrCreate( string path, LogFilePurpose purpose, LogFileWriteMode writeMode) { return(new LogFile(path, purpose, writeMode)); }
/// <summary> /// Creates a <see cref="FileBackedLogMessageCollection"/> backed by the specified log file. /// The log file is created, if it does not exist, yet. /// </summary> /// <param name="path">Path of the log file to open/create.</param> /// <param name="purpose"> /// Purpose of the log file determining whether the log file is primarily used for recording or for analysis /// (does not have any effect, if the log file exists already). /// </param> /// <param name="mode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <exception cref="LogFileException">Opening the log file failed (see message and inner exception for details).</exception> public static FileBackedLogMessageCollection OpenOrCreate( string path, LogFilePurpose purpose, LogFileWriteMode mode) { return(LogFile.OpenOrCreate(path, purpose, mode).Messages); }
private void OpenReadOnly(LogFilePurpose purpose, LogFileWriteMode writeMode) { string path = purpose == LogFilePurpose.Recording ? Fixture.GetCopyOfFile_Recording_RandomMessages_10K() : Fixture.GetCopyOfFile_Analysis_RandomMessages_10K(); try { Assert.True(File.Exists(path)); using (var collection = FileBackedLogMessageCollection.OpenReadOnly(path)) { Assert.True(File.Exists(path)); Assert.Equal(path, collection.FilePath); TestCollectionPropertyDefaults(collection, 10000, true); } // the file should persist after disposing the collection Assert.True(File.Exists(path)); } finally { // remove temporary log file to avoid polluting the output directory File.Delete(path); } }
/// <summary> /// Creates a new log file for reading and writing and populates it with the specified message set. /// Throws an exception, if the file exists already. /// </summary> /// <param name="path">Log file to open/create.</param> /// <param name="purpose"> /// Purpose of the log file determining whether the log file is primarily used for recording or for analysis /// (does not have any effect, if the log file exists already). /// </param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <exception cref="LogFileException">Opening the log file failed (see message and inner exception for details).</exception> private LogFile( string path, LogFilePurpose purpose, LogFileWriteMode writeMode) : this(path, true, false, purpose, writeMode, false, null, null) { mMessageCollection = new FileBackedLogMessageCollection(this); }
/// <summary> /// Creates a new log file and populates it with the specified log messages. /// </summary> /// <param name="path">Log file to create.</param> /// <param name="purpose">Purpose of the log file determining whether the log file is primarily used for recording or for analysis.</param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <param name="messages">Messages to populate the new log file with (may be null).</param> /// <exception cref="LogFileException">Creating the log file failed (see message and inner exception for details).</exception> public static LogFile Create( string path, LogFilePurpose purpose, LogFileWriteMode writeMode, IEnumerable <ILogMessage> messages = null) { return(new LogFile(path, purpose, writeMode, messages)); }
/// <summary> /// Creates a <see cref="FileBackedLogMessageCollection"/> backed by the specified log file and populates it with the specified messages. /// The log file must not exist, yet. /// </summary> /// <param name="path">Path of the log file to create.</param> /// <param name="purpose">Purpose of the log file determining whether the log file is primarily used for recording or for analysis.</param> /// <param name="mode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <param name="messages">Messages to populate the log file with (may be null).</param> /// <exception cref="LogFileException">Creating the log file failed (see message and inner exception for details).</exception> public static FileBackedLogMessageCollection Create( string path, LogFilePurpose purpose, LogFileWriteMode mode, IEnumerable <ILogMessage> messages = null) { return(LogFile.Create(path, purpose, mode, messages).Messages); }
/// <summary> /// Creates a new log file. /// </summary> /// <param name="path">Log file to create.</param> /// <param name="purpose">Purpose of the log file determining whether the log file is primarily used for recording or for analysis.</param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <param name="messages">Messages to populate the log file with.</param> /// <exception cref="LogFileException">Opening the log file failed (see message and inner exception for details).</exception> private LogFile( string path, LogFilePurpose purpose, LogFileWriteMode writeMode, IEnumerable <ILogMessage> messages) : this(path, true, true, purpose, writeMode, false, null, messages) { mMessageCollection = new FileBackedLogMessageCollection(this); }
/// <summary> /// Initializes an instance of the <see cref="FileBackedLogMessageCollectionTests_Base"/> class. /// </summary> /// <param name="fixture">Fixture providing static test data.</param> /// <param name="useReadOnlyCollection">Indicates whether the collection used for the test is read-only or not.</param> /// <param name="purpose">The log file purpose to test.</param> /// <param name="writeMode">The log file write mode to test.</param> protected SelectableFileBackedLogMessageFilterTests_Base( LogFileTestsFixture fixture, bool useReadOnlyCollection, LogFilePurpose purpose, LogFileWriteMode writeMode) { Fixture = fixture; LogFilePurposeToTest = purpose; LogFileWriteModeToTest = writeMode; CollectionIsReadOnly = useReadOnlyCollection; }
/// <summary> /// Creates a new instance of the <see cref="FileBackedLogMessageCollection"/> with a file in the temporary directory /// optionally marking the file for auto-deletion. /// </summary> /// <param name="deleteAutomatically"> /// true to delete the file automatically when the collection is disposed (or the next time, a temporary collection is created in the same directory); /// false to keep it after the collection is disposed. /// </param> /// <param name="temporaryDirectoryPath"> /// Path of the temporary directory to use; /// null to use the default temporary directory (default). /// </param> /// <param name="purpose"> /// Purpose of the log file determining whether the log file is primarily used for recording or for analysis (default). /// </param> /// <param name="mode"> /// Write mode determining whether to open the log file in 'robust' or 'fast' mode (default). /// </param> /// <param name="messages">Messages to populate the temporary collection with (may be null).</param> /// <returns>The created collection.</returns> public static FileBackedLogMessageCollection CreateTemporaryCollection( bool deleteAutomatically, string temporaryDirectoryPath = null, LogFilePurpose purpose = LogFilePurpose.Analysis, LogFileWriteMode mode = LogFileWriteMode.Fast, IEnumerable <ILogMessage> messages = null) { string path = TemporaryFileManager.GetTemporaryFileName(deleteAutomatically, temporaryDirectoryPath); var file = LogFile.Create(path, purpose, mode, messages); file.Messages.AutoDelete = deleteAutomatically; return(file.Messages); }
private void Create_ExistingFile(LogFilePurpose purpose, LogFileWriteMode writeMode, bool populate) { string backingFilePath = purpose == LogFilePurpose.Recording ? Fixture.GetCopyOfFile_Recording_RandomMessages_10K() : Fixture.GetCopyOfFile_Analysis_RandomMessages_10K(); var messages = populate ? Fixture.GetLogMessages_Random_10K() : null; try { Assert.Throws <LogFileException>(() => FileBackedLogMessageCollection.Create(backingFilePath, purpose, writeMode, messages)); } finally { // remove temporary log file to avoid polluting the output directory File.Delete(backingFilePath); } }
/// <summary> /// Creates a new instance of the collection class to test, pre-populated with the specified number of random log messages. /// The collection should be disposed at the end to avoid generating orphaned log files. /// </summary> /// <param name="count">Number of random log messages the collection should contain.</param> /// <param name="purpose">Purpose of the log file backing the collection.</param> /// <param name="writeMode">Write mode of the log file backing the collection.</param> /// <param name="isReadOnly"><c>true</c> to create a read-only log file; otherwise <c>false</c>.</param> /// <param name="messages">Receives messages that have been put into the collection.</param> /// <returns>A new instance of the collection class to test.</returns> private static FileBackedLogMessageCollection CreateCollection( int count, LogFilePurpose purpose, LogFileWriteMode writeMode, bool isReadOnly, out LogMessage[] messages) { string path = Guid.NewGuid().ToString("D") + ".gplog"; // create a collection backed by a new file using (var file1 = LogFile.OpenOrCreate(path, purpose, writeMode)) { // generate the required number of log message and add them to the collection var fileLogMessages = LoggingTestHelpers.GetTestMessages <LogFileMessage>(count); for (long i = 0; i < fileLogMessages.Length; i++) { fileLogMessages[i].Id = i; } messages = fileLogMessages.Cast <LogMessage>().ToArray(); if (count > 0) { file1.Write(messages); } } // open the created log file again as expected for the test var file2 = isReadOnly ? LogFile.OpenReadOnly(path) : LogFile.Open(path, writeMode); // let the collection delete the log file on its disposal file2.Messages.AutoDelete = true; // the collection should now contain the messages written into it // (the file-backed collection assigns message ids on its own, but they should be the same as the ids assigned to the test set) Assert.Equal(messages, file2.Messages.ToArray()); // the test assumes that the collection uses single-item notifications file2.Messages.UseMultiItemNotifications = false; return(file2.Messages); }
private void CreateTemporaryCollection( string temporaryDirectoryPath, bool deleteAutomatically, LogFilePurpose purpose, LogFileWriteMode mode) { string effectiveTemporaryFolderPath = temporaryDirectoryPath ?? Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar); string backingFilePath; using (var collection = FileBackedLogMessageCollection.CreateTemporaryCollection(deleteAutomatically, temporaryDirectoryPath, purpose, mode)) { Assert.True(File.Exists(collection.FilePath)); Assert.Equal(effectiveTemporaryFolderPath, Path.GetDirectoryName(collection.FilePath)); TestCollectionPropertyDefaults(collection, 0, false); backingFilePath = collection.FilePath; } // the file should not persist after disposing the collection, if auto-deletion is enabled Assert.Equal(deleteAutomatically, !File.Exists(backingFilePath)); }
private void Create_NewFile(LogFilePurpose purpose, LogFileWriteMode writeMode, bool populate) { string backingFilePath = Path.Combine(Environment.CurrentDirectory, "FileBackedLogMessageCollectionBuffer.gplog"); // delete the file to work with to ensure that the collection creates a new one File.Delete(backingFilePath); Assert.False(File.Exists(backingFilePath)); try { var messages = populate ? Fixture.GetLogMessages_Random_10K() : null; using (var collection = FileBackedLogMessageCollection.Create(backingFilePath, purpose, writeMode, messages)) { Assert.True(File.Exists(backingFilePath)); Assert.Equal(backingFilePath, collection.FilePath); TestCollectionPropertyDefaults(collection, populate ? messages.Length : 0, false); if (populate) { Assert.Equal(messages, collection); Assert.Equal(messages, collection.LogFile.Read(0, messages.Length + 1)); } else { Assert.Empty(collection); Assert.Equal(0, collection.LogFile.MessageCount); } } // the file should persist after disposing the collection Assert.True(File.Exists(backingFilePath)); } finally { File.Delete(backingFilePath); } }
/// <summary> /// Initializes a new instance of the <see cref="AnalysisDatabaseAccessor"/> class. /// </summary> /// <param name="connection">Database connection to use.</param> /// <param name="writeMode">Write mode that determines whether the database should be operating in robust mode or as fast as possible.</param> /// <param name="isReadOnly"> /// true, if the log file is opened in read-only mode; /// false, if the log file is opened in read/write mode. /// </param> /// <param name="create"> /// true to create the database; /// false to just use it. /// </param> /// <param name="messages">Messages to populate the file with (works for new files only).</param> public AnalysisDatabaseAccessor( SQLiteConnection connection, LogFileWriteMode writeMode, bool isReadOnly, bool create, IEnumerable <ILogMessage> messages = null) : base(connection, writeMode, isReadOnly) { // commands to get the lowest and the highest message id mGetOldestMessageIdCommand = PrepareCommand("SELECT id FROM messages ORDER BY id ASC LIMIT 1;"); mGetNewestMessageIdCommand = PrepareCommand("SELECT id FROM messages ORDER BY id DESC LIMIT 1;"); // command to get names of referenced processes, applications, log writers, log levels and tags in ascending order mSelectUsedProcessNamesCommand = PrepareCommand( "SELECT DISTINCT name" + " FROM processes" + " INNER JOIN messages ON messages.process_name_id = processes.id" + " ORDER BY name ASC;"); mSelectUsedProcessIdsCommand = PrepareCommand("SELECT DISTINCT process_id FROM messages ORDER BY process_id ASC;"); mSelectUsedApplicationNamesCommand = PrepareCommand( "SELECT DISTINCT name" + " FROM applications" + " INNER JOIN messages ON messages.application_name_id = applications.id" + " ORDER BY name ASC;"); mSelectUsedLogWriterNamesCommand = PrepareCommand( "SELECT DISTINCT name" + " FROM writers" + " INNER JOIN messages ON messages.writer_name_id = writers.id" + " ORDER BY name ASC;"); mSelectUsedLogLevelNamesCommand = PrepareCommand( "SELECT DISTINCT name" + " FROM levels" + " INNER JOIN messages ON messages.level_name_id = levels.id" + " ORDER BY name ASC;"); mSelectUsedTagsCommand = PrepareCommand( "SELECT DISTINCT name" + " FROM tags" + " INNER JOIN tag2msg ON tag2msg.tag_id = tags.id" + " INNER JOIN messages ON messages.id = tag2msg.message_id" + " ORDER BY name ASC;"); // command to add a log message metadata record (everything, but the actual message text) mInsertMessageCommand = PrepareCommand( "INSERT INTO messages (id, timestamp, timezone_offset, high_precision_timestamp, lost_message_count, process_id, process_name_id, application_name_id, writer_name_id, level_name_id, has_tags)" + " VALUES (@id, @timestamp, @timezone_offset, @high_precision_timestamp, @lost_message_count, @process_id, @process_name_id, @application_name_id, @writer_name_id, @level_name_id, @has_tags);"); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_IdParameter = new SQLiteParameter("@id", DbType.Int64)); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_TimestampParameter = new SQLiteParameter("@timestamp", DbType.Int64)); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_TimezoneOffsetParameter = new SQLiteParameter("@timezone_offset", DbType.Int64)); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_HighPrecisionTimestampParameter = new SQLiteParameter("@high_precision_timestamp", DbType.Int64)); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_LostMessageCountParameter = new SQLiteParameter("@lost_message_count", DbType.Int32)); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_ProcessIdParameter = new SQLiteParameter("@process_id", DbType.Int32)); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_ProcessNameIdParameter = new SQLiteParameter("@process_name_id", DbType.Int64)); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_ApplicationNameIdParameter = new SQLiteParameter("@application_name_id", DbType.Int64)); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_WriterNameIdParameter = new SQLiteParameter("@writer_name_id", DbType.Int64)); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_LevelNameIdParameter = new SQLiteParameter("@level_name_id", DbType.Int64)); mInsertMessageCommand.Parameters.Add(mInsertMessageCommand_HasTagsParameter = new SQLiteParameter("@has_tags", DbType.Boolean)); // command to add the text of a log message mInsertTextCommand = PrepareCommand("INSERT INTO texts (id, text) VALUES (@id, @text);"); mInsertTextCommand.Parameters.Add(mInsertTextCommand_IdParameter = new SQLiteParameter("@id", DbType.Int64)); mInsertTextCommand.Parameters.Add(mInsertTextCommand_TextParameter = new SQLiteParameter("@text", DbType.String)); // query to get the id of the first message that is next a specific point in time mSelectMessageIdByTimestampForDeleteMessagesCommand = PrepareCommand("SELECT id FROM messages WHERE timestamp < @timestamp ORDER BY timestamp DESC LIMIT 1;"); mSelectMessageIdByTimestampForDeleteMessagesCommand.Parameters.Add(mSelectMessageIdByTimestampForDeleteMessagesCommand_TimestampParameter = new SQLiteParameter("@timestamp", DbType.Int64)); // command to delete all message metadata up to the specified id (incl. the specified id) mDeleteMessagesUpToIdCommand = PrepareCommand("DELETE FROM messages WHERE id <= @id;"); mDeleteMessagesUpToIdCommand.Parameters.Add(mDeleteMessagesUpToIdCommand_IdParameter = new SQLiteParameter("@id", DbType.Int64)); // command to delete all message texts up to the specified id (incl. the specified id) mDeleteTextsUpToIdCommand = PrepareCommand("DELETE FROM texts WHERE id <= @id;"); mDeleteTextsUpToIdCommand.Parameters.Add(mDeleteTextsUpToIdCommand_IdParameter = new SQLiteParameter("@id", DbType.Int64)); // query to get a number of log messages starting at a specific log message id mSelectContinuousMessagesCommand = PrepareCommand( "SELECT m.id, timestamp, m.timezone_offset, m.high_precision_timestamp, m.lost_message_count, m.process_id, p.name, a.name, w.name, l.name, m.has_tags, t.text" + " FROM messages as m" + " INNER JOIN processes as p ON p.id = m.process_name_id" + " INNER JOIN applications as a ON a.id = m.application_name_id" + " INNER JOIN writers as w ON w.id = m.writer_name_id" + " INNER JOIN levels as l ON l.id = m.level_name_id" + " INNER JOIN texts as t ON t.id = m.id" + " WHERE m.id >= @from_id" + " ORDER BY m.id ASC" + " LIMIT @count;"); mSelectContinuousMessagesCommand.Parameters.Add(mSelectContinuousMessagesCommand_FromIdParameter = new SQLiteParameter("@from_id", DbType.Int64)); mSelectContinuousMessagesCommand.Parameters.Add(mSelectContinuousMessagesCommand_CountParameter = new SQLiteParameter("@count", DbType.Int64)); // create database tables and indices, if requested if (create) { // create structure first ExecuteNonQueryCommands(CreateDatabaseCommands_CommonStructure); ExecuteNonQueryCommands(sCreateDatabaseCommands_SpecificStructure); // retrieve the ids of the oldest and newest message OldestMessageId = GetOldestMessageId(); NewestMessageId = GetNewestMessageId(); // populate the database with messages if (messages != null) { Write(messages); } // create indices at last (is much faster than updating indices when inserting) ExecuteNonQueryCommands(CreateDatabaseCommands_CommonIndices); ExecuteNonQueryCommands(sCreateDatabaseCommands_SpecificIndices); } else { // retrieve the ids of the oldest and newest message OldestMessageId = GetOldestMessageId(); NewestMessageId = GetNewestMessageId(); } }
/// <summary> /// Creates a <see cref="FileBackedLogMessageCollection"/> backed by an existing log file. /// The log file is opened for reading and writing. /// </summary> /// <param name="path">Path of the log file to open.</param> /// <param name="mode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <exception cref="FileNotFoundException">The specified file does not exist.</exception> /// <exception cref="LogFileException">Opening the log file failed (see message and inner exception for details).</exception> public static FileBackedLogMessageCollection Open(string path, LogFileWriteMode mode) { return(LogFile.Open(path, mode).Messages); }
/// <summary> /// Constructor providing functionality common to other constructors (for internal use only). /// </summary> /// <param name="path">Log file to open/create.</param> /// <param name="createIfNotExist"> /// true to create the specified log file, if it does not exist, yet; /// false to throw an exception, if the file does not exist. /// </param> /// <param name="fileMustNotExist"> /// <c>true</c> if the specified file must not exist; otherwise <c>false</c>. /// </param> /// <param name="purpose">Purpose of the log file determining whether the log file is primarily used for recording or for analysis.</param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <param name="isReadOnly"> /// true to open the log file in read-only mode; /// false to open the log file in read/write mode. /// </param> /// <param name="collection">Collection that works upon the log file.</param> /// <param name="messages">Messages to put into the log file (should only be used for new files).</param> /// <exception cref="FileNotFoundException"><paramref name="createIfNotExist"/> is <c>false</c> and the specified file does not exist.</exception> /// <exception cref="LogFileException">Opening/Creating the log file failed.</exception> internal LogFile( string path, bool createIfNotExist, bool fileMustNotExist, LogFilePurpose purpose, LogFileWriteMode writeMode, bool isReadOnly, FileBackedLogMessageCollection collection, IEnumerable <ILogMessage> messages) { if (path == null) { throw new ArgumentNullException(nameof(path)); } // initialize information about the operating mode mFilePath = Path.GetFullPath(path); mMessageCollection = collection; // check whether the log file exists already bool fileExists = File.Exists(mFilePath); // abort, if the file does not exist and creating a new file is not allowed if (!fileExists && !createIfNotExist) { throw new FileNotFoundException($"Log file ({path}) does not exist."); } // abort, if the file exists, but the caller expects it does not if (fileExists && fileMustNotExist) { throw new LogFileException("Log file ({path}) exists already, but it should not."); } // abort, if the file exists, but an initial message set is specified (internal error) if (fileExists && messages != null) { throw new InvalidOperationException("Log file ({path}) exists already, but it should not as an initial message set is specified."); } SQLiteConnection connection = null; try { // open database file (creates a new one, if it does not exist) connection = new SQLiteConnection($"Data Source={mFilePath};Version=3;Read Only={isReadOnly}"); connection.Open(); // open/create the database if (fileExists) { // check application id ulong applicationId = DatabaseAccessor.GetApplicationId(connection); if (applicationId != DatabaseAccessor.LogFileApplicationId) { throw new InvalidLogFileFormatException($"Application id in the sqlite database is 0x{applicationId:08x}, expecting not 0x{DatabaseAccessor.LogFileApplicationId:08x}"); } // check user version // (indicates its purpose, directly corresponds to the database schema) ulong userVersion = DatabaseAccessor.GetSchemaVersion(connection); switch (userVersion) { case 1: mDatabaseAccessor = new RecordingDatabaseAccessor(connection, writeMode, isReadOnly, false); break; case 2: mDatabaseAccessor = new AnalysisDatabaseAccessor(connection, writeMode, isReadOnly, false); break; default: throw new FileVersionNotSupportedException(); } } else { switch (purpose) { case LogFilePurpose.Recording: mDatabaseAccessor = new RecordingDatabaseAccessor(connection, writeMode, isReadOnly, true, messages); break; case LogFilePurpose.Analysis: mDatabaseAccessor = new AnalysisDatabaseAccessor(connection, writeMode, isReadOnly, true, messages); break; default: throw new NotSupportedException($"The specified purpose ({purpose}) is not supported."); } } } catch (SQLiteException ex) { Dispose(); connection?.Dispose(); throw new LogFileException( $"Opening/Creating the log file failed: {ex.Message}", ex); } catch (Exception) { Dispose(); connection?.Dispose(); throw; } }
/// <summary> /// Opens an existing log file for reading and writing. /// </summary> /// <param name="path">Log file to open.</param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <exception cref="FileNotFoundException">The specified file does not exist.</exception> /// <exception cref="LogFileException">Opening the log file failed (see message and inner exception for details).</exception> public static LogFile Open(string path, LogFileWriteMode writeMode) { return(new LogFile(path, writeMode)); }
private void CreateTemporaryCollection( string temporaryDirectoryPath, bool deleteAutomatically, LogFilePurpose purpose, LogFileWriteMode mode, bool populate) { string effectiveTemporaryFolderPath = temporaryDirectoryPath ?? Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar); string backingFilePath; var messages = populate ? mFixture.GetLogMessages_Random_10K() : null; using (var collection = FileBackedLogMessageCollection.CreateTemporaryCollection(deleteAutomatically, temporaryDirectoryPath, purpose, mode, messages)) { Assert.True(File.Exists(collection.FilePath)); Assert.Equal(effectiveTemporaryFolderPath, Path.GetDirectoryName(collection.FilePath)); using (var eventWatcher = collection.AttachEventWatcher()) { // check collection specific properties // --------------------------------------------------------------------------------------------------------------- Assert.Equal(20, collection.MaxCachePageCount); Assert.Equal(100, collection.CachePageCapacity); if (messages != null) { Assert.Equal(messages.Length, collection.Count); Assert.Equal(messages, collection); } else { Assert.Equal(0, collection.Count); Assert.Empty(collection); } // check log file specific properties // --------------------------------------------------------------------------------------------------------------- Assert.NotNull(collection.LogFile); Assert.NotNull(collection.FilePath); Assert.Equal(collection.LogFile.FilePath, collection.FilePath); // check properties exposed by IList implementation // --------------------------------------------------------------------------------------------------------------- { var list = (IList)collection; Assert.False(list.IsReadOnly); Assert.False(list.IsFixedSize); Assert.False(list.IsSynchronized); Assert.NotSame(collection, list.SyncRoot); // sync root must not be the same as the collection to avoid deadlocks if (messages != null) { Assert.Equal(messages.Length, list.Count); Assert.Equal(messages, list); } else { Assert.Equal(0, list.Count); Assert.Empty(collection); } } // check properties exposed by IList<T> implementation // --------------------------------------------------------------------------------------------------------------- { var list = (IList <LogMessage>)collection; Assert.False(list.IsReadOnly); if (messages != null) { Assert.Equal(messages.Length, list.Count); Assert.Equal(messages, list.Cast <LogFileMessage>()); } else { Assert.Equal(0, list.Count); Assert.Empty(collection); } } // no events should have been raised eventWatcher.CheckInvocations(); } backingFilePath = collection.FilePath; } // the file should not persist after disposing the collection, if auto-deletion is enabled Assert.Equal(deleteAutomatically, !File.Exists(backingFilePath)); // delete the file, if it still exists to avoid polluting the output directory File.Delete(backingFilePath); }