Ejemplo n.º 1
0
        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);
            }
        }
Ejemplo n.º 2
0
 /// <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));
 }
Ejemplo n.º 3
0
 /// <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);
 }
Ejemplo n.º 4
0
        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);
            }
        }
Ejemplo n.º 5
0
 /// <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);
 }
Ejemplo n.º 6
0
 /// <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));
 }
Ejemplo n.º 7
0
 /// <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);
 }
Ejemplo n.º 8
0
 /// <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);
 }
Ejemplo n.º 9
0
 /// <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;
 }
Ejemplo n.º 10
0
        /// <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);
        }
Ejemplo n.º 11
0
        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);
            }
        }
Ejemplo n.º 12
0
        /// <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);
        }
Ejemplo n.º 13
0
        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));
        }
Ejemplo n.º 14
0
        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();
                }
            }
Ejemplo n.º 16
0
 /// <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);
 }
Ejemplo n.º 17
0
        /// <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;
            }
        }
Ejemplo n.º 18
0
 /// <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);
        }