summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ConsoleLogSink.cpp17
-rwxr-xr-xsrc/ConsoleLogSink.hpp14
-rw-r--r--src/FileLogSink.cpp85
-rwxr-xr-xsrc/FileLogSink.hpp23
-rwxr-xr-xsrc/GNUmakefile3
-rwxr-xr-xsrc/LogSink.hpp23
-rw-r--r--src/Logger.cpp77
-rwxr-xr-xsrc/Logger.hpp130
-rwxr-xr-xsrc/Makefile.W323
-rwxr-xr-xsrc/crawl.cpp3
-rw-r--r--tests/GNUmakefile2
-rw-r--r--tests/Makefile.W322
-rwxr-xr-xtests/logger/GNUmakefile30
-rwxr-xr-xtests/logger/Makefile.W3238
-rw-r--r--tests/logger/test1.cpp23
-rw-r--r--tests/typedetect/GNUmakefile2
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 ; \