]> WPIA git - cassiopeia.git/commitdiff
add: Import Logging functionality by Florian Weber
authorBenny Baumann <BenBE@geshi.org>
Mon, 8 Jun 2015 11:20:28 +0000 (13:20 +0200)
committerBenny Baumann <BenBE@geshi.org>
Mon, 8 Jun 2015 21:54:19 +0000 (23:54 +0200)
Original source at https://github.com/Florianjw/simple_logger/

Minor modifications and source formatting have been applied

Makefile
src/log/logger.cpp [new file with mode: 0644]
src/log/logger.hpp [new file with mode: 0644]

index a22b76622ab19a14b409936c43f049387e8d7607..562abb5a503389d5c5df21d33363522f2f794bff 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -46,7 +46,7 @@ SRC_DIR=src
 OBJ_DIR=obj
 DEP_DIR=dep
 
-FS_SRC=$(wildcard ${SRC_DIR}/*.cpp) $(wildcard ${SRC_DIR}/io/*.cpp) $(wildcard ${SRC_DIR}/crypto/*.cpp) $(wildcard ${SRC_DIR}/db/*.cpp)
+FS_SRC=$(wildcard ${SRC_DIR}/*.cpp) $(wildcard ${SRC_DIR}/log/*.cpp) $(wildcard ${SRC_DIR}/io/*.cpp) $(wildcard ${SRC_DIR}/crypto/*.cpp) $(wildcard ${SRC_DIR}/db/*.cpp)
 
 FS_BIN=$(wildcard ${SRC_DIR}/app/*.cpp)
 FS_LIBS=$(wildcard lib/*/)
diff --git a/src/log/logger.cpp b/src/log/logger.cpp
new file mode 100644 (file)
index 0000000..9a70300
--- /dev/null
@@ -0,0 +1,146 @@
+#include "log/logger.hpp"
+
+#include <algorithm>
+#include <chrono>
+#include <cstring>
+#include <iostream>
+#include <iterator>
+
+namespace logger {
+
+    namespace {
+
+        std::ostream*& ostream_pointer() {
+            static std::ostream* stream = &std::cout;
+            return stream;
+        }
+
+        std::ostream& get_stream() {
+            return *ostream_pointer();
+        }
+
+        std::string make_prefix( level l ) {
+            auto prefix = std::string {};
+
+            switch( l ) {
+            case level::debug:
+                prefix = "[debug][";
+                break;
+
+            case level::note:
+                prefix = "[note ][";
+                break;
+
+            case level::warn:
+                prefix = "[warn ][";
+                break;
+
+            case level::error:
+                prefix = "[error][";
+                break;
+
+            case level::fatal:
+                prefix = "[fatal][";
+                break;
+            }
+
+            using clock = std::chrono::system_clock;
+            const auto now = clock::to_time_t( clock::now() );
+            // ctime appends a newline, we don't want that here:
+            auto time_str = std::ctime( &now );
+            prefix.append( time_str, time_str + std::strlen( time_str ) - 1 );
+            prefix += "]: ";
+            return prefix;
+        }
+
+    } // anonymous namespace
+
+    namespace impl {
+
+        std::string replace_newlines( const std::string& str, std::size_t length ) {
+            auto returnstring = std::string {};
+            auto it = str.begin();
+            const auto end = str.end();
+            auto nl_it = it;
+
+            while( ( nl_it = std::find( it, end, '\n' ) ) != end ) {
+                ++nl_it;
+                returnstring.append( it, nl_it );
+                returnstring.append( length, ' ' );
+                it = nl_it;
+            }
+
+            returnstring.append( it, end );
+            return returnstring;
+        }
+
+        void log( level l, const std::vector<std::string>& args ) {
+            const auto prefix = make_prefix( l );
+            const auto length = prefix.length();
+            get_stream() << prefix;
+            std::transform( args.begin(), args.end(), std::ostream_iterator<std::string> {get_stream()},
+                [length]( const std::string & str ) {
+                    return replace_newlines( str, length );
+                } );
+            get_stream() << '\n' << std::flush;
+        }
+
+        void logf( level l, const std::string& format, std::vector<std::string> args ) {
+            const auto prefix = make_prefix( l );
+            const auto length = prefix.length();
+            const auto fmt = replace_newlines( format, length );
+            std::transform( args.begin(), args.end(), args.begin(),
+                [length]( const std::string & str ) {
+                    return replace_newlines( str, length );
+                } );
+
+            auto mesg = prefix;
+            auto arg_index = std::size_t {0};
+            auto it = fmt.begin();
+            const auto end = fmt.end();
+
+            while( it != end ) {
+                auto pos = std::find( it, end, '%' );
+                mesg.append( it, pos );
+
+                if( pos == end ) {
+                    break;
+                }
+
+                ++pos;
+
+                if( pos == end ) {
+                    throw std::invalid_argument {"Invalid formatstring (ends on single '%')"};
+                }
+
+                switch( *pos ) {
+                case '%':
+                    mesg.push_back( '%' );
+                    break;
+
+                case 's':
+                    if( arg_index >= args.size() ) {
+                        throw std::invalid_argument {"Invalid formatstring (not enough arguments)"};
+                    }
+
+                    mesg.append( args[arg_index++] );
+                    break;
+
+                default:
+                    throw std::invalid_argument {"Invalid formatstring (unknown format-character)"};
+                }
+
+                it = std::next( pos );
+            }
+
+            mesg.push_back( '\n' );
+            get_stream() << mesg << std::flush;
+        }
+
+    } //  namespace impl
+
+    void set_stream( std::ostream& stream ) {
+        ostream_pointer() = &stream;
+    }
+
+} // namespace logger
diff --git a/src/log/logger.hpp b/src/log/logger.hpp
new file mode 100644 (file)
index 0000000..6d1e5e5
--- /dev/null
@@ -0,0 +1,97 @@
+#pragma once
+
+#include <ostream>
+#include <string>
+#include <sstream>
+#include <vector>
+
+namespace logger {
+
+    enum class level {
+        debug, note, warn, error, fatal
+    };
+
+    /**
+     * conv::to_string will be used to convert whatever argument is send
+     * to the logger to a string. If another type shall be supported,
+     * just add the appropriate overload and you can start using it right
+     * away. The default conversion will use a stringstream.
+     */
+    namespace conv {
+        template <typename T>
+        inline std::string to_string( const T& arg ) {
+            std::ostringstream stream;
+            stream << arg;
+            return stream.str();
+        }
+        inline std::string to_string( std::string&& arg ) {
+            return arg;
+        }
+        inline std::string to_string( const std::string& arg ) {
+            return arg;
+        }
+        inline std::string to_string( const char* arg ) {
+            return arg;
+        }
+    }
+
+    namespace impl {
+        void log( level, const std::vector<std::string>& args );
+        void logf( level, const std::string&, std::vector<std::string> args );
+    }
+
+    void set_stream( std::ostream& );
+
+    template <typename... Args>
+    void log( level l, Args&& ... data ) {
+        impl::log( l, {conv::to_string( std::forward<Args>( data ) )...} );
+    }
+
+    template <typename... Args>
+    void logf( level l, const std::string& format, Args&& ... data ) {
+        impl::logf( l, format, {conv::to_string( std::forward<Args>( data ) )...} );
+    }
+
+    template <typename... Args>
+    void debug( Args&& ... args ) {
+        log( level::debug, std::forward<Args>( args )... );
+    }
+    template <typename... Args>
+    void note( Args&& ... args ) {
+        log( level::note, std::forward<Args>( args )... );
+    }
+    template <typename... Args>
+    void warn( Args&& ... args ) {
+        log( level::warn, std::forward<Args>( args )... );
+    }
+    template <typename... Args>
+    void error( Args&& ... args ) {
+        log( level::error, std::forward<Args>( args )... );
+    }
+    template <typename... Args>
+    void fatal( Args&& ... args ) {
+        log( level::fatal, std::forward<Args>( args )... );
+    }
+
+    template <typename... Args>
+    void debugf( const std::string& fmt, Args&& ... args ) {
+        logf( level::debug, fmt, std::forward<Args>( args )... );
+    }
+    template <typename... Args>
+    void notef( const std::string& fmt, Args&& ... args ) {
+        logf( level::note, fmt, std::forward<Args>( args )... );
+    }
+    template <typename... Args>
+    void warnf( const std::string& fmt, Args&& ... args ) {
+        logf( level::warn, fmt, std::forward<Args>( args )... );
+    }
+    template <typename... Args>
+    void errorf( const std::string& fmt, Args&& ... args ) {
+        logf( level::error, fmt, std::forward<Args>( args )... );
+    }
+    template <typename... Args>
+    void fatalf( const std::string& fmt, Args&& ... args ) {
+        logf( level::fatal, fmt, std::forward<Args>( args )... );
+    }
+
+}