/* * This file is a part of PikoTools * and is distributed under the (new) BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2018-2021, 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 "log.h" #include "date/date.h" #include "utf8/utf8.h" #ifdef PT_HAS_MORM #include "morm.h" #endif namespace pt { Log::Log() { buffer = nullptr; file_log = nullptr; current_level = 4; max_buffer_length = 2 * 1024 * 1024; // 2MB } Log::~Log() { // IMPROVE ME // I am not sure if this is a correct behaviour // the log buffer and file logger may not exist now // (life time of objects) // may would be better to have a flag 'clear_at_the_end' // and if true then call this method? save_log_and_clear(); } void Log::SetLogBuffer(WTextStream * buffer) { this->buffer = buffer; } WTextStream * Log::GetLogBuffer() { return buffer; } void Log::SetMaxBufferLength(size_t max_buffer_length) { this->max_buffer_length = max_buffer_length; } size_t Log::GetMaxBufferLength() { return max_buffer_length; } void Log::SetFileLog(FileLog * file_log) { this->file_log = file_log; } FileLog * Log::GetFileLog() { return file_log; } Log & Log::IntMinWidth(size_t min_width) { if( buffer ) { buffer->int_min_width(min_width); } return *this; } Log & Log::operator<<(const void * s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(const char * s) { if( buffer && file_log && s && current_level <= file_log->get_log_level() ) { utf8_to_wide(s, *buffer, false); } return *this; } Log & Log::operator<<(const std::string & s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { utf8_to_wide(s, *buffer, false); } return *this; } Log & Log::operator<<(const std::string * s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { utf8_to_wide(*s, *buffer, false); } return *this; } Log & Log::operator<<(const wchar_t * s) { if( buffer && file_log && s && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(const std::wstring & s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(const std::wstring * s) { if( buffer && file_log && s && current_level <= file_log->get_log_level() ) { (*buffer) << *s; } return *this; } Log & Log::operator<<(int s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(long s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(long long s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(char s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(wchar_t s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(size_t s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(double s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(const Space & s) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << s; } return *this; } Log & Log::operator<<(const Date & date) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << date; } return *this; } #ifdef PT_HAS_MORM Log & Log::operator<<(morm::Model & model) { operator<<(model.to_string()); return *this; } #endif Log & Log::operator<<(Manipulators m) { switch(m) { case lend: case logend: if( buffer && file_log && current_level <= file_log->get_log_level() ) { (*buffer) << '\n'; if( file_log->should_save_each_line() || buffer->size() > max_buffer_length ) 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; } Log & Log::LogString(const std::string & value, size_t max_size) { return log_string_generic(value, max_size); } Log & Log::LogString(const std::wstring & value, size_t max_size) { return log_string_generic(value, max_size); } char Log::get_hex_digit(unsigned char c) { if( c < 10 ) return c + '0'; return c - 10 + 'A'; } void Log::to_hex(char * buf, unsigned char c) { buf[0] = get_hex_digit(c >> 4); buf[1] = get_hex_digit(c & 0xf); buf[2] = 0; } Log & Log::LogBinary(const char * blob, size_t blob_len) { size_t i=0; char buf[3]; if( buffer && file_log && blob && current_level <= file_log->get_log_level() ) { 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; } Log & Log::LogBinary(const std::string & blob) { return LogBinary(blob.c_str(), blob.size()); } void Log::save_log_and_clear() { save_log(); if( buffer ) { buffer->clear(); } } void Log::save_log() { if( file_log && buffer ) { file_log->save_log(buffer); } } } // namespace