diff --git a/Makefile b/Makefile index 5400daf..17c09bd 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ export LDFLAGS export AR -all: space mainparser mainspaceparser utf8 date convert +all: space mainparser mainspaceparser utf8 date convert logger @@ -48,6 +48,8 @@ date: FORCE convert: FORCE @cd convert ; $(MAKE) -e +logger: FORCE + @cd logger ; $(MAKE) -e @@ -62,6 +64,7 @@ clean: @cd utf8 ; $(MAKE) -e clean @cd date ; $(MAKE) -e clean @cd convert ; $(MAKE) -e clean + @cd logger ; $(MAKE) -e clean depend: @cd space ; $(MAKE) -e depend @@ -70,3 +73,4 @@ depend: @cd utf8 ; $(MAKE) -e depend @cd date ; $(MAKE) -e depend @cd convert ; $(MAKE) -e depend + @cd logger ; $(MAKE) -e depend diff --git a/logger/Makefile b/logger/Makefile new file mode 100644 index 0000000..79eef0d --- /dev/null +++ b/logger/Makefile @@ -0,0 +1,27 @@ +include Makefile.o.dep + +libname=logger.a + +all: $(libname) + +$(libname): $(o) + $(AR) rcs $(libname) $(o) + + +%.o: %.cpp + $(CXX) -c $(CXXFLAGS) -I.. $< + + + +depend: + makedepend -Y. -I.. -f- *.cpp > Makefile.dep + echo -n "o = " > Makefile.o.dep + ls -1 *.cpp | xargs -I foo echo -n foo " " | sed -E "s/([^\.]*)\.cpp[ ]/\1\.o/g" >> Makefile.o.dep + + +clean: + rm -f *.o + rm -f $(libname) + + +include Makefile.dep diff --git a/logger/Makefile.dep b/logger/Makefile.dep new file mode 100644 index 0000000..461fd58 --- /dev/null +++ b/logger/Makefile.dep @@ -0,0 +1,7 @@ +# DO NOT DELETE + +logger.o: logger.h ../textstream/textstream.h ../space/space.h +logger.o: ../textstream/types.h ../date/date.h ../convert/convert.h +logger.o: ../convert/inttostr.h ../convert/strtoint.h ../convert/text.h +logger.o: ../convert/misc.h ../membuffer/membuffer.h ../textstream/types.h +logger.o: ../utf8/utf8.h diff --git a/logger/Makefile.o.dep b/logger/Makefile.o.dep new file mode 100644 index 0000000..acfd9ce --- /dev/null +++ b/logger/Makefile.o.dep @@ -0,0 +1 @@ +o = logger.o \ No newline at end of file diff --git a/logger/logger.cpp b/logger/logger.cpp new file mode 100644 index 0000000..d2e347f --- /dev/null +++ b/logger/logger.cpp @@ -0,0 +1,472 @@ +/* + * This file is a part of PikoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2018, Tomasz Sowa + * 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 Tomasz Sowa nor the names of contributors to this + * project 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 OWNER 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. + */ + +#include +#include +#include "logger.h" +#include "date/date.h" +#include "utf8/utf8.h" + + +namespace PT +{ + + + + +Logger::Logger() +{ + log_level = 1; + current_level = 100; // nothing to log (call Init() first) + lines = 0; + max_lines = 500; + log_file_open = false; +} + + +Logger::~Logger() +{ + save_log_and_clear(); +} + + + + +int Logger::get_log_level() +{ + return log_level; +} + + +void Logger::set_log_level(int log_level) +{ + this->log_level = log_level; +} + + + + +void Logger::init(int log_level, bool save_each_line, const std::wstring & log_file, bool log_stdout) +{ + this->log_level = log_level; + this->save_each_line = save_each_line; + this->log_stdout = log_stdout; + + PT::WideToUTF8(log_file, this->log_file); + // don't open the file here + // because it would be created with the root as an owner if you created something like a www server + // which starts as root and then drops privileges +} + + +void Logger::open_file() +{ + if( !log_file.empty() ) + { + file.open(log_file.c_str(), std::ios_base::out | std::ios_base::app); + log_file_open = true; + } +} + + +Logger & Logger::operator<<(const void * s) +{ + if( current_level > log_level ) + return *this; + + buffer << s; + return *this; +} + + + +Logger & Logger::operator<<(const char * s) +{ + if( current_level > log_level ) + return *this; + + if( !s ) + return *this; + + buffer << s; + +return *this; +} + + + +Logger & Logger::operator<<(const std::string & s) +{ + if( current_level > log_level ) + return *this; + + buffer << s; + return *this; +} + + + +Logger & Logger::operator<<(const std::string * s) +{ + if( current_level > log_level ) + return *this; + + buffer << *s; + return *this; +} + + + + + + +Logger & Logger::operator<<(const wchar_t * s) +{ + if( current_level <= log_level ) + { + if( s ) + buffer << s; + } + +return *this; +} + + + +Logger & Logger::operator<<(const std::wstring & s) +{ + if( current_level <= log_level ) + { + buffer << s; + } + + return *this; +} + + + +Logger & Logger::operator<<(const std::wstring * s) +{ + if( current_level <= log_level ) + { + buffer << *s; + } + + return *this; +} + + + + + +Logger & Logger::operator<<(int s) +{ + if( current_level <= log_level ) + { + buffer << s; + } + + return *this; +} + + + +Logger & Logger::operator<<(long s) +{ + if( current_level <= log_level ) + { + buffer << s; + } + + return *this; +} + + + + +Logger & Logger::operator<<(char s) +{ + if( current_level <= log_level ) + { + buffer << s; + } + + return *this; +} + + +Logger & Logger::operator<<(wchar_t s) +{ + if( current_level <= log_level ) + { + buffer << s; + } + + return *this; +} + + +Logger & Logger::operator<<(size_t s) +{ + if( current_level <= log_level ) + { + buffer << s; + } + + return *this; +} + + + +Logger & Logger::operator<<(double s) +{ + if( current_level <= log_level ) + { + buffer << s; + } + + return *this; +} + + + +Logger & Logger::operator<<(const PT::Space & s) +{ + if( current_level <= log_level ) + { + buffer << s; + } + +return *this; +} + + + +Logger & Logger::operator<<(const PT::Date & date) +{ + if( current_level <= log_level ) + { + buffer << date; + } + +return *this; +} + + + +Logger & Logger::operator<<(Manipulators m) +{ + switch(m) + { + case lend: + case logend: + // IMPROVE ME use max_lines here + if( current_level <= log_level ) + { + buffer << '\n'; + lines += 1; + + if( save_each_line ) + save_log_and_clear(); + } + break; + + case lsave: + case logsave: + save_log_and_clear(); + break; + + case l1: + case log1: + current_level = 1; + break; + + case l2: + case log2: + current_level = 2; + break; + + case l3: + case log3: + current_level = 3; + break; + + case l4: + case log4: + current_level = 4; + break; + + default: + break; + } + +return *this; +} + + + + +char Logger::get_hex_digit(unsigned char c) +{ + if( c < 10 ) + return c + '0'; + +return c - 10 + 'A'; +} + + + +void Logger::to_hex(char * buf, unsigned char c) +{ + buf[0] = get_hex_digit(c >> 4); + buf[1] = get_hex_digit(c & 0xf); + buf[2] = 0; +} + + +Logger & Logger::log_binary(const char * blob, size_t blob_len) +{ +size_t i=0; +char buf[3]; + + + while( i < blob_len ) + { + size_t oldi = i; + + for(size_t a=0 ; a<16 ; ++a) + { + if( i < blob_len ) + { + to_hex(buf, blob[i]); + buffer << buf << ' '; + ++i; + } + else + { + buffer << " "; + } + + if( a == 7 ) + { + if( i < blob_len ) + buffer << "- "; + else + buffer << " "; + } + } + + i = oldi; + buffer << ' '; + + for(size_t a=0 ; a<16 && i 31 && blob[i] < 127 ) + buffer << blob[i]; + else + buffer << '.'; + } + + (*this) << logend; + } + + return *this; +} + + +Logger & Logger::log_binary(const std::string & blob) +{ + return log_binary(blob.c_str(), blob.size()); +} + + + +void Logger::save_log_and_clear() +{ + save_log(); + + buffer.clear(); + lines = 0; +} + + +void Logger::save_log() +{ + std::wstring log_wide;// IMPROVE ME do something better + std::string log_ascii;// IMPROVE ME + + if( buffer.empty() ) + return; + + // IMPROVE ME + // add special version of TextStream.to_string() + // which can convert from wide to utf8 (by using if constexpr) + + // may we need a different buffer type? utf8 buffer? + + buffer.to_string(log_wide); + PT::WideToUTF8(log_wide, log_ascii); + + if( log_stdout ) + std::cout << log_ascii; + + if( log_file.empty() ) + return; + + if( !log_file_open || !file ) + { + file.close(); + file.clear(); + + open_file(); + + if( !file ) + return; + } + + file << log_ascii; + file.flush(); +} + + + +} // namespace + + + + + diff --git a/logger/logger.h b/logger/logger.h new file mode 100644 index 0000000..e04080a --- /dev/null +++ b/logger/logger.h @@ -0,0 +1,236 @@ +/* + * This file is a part of PikoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2018, Tomasz Sowa + * 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 Tomasz Sowa nor the names of contributors to this + * project 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 OWNER 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. + */ + +#ifndef headerfile_picotools_logger_logger +#define headerfile_picotools_logger_logger + +#include +#include +#include "textstream/textstream.h" + + + +namespace PT +{ + + +class Logger +{ +public: + + + + /* + log1 - the first level + log2 + log3 + log4 - the last level (debug level) + logend - the end of a line + logendrequest - end of a current request + logsave - current log buffer is saved and cleared + + manipulators used by the session logger (SLog) + loginfo - normal info to a user + logerror - we are reporting an error + logwarning - we are reporting a warning + + make sure that loginfo, logerror and logwarning have values less than 32 (space) + their are used as control codes in a string + */ + enum Manipulators + { + log1, + log2, + log3, + log4, + + l1, + l2, + l3, + l4, + + logend, + lend, + + + logsave, + lsave, + + +// logendrequest, +// logsave, + +// loginfo, +// logerror, +// logwarning + }; + + + + Logger(); + virtual ~Logger(); + + + int get_log_level(); + void set_log_level(int log_level); + + + void init(int log_level, bool save_each_line, const std::wstring & log_file, bool log_stdout); + + Logger & operator<<(const void * s); + + Logger & operator<<(const char * s); + Logger & operator<<(const std::string * s); + Logger & operator<<(const std::string & s); + + Logger & operator<<(const wchar_t * s); + Logger & operator<<(const std::wstring * s); + Logger & operator<<(const std::wstring & s); + + Logger & operator<<(char s); + Logger & operator<<(wchar_t s); + + Logger & operator<<(int s); + Logger & operator<<(long s); + //Logger & operator<<(long long s); // added + + + Logger & operator<<(size_t s); + + //Logger & operator<<(float s); // added + Logger & operator<<(double s); + + Logger & operator<<(const PT::Space & space); + Logger & operator<<(Manipulators m); + Logger & operator<<(const PT::Date & date); + + + template + Logger & operator<<(const PT::TextStreamBase & buf); + + + template + Logger & log_string(const StringType & value, size_t max_size); + + Logger & log_binary(const char * blob, size_t blob_len); + Logger & log_binary(const std::string & blob); + + + void save_log(); + void save_log_and_clear(); + + + +private: + + // buffer for the log (wide characters) + PT::WTextStream buffer; + + // log lovel from init() + int log_level; + + // current level set by a modifier (e.g. log << log3) + int current_level; + + // file log + std::string log_file; + std::ofstream file; + + // logging to stdout + bool log_stdout; + + // how many lines there are in the buffer + int lines; + + // is the config file already open + bool log_file_open; + + // how many lines can be in the config buffer + // default: 500 + int max_lines; + + // whether to save each line (for debug purpopes) + bool save_each_line; + + void open_file(); + char get_hex_digit(unsigned char c); + void to_hex(char * buf, unsigned char c); + +}; + + + +template +Logger & Logger::log_string(const StringType & value, size_t max_size) +{ + size_t min_size = value.size() < max_size ? value.size() : max_size; + + if( current_level <= log_level ) + { + for(size_t i=0 ; i < min_size ; ++i) + { + if( value[i] < 32 ) + buffer << '.'; // unprintable characters + else + buffer << value[i]; + } + } + + return *this; +} + + + +template +Logger & Logger::operator<<(const PT::TextStreamBase & buf) +{ + if( current_level <= log_level ) + buffer << buf; + +return *this; +} + + + + + +} // namespace + + +#endif + +