diff options
author | Andreas Baumann <abaumann@yahoo.com> | 2012-08-22 20:17:03 +0200 |
---|---|---|
committer | Andreas Baumann <abaumann@yahoo.com> | 2012-08-22 20:17:03 +0200 |
commit | 7e45233ba4435cbfd775bb252e3c3b81120f9825 (patch) | |
tree | 4688ef69a2cd8cb52efb6b7f2ba1783cc57cdcaf | |
parent | 288d553d5b60c84da8795000ac22df288d9becb2 (diff) | |
download | crawler-7e45233ba4435cbfd775bb252e3c3b81120f9825.tar.gz crawler-7e45233ba4435cbfd775bb252e3c3b81120f9825.tar.bz2 |
completly rewrote the logger as singleton
-rw-r--r-- | src/ConsoleLogSink.cpp | 17 | ||||
-rwxr-xr-x | src/ConsoleLogSink.hpp | 14 | ||||
-rw-r--r-- | src/FileLogSink.cpp | 85 | ||||
-rwxr-xr-x | src/FileLogSink.hpp | 23 | ||||
-rwxr-xr-x | src/GNUmakefile | 3 | ||||
-rwxr-xr-x | src/LogSink.hpp | 23 | ||||
-rw-r--r-- | src/Logger.cpp | 77 | ||||
-rwxr-xr-x | src/Logger.hpp | 130 | ||||
-rwxr-xr-x | src/Makefile.W32 | 3 | ||||
-rwxr-xr-x | src/crawl.cpp | 3 | ||||
-rw-r--r-- | tests/GNUmakefile | 2 | ||||
-rw-r--r-- | tests/Makefile.W32 | 2 | ||||
-rwxr-xr-x | tests/logger/GNUmakefile | 30 | ||||
-rwxr-xr-x | tests/logger/Makefile.W32 | 38 | ||||
-rw-r--r-- | tests/logger/test1.cpp | 23 | ||||
-rw-r--r-- | tests/typedetect/GNUmakefile | 2 |
16 files changed, 383 insertions, 92 deletions
diff --git a/src/ConsoleLogSink.cpp b/src/ConsoleLogSink.cpp new file mode 100644 index 0000000..e986961 --- /dev/null +++ b/src/ConsoleLogSink.cpp @@ -0,0 +1,17 @@ +#include "ConsoleLogSink.hpp" + +#include <iostream> + +using namespace std; + +void ConsoleLogSink::log( const LogLevel level, const std::string &msg ) +{ + if( level > reportingLevel( ) ) return; + + cerr << Logger::toString( level ) + << ": " + << msg + << endl; + + cerr.flush( ); +} diff --git a/src/ConsoleLogSink.hpp b/src/ConsoleLogSink.hpp new file mode 100755 index 0000000..f700825 --- /dev/null +++ b/src/ConsoleLogSink.hpp @@ -0,0 +1,14 @@ +#ifndef __CONSOLE_LOGSINK_H +#define __CONSOLE_LOGSINK_H + +#include "LogSink.hpp" + +class ConsoleLogSink : public LogSink +{ + public: + ConsoleLogSink( const LogLevel level ) : LogSink( level ) { } + + void log( const LogLevel level, const std::string &msg ); +}; + +#endif diff --git a/src/FileLogSink.cpp b/src/FileLogSink.cpp new file mode 100644 index 0000000..d812dbe --- /dev/null +++ b/src/FileLogSink.cpp @@ -0,0 +1,85 @@ +#include "FileLogSink.hpp" + +#include <iostream> +#include <cstring> + +#ifndef _WIN32 +#include <sys/time.h> +#else +#define WIN32_MEAN_AND_LEAN +#include <windows.h> +#endif + +using namespace std; + +#ifndef _WIN32 + +static string timestamp( ) +{ + time_t t; + time( &t ); + + struct tm r; + memset( &r, 0, sizeof( r ) ); + localtime_r( &t, &r ); + + char buf[30]; + strftime( buf, sizeof( buf ), "%F - %X", &r ); + + struct timeval tv; + gettimeofday( &tv, 0 ); + char result[100]; + snprintf( result, sizeof( result ), "%s.%03ld", buf, (long)tv.tv_usec / 1000 ); + + return result; +} + +#else + +static string timestamp( ) +{ + enum { LEN = 255 }; + char buf[LEN]; + + if( GetTimeFormat( LOCALE_USER_DEFAULT, 0, 0, "HH':'mm':'ss", buf, LEN ) == 0 ) { + return "<timestamp error>"; + } + + static DWORD first = GetTickCount( ); + + char result[LEN] = { 0 }; + _snprintf( result, LEN, "%s.%03ld", buf, (long)( GetTickCount( ) - first ) % 1000 ); + + return result; +} + +#endif + +FileLogSink::FileLogSink( const LogLevel level, const string &filename ) + : LogSink( level ), m_filename( filename ) +{ + m_file.exceptions( m_file.badbit | m_file.failbit ); + + try { + m_file.open( m_filename.c_str( ), std::ios::app ); + } catch( exception &e ) { + LOG( logCRITICAL ) << e.what( ); + } +} + +FileLogSink::~FileLogSink( ) +{ + m_file.close( ); +} + +void FileLogSink::log( const LogLevel level, const string &msg ) +{ + if( level > reportingLevel( ) ) return; + + m_file << timestamp( ) + << " " + << Logger::toString( level ) + << ": " + << msg + << endl; +} diff --git a/src/FileLogSink.hpp b/src/FileLogSink.hpp new file mode 100755 index 0000000..f488a87 --- /dev/null +++ b/src/FileLogSink.hpp @@ -0,0 +1,23 @@ +#ifndef __FILE_LOGSINK_H +#define __FILE_LOGSINK_H + +#include "LogSink.hpp" + +#include <string> +#include <fstream> + +class FileLogSink : public LogSink +{ + public: + FileLogSink( const LogLevel level, const std::string &filename ); + + ~FileLogSink( ); + + void log( const LogLevel level, const std::string &msg ); + + private: + std::string m_filename; + std::ofstream m_file; +}; + +#endif diff --git a/src/GNUmakefile b/src/GNUmakefile index 1e8ecba..119ec2b 100755 --- a/src/GNUmakefile +++ b/src/GNUmakefile @@ -24,6 +24,9 @@ INCLUDE_LIBS += \ endif LOCAL_STATIC_LIB_OBJS = \ + Logger.o \ + ConsoleLogSink.o \ + FileLogSink.o \ URL.o \ MIMEType.o \ SpoolRewindInputStream.o diff --git a/src/LogSink.hpp b/src/LogSink.hpp new file mode 100755 index 0000000..47d92a7 --- /dev/null +++ b/src/LogSink.hpp @@ -0,0 +1,23 @@ +#ifndef __LOGSINK_H +#define __LOGSINK_H + +#include "Logger.hpp" + +class LogSink +{ + public: + LogSink( const LogLevel level ) : m_level( level ) { } + + virtual ~LogSink( ) { } + + virtual void log( const LogLevel level, const std::string &msg ) = 0; + + protected: + + LogLevel reportingLevel( ) { return m_level; } + + private: + LogLevel m_level; +}; + +#endif diff --git a/src/Logger.cpp b/src/Logger.cpp new file mode 100644 index 0000000..24957a8 --- /dev/null +++ b/src/Logger.cpp @@ -0,0 +1,77 @@ +#include "Logger.hpp" +#include "LogSink.hpp" + +#include <algorithm> + +using namespace std; + +LogStream::LogStream( Logger &logger, const LogLevel level ) + : m_logger( logger ), m_level( level ) +{ +} + +LogStream::~LogStream( ) +{ + m_logger.log( m_level, str( ) ); +} + +ostream &LogStream::get( ) +{ + return static_cast<ostream &>( *this ); +} + +Logger::~Logger( ) +{ + SinkList::const_iterator it, end = m_sinks.end( ); + + for( it = m_sinks.begin( ); it != end; it++ ) { + delete (*it); + } +} + +void Logger::addSink( LogSink *sink ) +{ + m_sinks.push_back( sink ); +} + +void Logger::removeSink( LogSink *sink ) +{ + SinkList::iterator it = find( m_sinks.begin( ), m_sinks.end( ), sink ); + if( it != m_sinks.end( ) ) { + m_sinks.erase( it ); + } +} + +void Logger::log( const LogLevel level, const string &msg ) +{ + SinkList::const_iterator it, end = m_sinks.end( ); + + for( it = m_sinks.begin( ); it != end; it++ ) { + (*it)->log( level, msg ); + } +} + +string Logger::toString( const LogLevel level ) +{ + static const char* const buf[] = { "FATAL", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG", "DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4" }; + return buf[level]; +} + +LogLevel Logger::fromString( const string& level ) +{ + if( level == "DEBUG4" ) return logDEBUG4; + if( level == "DEBUG3" ) return logDEBUG3; + if( level == "DEBUG2" ) return logDEBUG2; + if( level == "DEBUG1") return logDEBUG1; + if( level == "DEBUG") return logDEBUG; + if( level == "INFO") return logINFO; + if( level == "NOTICE" ) return logNOTICE; + if( level == "WARNING" ) return logWARNING; + if( level == "ERROR" ) return logERROR; + if( level == "CRITICAL" ) return logCRITICAL; + if( level == "FATAL" ) return logFATAL; + + LOG( logWARNING ) << "Unknown log level '" << level << "'. Using INFO level as default."; + return logINFO; +} + diff --git a/src/Logger.hpp b/src/Logger.hpp index 497e170..a004068 100755 --- a/src/Logger.hpp +++ b/src/Logger.hpp @@ -1,27 +1,16 @@ #ifndef __LOGGER_H #define __LOGGER_H -// roughly based on http://drdobbs.com/cpp/201804215? - #include "Singleton.hpp" +#include "NonCopyable.hpp" +#include "Exportable.hpp" #include <sstream> -#include <string> - -#include <cstdio> -#include <cstring> - -#ifndef _WIN32 -#include <sys/time.h> -#else -#define WIN32_MEAN_AND_LEAN -#include <windows.h> -#endif - -using namespace std; +#include <list> enum LogLevel { logFATAL, + logCRITICAL, logERROR, logWARNING, logNOTICE, @@ -33,48 +22,51 @@ enum LogLevel { logDEBUG4 }; -#ifndef _WIN32 +class Logger; -static inline string timestamp( ) +class LogStream : private noncopyable, public std::ostringstream { - time_t t; - time( &t ); + public: + LogStream( Logger &logger, const LogLevel level ); + ~LogStream( ); + std::ostream &get( ); - struct tm r; - memset( &r, 0, sizeof( r ) ); - localtime_r( &t, &r ); + private: + LogStream( ); + LogStream( const LogStream & ); + LogStream &operator=( const LogStream &); + + private: + Logger &m_logger; + LogLevel m_level; +}; - char buf[30]; - strftime( buf, sizeof( buf ), "%F - %X", &r ); - - struct timeval tv; - gettimeofday( &tv, 0 ); - char result[100]; - snprintf( result, sizeof( result ), "%s.%03ld", buf, (long)tv.tv_usec / 1000 ); +class LogSink; - return result; -} +class Logger : public Singleton< Logger > +{ + public: + void addSink( LogSink *sink ); + void removeSink( LogSink *sink ); + void log( const LogLevel level, const std::string &msg ); -#else + ~Logger( ); -static inline string timestamp( ) -{ - enum { LEN = 255 }; - char buf[LEN]; - - if( GetTimeFormat( LOCALE_USER_DEFAULT, 0, 0, "HH':'mm':'ss", buf, LEN ) == 0 ) { - return "<timestamp error>"; - } - - static DWORD first = GetTickCount( ); + static std::string toString( LogLevel level ); + static LogLevel fromString( const std::string &s ); + + private: + typedef std::list< LogSink * > SinkList; + SinkList m_sinks; +}; - char result[LEN] = { 0 }; - _snprintf( result, LEN, "%s.%03ld", buf, (long)( GetTickCount( ) - first ) % 1000 ); - - return result; -} +SINGLETON_EXTERN template class SINGLETON_EXPORT Singleton< Logger >; -#endif +#define LOG( level ) LogStream( Logger::instance( ), level ).get( ) + +#if 0 + +using namespace std; template<typename T> class Log @@ -87,15 +79,11 @@ class Log ostringstream& get( LogLevel level = logINFO ); static LogLevel& reportingLevel( ); - static string toString( const LogLevel level ); - static LogLevel fromString( const string& s ); protected: ostringstream os; private: - Log( const Log & ); - Log& operator=(const Log & ); }; template <typename T> @@ -104,17 +92,6 @@ Log<T>::Log( ) } template <typename T> -std::ostringstream& Log<T>::get( LogLevel level ) -{ - os << timestamp( ) - << " " - << toString( level ) - << ": "; - - return os; -} - -template <typename T> Log<T>::~Log() { os << endl; @@ -128,31 +105,6 @@ LogLevel& Log<T>::reportingLevel( ) return reportingLevel; } -template <typename T> -string Log<T>::toString( const LogLevel level ) -{ - static const char* const buf[] = { "FATAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG", "DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4" }; - return buf[level]; -} - -template <typename T> -LogLevel Log<T>::fromString( const string& level ) -{ - if( level == "DEBUG4" ) return logDEBUG4; - if( level == "DEBUG3" ) return logDEBUG3; - if( level == "DEBUG2" ) return logDEBUG2; - if( level == "DEBUG1") return logDEBUG1; - if( level == "DEBUG") return logDEBUG; - if( level == "INFO") return logINFO; - if( level == "NOTICE" ) return logNOTICE; - if( level == "WARNING" ) return logWARNING; - if( level == "ERROR" ) return logERROR; - if( level == "FATAL" ) return logFATAL; - - Log<T>( ).get( logWARNING ) << "Unknown log level '" << level << "'. Using INFO level as default."; - return logINFO; -} - class Output2FILE { public: @@ -190,3 +142,5 @@ class FILELog : public Log<Output2FILE> else FILELog( ).get( level ) #endif + +#endif diff --git a/src/Makefile.W32 b/src/Makefile.W32 index 8478607..786bb09 100755 --- a/src/Makefile.W32 +++ b/src/Makefile.W32 @@ -17,6 +17,9 @@ INCLUDE_LIBS = \ LOCAL_STATIC_LIB_OBJS = \ win32\errormsg.obj \ win32\stringutils.obj \ + Logger.obj \ + ConsoleLogSink.obj \ + FileLogSink.obj \ URL.obj \ MIMEType.obj \ SpoolRewindInputStream.obj diff --git a/src/crawl.cpp b/src/crawl.cpp index 08f3eec..dcc8d11 100755 --- a/src/crawl.cpp +++ b/src/crawl.cpp @@ -10,6 +10,7 @@ #include "ModuleLoader.hpp" #include "Logger.hpp" +#include "ConsoleLogSink.hpp" #include <set> #include <vector> @@ -55,7 +56,7 @@ BOOL WINAPI termHandler( DWORD ctrlType ) int main( void ) { try { - FILELog::reportingLevel( ) = logINFO; + Logger::instance( ).addSink( new ConsoleLogSink( logINFO ) ); #ifndef _WIN32 struct sigaction sa; diff --git a/tests/GNUmakefile b/tests/GNUmakefile index 440ba18..46fe18b 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -1,7 +1,7 @@ TOPDIR = .. SUBDIRS = \ - utils modules url streamhtmlparser libfetch curl psql sqlite typedetect \ + utils logger modules url streamhtmlparser libfetch curl psql sqlite typedetect \ fetcher -include $(TOPDIR)/makefiles/gmake/sub.mk diff --git a/tests/Makefile.W32 b/tests/Makefile.W32 index d5ac96b..f5c828b 100644 --- a/tests/Makefile.W32 +++ b/tests/Makefile.W32 @@ -1,7 +1,7 @@ TOPDIR = .. SUBDIRS = \ - utils modules winhttp url streamhtmlparser \ + utils logger modules winhttp url streamhtmlparser \ fetcher !INCLUDE $(TOPDIR)\makefiles\nmake\sub.mk diff --git a/tests/logger/GNUmakefile b/tests/logger/GNUmakefile new file mode 100755 index 0000000..278a892 --- /dev/null +++ b/tests/logger/GNUmakefile @@ -0,0 +1,30 @@ +TOPDIR = ../.. + +SUBDIRS = + +INCLUDE_DIRS = \ + -I. -I$(TOPDIR)/src + +INCLUDE_LDFLAGS = + +INCLUDE_LIBS = \ + $(TOPDIR)/src/libcrawler.a + +TEST_CPP_BINS = \ + test1$(EXE) + +OBJS = + +-include $(TOPDIR)/makefiles/gmake/sub.mk + +local_all: + +local_clean: + -@rm -f *.RES *.DIFF + +local_distclean: + +local_test: +# @./exec_test test1 "TypeList and TypeTraits" +# @./exec_test test2 "TypeInfo C++ demangle" +# @./exec_test test3 "Singleton" diff --git a/tests/logger/Makefile.W32 b/tests/logger/Makefile.W32 new file mode 100755 index 0000000..cbc9e0e --- /dev/null +++ b/tests/logger/Makefile.W32 @@ -0,0 +1,38 @@ +TOPDIR = ..\.. + +SUBDIRS = + +!INCLUDE $(TOPDIR)\makefiles\nmake\platform.mk + +INCLUDE_CXXFLAGS = \ + /D_WIN32_WINNT=0x504 + +INCLUDE_DIRS = \ + /I. \ + /I$(TOPDIR)\src + +INCLUDE_LDFLAGS = \ + +INCLUDE_LIBS = \ + $(TOPDIR)\src\crawler.lib + +TEST_CPP_BINS = \ + test1.exe + +OBJS = + +!INCLUDE $(TOPDIR)\makefiles\nmake\sub.mk + +test1.exe: test1.obj + +local_all: + +local_clean: + @-erase -f *.RES *.DIFF *.ERR 2>NUL + +local_distclean: + +local_test: +# @-exec_test test1 "TypeList and TypeTraits" +# @-exec_test test2 "TypeInfo C++ demangle" +# @-exec_test test3 "Singleton" diff --git a/tests/logger/test1.cpp b/tests/logger/test1.cpp new file mode 100644 index 0000000..0b1e11b --- /dev/null +++ b/tests/logger/test1.cpp @@ -0,0 +1,23 @@ +#include "Logger.hpp" +#include "ConsoleLogSink.hpp" +#include "FileLogSink.hpp" + +int main( void ) +{ + Logger::instance( ).addSink( new ConsoleLogSink( logNOTICE ) ); + Logger::instance( ).addSink( new FileLogSink( logNOTICE, "test1.log" ) ); + + LOG( logFATAL ) << "fatal error"; + LOG( logCRITICAL ) << "critical error"; + LOG( logERROR ) << "error"; + LOG( logWARNING ) << "warning"; + LOG( logNOTICE ) << "notice"; + LOG( logINFO ) << "info"; + LOG( logDEBUG ) << "debug"; + LOG( logDEBUG1 ) << "debug level 1"; + LOG( logDEBUG2 ) << "debug level 2"; + LOG( logDEBUG3 ) << "debug level 3"; + LOG( logDEBUG4 ) << "debug level 4"; + + return 0; +} diff --git a/tests/typedetect/GNUmakefile b/tests/typedetect/GNUmakefile index 251a2a2..4ddeacc 100644 --- a/tests/typedetect/GNUmakefile +++ b/tests/typedetect/GNUmakefile @@ -52,7 +52,7 @@ local_test: @-for METHOD in libmagic_typedetect; do \ echo "Using MIME type detector '$$METHOD'.." ; \ ./exec_test test1 test1 "detect a simple C++ file" $$METHOD file_fetcher file://localhost/`pwd`/test1.cpp ; \ - ./exec_test test1 test2 "detect a M$ word file" $$METHOD file_fetcher file://localhost/`pwd`/test2.doc ; \ + ./exec_test test1 test2 "detect a Msword file" $$METHOD file_fetcher file://localhost/`pwd`/test2.doc ; \ ./exec_test test1 test3 "detect a Excel file" $$METHOD file_fetcher file://localhost/`pwd`/test3.xls ; \ ./exec_test test1 test4 "detect a HTML file" $$METHOD file_fetcher file://localhost/`pwd`/test4.html ; \ ./exec_test test1 test5 "detect a CSS file" $$METHOD file_fetcher file://localhost/`pwd`/test5.css ; \ |