// Copyright (c) 2012, Outercurve Foundation. // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // - Neither the name of the Outercurve Foundation nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using System; using System.IO; using System.Collections; using System.Collections.Specialized; using System.Diagnostics; using WebsitePanel.Server.Utils; namespace WebsitePanel.Providers.Utils.LogParser { /// /// Summary description for LogReader. /// public class LogReader { public static long TotalBytesProcessed = 0; public class FilesByCreationDateComparer : IComparer { public int Compare(object x, object y) { return DateTime.Compare(((FileInfo)x).CreationTime, ((FileInfo)y).CreationTime); } } private const string FIELDS_LINE = "#Fields: "; private const int FIELDS_LINE_LENGTH = 9; protected const char FIELDS_SEPARATOR = ' '; protected static readonly char[] FIELDS_SPLITTER = new char[] { FIELDS_SEPARATOR }; protected int fieldsLength; // initial log position private int fileIndex = -1; private long lineIndex = 0; private long lastLineIndex = 0; protected string line = null; // current log line protected bool errorLine = false; protected bool systemLine = false; private string logName = null; private long logDate = 0; private StreamReader reader; // log files in the log directory protected ArrayList logFiles = new ArrayList(); // fields available in the current log file private string[] fields = new string[0]; protected string[] fieldsValues = null; // field values of the current log line protected Hashtable record = new Hashtable(); public LogReader() { // nothing to do } public void Open(string logsPath) { // use this this.Open(logsPath, 0, 0); } public void Open(string logsPath, long lastAccessed, long line) { // save specified line lineIndex = line; // get logs directory DirectoryInfo logsDir = new DirectoryInfo(FileUtils.EvaluateSystemVariables(logsPath)); // get the list of files if (logsDir.Exists) GetDirectoryFiles(logsDir, logFiles); // sort files by date logFiles.Sort(new FilesByCreationDateComparer()); // try to find specified file if (lastAccessed != 0) { for (int i = 0; i < logFiles.Count; i++) { if (((FileInfo)logFiles[i]).CreationTime.Ticks == lastAccessed) { fileIndex = i; } } } // check whether specified file was found if (fileIndex == -1) { // no fileIndex = 0; lineIndex = 0; } } /// /// Checks whether requested fields are available against currently reading block with log data /// /// Fields names to be accessed /// Returns true if all of requested fields are available. Otherwise returns false. public bool CheckFieldsAvailable(string[] keyFields) { try { if (fields == null || fields.Length == 0) return false; // foreach (string keyField in keyFields) { // if (Array.IndexOf(fields, keyField) == -1) return false; } // } catch(Exception ex) { Log.WriteError(ex); } return true; } public bool Read() { // first of all try to open the "next" log file while (reader == null && fileIndex < logFiles.Count) { // open reader FileInfo file = (FileInfo)logFiles[fileIndex]; logName = file.FullName; logDate = file.CreationTime.Ticks; try { Stream logStream = new FileStream(logName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); reader = new StreamReader(logStream); // update statistics counter TotalBytesProcessed += file.Length; // position file to the specified line if (lineIndex > 0) { // skip lines up to required int seekLine = 0; while (((line = reader.ReadLine()) != null) && ++seekLine < lineIndex) { // try to get field names ParseFieldNames(); } lastLineIndex = lineIndex; } } catch(Exception ex) { // can't open log file // skip it Log.WriteError(String.Format("An error occured while reading log file: {0}", logName), ex); } fileIndex++; // increment files pointer } // return if it was the last log file in the list if (reader == null) return false; // assumed that log file is already opened // read next line line = reader.ReadLine(); if (line == null) { // the most propbably current log file is finished // reset current reader reader.Close(); reader = null; lineIndex = 0; // try to open next reader and read the first line return Read(); } // increment line index lineIndex++; lastLineIndex = lineIndex; // parse line if (!String.IsNullOrEmpty(line)) { if (line[0] == '#') { ParseFieldNames(); } else { ParseFieldValues(); } } else { errorLine = true; } return true; } private void ParseFieldNames() { systemLine = true; if (!line.StartsWith(FIELDS_LINE)) return; fields = line.Substring(FIELDS_LINE_LENGTH).Trim().Split(FIELDS_SPLITTER); fieldsLength = fields.Length; } protected virtual void ParseFieldValues() { // clear state errorLine = systemLine = false; // clear values hash // record.Clear(); /*if (line[0] == '#') { // it is a system line // skip it and go ahead systemLine = true; return; }*/ // fieldsValues = line.Split(FIELDS_SPLITTER, StringSplitOptions.None); // error line if (fieldsValues.Length != fieldsLength) errorLine = true; } private void GetDirectoryFiles(DirectoryInfo root, ArrayList files) { // get the files in the current directory files.AddRange(root.GetFiles()); // scan subdirectories DirectoryInfo[] dirs = root.GetDirectories(); foreach (DirectoryInfo dir in dirs) GetDirectoryFiles(dir, files); } // provide read-only access to the current log line fields public string this[string field] { get { if (!errorLine && !systemLine) { // get field index in fields array int indexOf = Array.IndexOf(fields, field); // ensure field exists if (indexOf > -1) return fieldsValues[indexOf]; ; } // field not found or line is either system or error return null; } } public bool ErrorLine { get { return errorLine; } set { errorLine = value; } } public bool SystemLine { get { return systemLine; } set { systemLine = value; } } public long LogDate { get { return logDate; } } public string LogName { get { return logName; } } public string[] LineFields { get { return fields; } } public string[] LineValues { get { return fieldsValues; } } public string CurrentLine { get { return line; } } public long LogLine { get { return lastLineIndex; } } } }