Adding updated logging system similar to log4
Updates to ssh client Updated reflect enum
This commit is contained in:
parent
b7f1f7bdc7
commit
71ea16cf8b
15 changed files with 657 additions and 16 deletions
|
|
@ -49,6 +49,9 @@ include_directories( ${OPENSSL_INCLUDE_DIR} )
|
|||
include_directories( include )
|
||||
|
||||
set( sources
|
||||
src/logger.cpp
|
||||
src/appender.cpp
|
||||
src/logger_config.cpp
|
||||
src/ssh.cpp
|
||||
src/url.cpp
|
||||
src/process.cpp
|
||||
|
|
@ -105,6 +108,8 @@ setup_library( fc SOURCES ${sources} )
|
|||
#setup_executable( json_rpc_test SOURCES tests/json_rpc_test.cpp LIBRARIES fc ${ZLIB_LIBRARY} ${pthread_library} ${rt_library} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ${Boost_DATE_TIME_LIBRARY})
|
||||
#setup_executable( ssh_test SOURCES tests/ssh.cpp LIBRARIES fc ${pthread_library} ${rt_library} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ssh2 ${OPENSSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} ${ZLIB_LIBRARY} ${ALL_OPENSSL_LIBRARIES} ${Boost_DATE_TIME_LIBRARY})
|
||||
|
||||
setup_executable( logger_test SOURCES tests/logger.cpp LIBRARIES fc ${pthread_library} ${rt_library} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ssh2 ${OPENSSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} ${ZLIB_LIBRARY} ${ALL_OPENSSL_LIBRARIES} ${Boost_DATE_TIME_LIBRARY})
|
||||
|
||||
#add_executable( test_vec tests/vector_test.cpp )
|
||||
#target_link_libraries( test_vec fc ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} )
|
||||
|
||||
|
|
|
|||
43
include/fc/appender.hpp
Normal file
43
include/fc/appender.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
#include <fc/shared_ptr.hpp>
|
||||
|
||||
namespace fc {
|
||||
class appender;
|
||||
class log_message;
|
||||
class value;
|
||||
class string;
|
||||
|
||||
class appender_factory : public fc::retainable {
|
||||
public:
|
||||
typedef fc::shared_ptr<appender_factory> ptr;
|
||||
|
||||
virtual ~appender_factory(){};
|
||||
virtual fc::shared_ptr<appender> create( const value& args ) = 0;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
class appender_factory_impl : public appender_factory {
|
||||
public:
|
||||
virtual fc::shared_ptr<appender> create( const value& args ) {
|
||||
return fc::shared_ptr<appender>(new T(args));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class appender : public fc::retainable {
|
||||
public:
|
||||
typedef fc::shared_ptr<appender> ptr;
|
||||
|
||||
template<typename T>
|
||||
static bool register_appender(const fc::string& type) {
|
||||
return register_appender( type, new detail::appender_factory_impl<T>() );
|
||||
}
|
||||
|
||||
static appender::ptr create( const fc::string& name, const fc::string& type, const value& args );
|
||||
static appender::ptr get( const fc::string& name );
|
||||
static bool register_appender( const fc::string& type, const appender_factory::ptr& f );
|
||||
|
||||
virtual void log( const log_message& m ) = 0;
|
||||
};
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ namespace fc {
|
|||
fc::path parent_path()const;
|
||||
fc::string string()const;
|
||||
fc::string generic_string()const;
|
||||
|
||||
bool is_relative()const;
|
||||
bool is_absolute()const;
|
||||
private:
|
||||
|
|
|
|||
138
include/fc/logger.hpp
Normal file
138
include/fc/logger.hpp
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
#pragma once
|
||||
#include <fc/value.hpp>
|
||||
#include <fc/string.hpp>
|
||||
#include <fc/time.hpp>
|
||||
#include <fc/shared_ptr.hpp>
|
||||
|
||||
|
||||
namespace fc {
|
||||
|
||||
struct log_level {
|
||||
enum type {
|
||||
all, trace, debug, info, warn, error, fatal, off
|
||||
};
|
||||
};
|
||||
|
||||
struct log_message {
|
||||
log_message(log_level::type, const string& file, int line, const string& func, const string& format );
|
||||
log_message();
|
||||
|
||||
otime_point when;
|
||||
log_level::type level;
|
||||
ostring context;
|
||||
ostring thread;
|
||||
ostring fiber;
|
||||
string file;
|
||||
int line;
|
||||
string method;
|
||||
string format;
|
||||
value args;
|
||||
ovalue meta;
|
||||
|
||||
// key based args
|
||||
log_message& operator()( const string& arg, value&& v );
|
||||
log_message& operator()( const string& arg, const value& v );
|
||||
// position based args...
|
||||
log_message& operator()( value&& v );
|
||||
log_message& operator()( const value& v );
|
||||
};
|
||||
|
||||
class appender;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
@code
|
||||
void my_class::func()
|
||||
{
|
||||
fc_dlog( my_class_logger, "Format four: ${arg} five: ${five}", ("arg",4)("five",5) );
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
class logger {
|
||||
public:
|
||||
static logger get( const fc::string& name = "default");
|
||||
|
||||
logger();
|
||||
logger( const string& name, const logger& parent = nullptr );
|
||||
logger( std::nullptr_t );
|
||||
logger( const logger& c );
|
||||
logger( logger&& c );
|
||||
~logger();
|
||||
logger& operator=(const logger&);
|
||||
logger& operator=(logger&&);
|
||||
friend bool operator==( const logger&, std::nullptr_t );
|
||||
friend bool operator!=( const logger&, std::nullptr_t );
|
||||
|
||||
logger& set_log_level( log_level::type e );
|
||||
log_level::type get_log_level()const;
|
||||
logger& set_parent( const logger& l );
|
||||
logger get_parent()const;
|
||||
|
||||
void set_name( const fc::string& n );
|
||||
const fc::string& name()const;
|
||||
|
||||
void add_appender( const fc::shared_ptr<appender>& a );
|
||||
|
||||
|
||||
bool is_enabled( log_level::type e )const;
|
||||
void log( log_message m );
|
||||
|
||||
private:
|
||||
class impl;
|
||||
fc::shared_ptr<impl> my;
|
||||
};
|
||||
|
||||
/**
|
||||
* This helper class is used to automatically print a log message
|
||||
* once upon construction, and again upon destruction and is therefore
|
||||
* helpful in catching scope changes.
|
||||
struct tracer {
|
||||
tracer( const logger::ptr& lgr );
|
||||
~tracer();
|
||||
|
||||
void set_message( log_message&& ms g);
|
||||
|
||||
private:
|
||||
logger::ptr logger;
|
||||
log_message msg;
|
||||
};
|
||||
*/
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#include <fc/reflect.hpp>
|
||||
FC_REFLECT( fc::log_message, (when)(level)(context)(thread)(method)(file)(line)(format)(args)(meta) )
|
||||
FC_REFLECT_ENUM( fc::log_level::type, (all)(trace)(debug)(info)(warn)(error)(fatal)(off) )
|
||||
|
||||
#define fc_scope_log( LOGGER, FORMAT, ... ) \
|
||||
fc::tracer __tracer; \
|
||||
if( (LOGGER).is_enabled( fc::log_level::trace ) ) { \
|
||||
__tracer.set_message( fc::log_message( fc::log_level::trace, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\
|
||||
}
|
||||
|
||||
#define fc_dlog( LOGGER, FORMAT, ... ) \
|
||||
if( (LOGGER).is_enabled( fc::log_level::debug ) ) { \
|
||||
(LOGGER).log( fc::log_message( fc::log_level::debug, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\
|
||||
}
|
||||
|
||||
#define fc_ilog( LOGGER, FORMAT, ... ) \
|
||||
if( (LOGGER).is_enabled( fc::log_level::info ) ) { \
|
||||
(LOGGER).log( fc::log_message( fc::log_level::info, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\
|
||||
}
|
||||
|
||||
#define fc_wlog( LOGGER, FORMAT, ... ) \
|
||||
if( (LOGGER).is_enabled( fc::log_level::warn ) ) { \
|
||||
(LOGGER).log( fc::log_message( fc::log_level::warn, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\
|
||||
}
|
||||
|
||||
#define fc_elog( LOGGER, FORMAT, ... ) \
|
||||
if( (LOGGER).is_enabled( fc::log_level::error ) ) { \
|
||||
(LOGGER).log( fc::log_message( fc::log_level::error, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\
|
||||
}
|
||||
|
||||
#define fc_flog( LOGGER, FORMAT, ... ) \
|
||||
if( (LOGGER).is_enabled( fc::log_level::fatal ) ) { \
|
||||
(LOGGER).log( fc::log_message( fc::log_level::fatal, __FILE__, __LINE__, __func__, FORMAT ) __VA_ARGS__ );\
|
||||
}
|
||||
|
||||
41
include/fc/logger_config.hpp
Normal file
41
include/fc/logger_config.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
#include <fc/logger.hpp>
|
||||
|
||||
namespace fc {
|
||||
class path;
|
||||
struct appender_config {
|
||||
appender_config(const fc::string& n="",const fc::string& t="", const value& a=value())
|
||||
:name(n),type(t),args(a),enabled(true){}
|
||||
string name;
|
||||
string type;
|
||||
value args;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct logger_config {
|
||||
logger_config(const fc::string& n=""):name(n),enabled(true),additivity(false){}
|
||||
string name;
|
||||
ostring parent;
|
||||
/// if not set, then parents level is used.
|
||||
fc::optional<log_level::type> level;
|
||||
bool enabled;
|
||||
/// if any appenders are sepecified, then parent's appenders are not set.
|
||||
bool additivity;
|
||||
fc::vector<string> appenders;
|
||||
};
|
||||
|
||||
struct logging_config {
|
||||
static logging_config default_config();
|
||||
fc::vector<string> includes;
|
||||
fc::vector<appender_config> appenders;
|
||||
fc::vector<logger_config> loggers;
|
||||
};
|
||||
|
||||
void configure_logging( const fc::path& log_config );
|
||||
bool configure_logging( const logging_config& l );
|
||||
}
|
||||
|
||||
#include <fc/reflect.hpp>
|
||||
FC_REFLECT( fc::appender_config, (name)(type)(args)(enabled) )
|
||||
FC_REFLECT( fc::logger_config, (name)(parent)(level)(enabled)(additivity)(appenders) )
|
||||
FC_REFLECT( fc::logging_config, (includes)(appenders)(loggers) )
|
||||
|
|
@ -105,13 +105,13 @@ void fc::reflector<TYPE>::visit( const Visitor& v ) { \
|
|||
#endif // DOXYGEN
|
||||
|
||||
|
||||
#define FC_REFLECT_VISIT_ENUM( r, visitor, elem ) \
|
||||
visitor.TEMPLATE operator()<elem>(BOOST_PP_STRINGIZE(elem));
|
||||
#define FC_REFLECT_ENUM_TO_STRING( r, visitor, elem ) \
|
||||
case elem: return BOOST_PP_STRINGIZE(elem);
|
||||
#define FC_REFLECT_VISIT_ENUM( r, enum_type, elem ) \
|
||||
v.TEMPLATE operator()<enum_type::elem>(BOOST_PP_STRINGIZE(elem));
|
||||
#define FC_REFLECT_ENUM_TO_STRING( r, enum_type, elem ) \
|
||||
case enum_type::elem: return BOOST_PP_STRINGIZE(elem);
|
||||
|
||||
#define FC_REFLECT_ENUM_FROM_STRING( r, visitor, elem ) \
|
||||
if( strcmp( s, BOOST_PP_STRINGIZE(elem) ) == 0 ) return elem;
|
||||
#define FC_REFLECT_ENUM_FROM_STRING( r, enum_type, elem ) \
|
||||
if( strcmp( s, BOOST_PP_STRINGIZE(elem) ) == 0 ) return enum_type::elem;
|
||||
|
||||
#define FC_REFLECT_ENUM( ENUM, FIELDS ) \
|
||||
namespace fc { \
|
||||
|
|
@ -120,18 +120,21 @@ template<> struct reflector<ENUM> { \
|
|||
typedef fc::true_type is_enum; \
|
||||
template<typename Visitor> \
|
||||
static inline void visit( const Visitor& v ) { \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_ENUM, v, FIELDS ) \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_ENUM, ENUM, FIELDS ) \
|
||||
}\
|
||||
static const char* to_string(int64_t i) { \
|
||||
switch( ENUM(i) ) { \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_TO_STRING, v, FIELDS ) \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_TO_STRING, ENUM, FIELDS ) \
|
||||
default: \
|
||||
FC_THROW_MSG( "Unknown field %s not in enum '%s'", i, BOOST_PP_STRINGIZE(ENUM) ); \
|
||||
FC_THROW_REPORT( "Unknown field ${field} not in enum ${enum}", \
|
||||
fc::value().set("field",i).set("enum",BOOST_PP_STRINGIZE(ENUM)) ); \
|
||||
}\
|
||||
return nullptr; \
|
||||
} \
|
||||
static ENUM from_string( const char* s ) { \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_FROM_STRING, v, FIELDS ) \
|
||||
FC_THROW_MSG( "Unknown field %s not in enum '%s'", s, BOOST_PP_STRINGIZE(ENUM) ); \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_FROM_STRING, ENUM, FIELDS ) \
|
||||
FC_THROW_REPORT( "Unknown field ${field} not in enum ${enum}", \
|
||||
fc::value().set("field",s).set("enum",BOOST_PP_STRINGIZE(ENUM)) ); \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,16 @@ namespace fc {
|
|||
void scp_send( const fc::path& local_path, const fc::path& remote_path,
|
||||
std::function<bool(size_t,size_t)> progress = [](size_t,size_t){return true;} );
|
||||
|
||||
/**
|
||||
* @brief recursively sends the contents of local_dir to the remote_path
|
||||
*
|
||||
* If remote_path ends in '/' then a new directory at <code>remote_path/local_dir.filename()</code> will
|
||||
* be created, otherwise <code>local_dir / *</code> will be copied to <code>remote_path / *</code>
|
||||
*
|
||||
* Progress will be reported as total bytes transferred for all files.
|
||||
*/
|
||||
void scp_send_dir( const fc::path& local_dir, const fc::path& remote_path,
|
||||
std::function<bool(size_t,size_t)> progress = [](size_t,size_t){return true;} );
|
||||
|
||||
/**
|
||||
* @pre remote_path is not a directory
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <fc/vector.hpp>
|
||||
#include <fc/aligned.hpp>
|
||||
#include <fc/typename.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
|
@ -131,7 +132,8 @@ namespace fc {
|
|||
/** array interface **/
|
||||
void resize( size_t s );
|
||||
void reserve( size_t s );
|
||||
void push_back( value&& v );
|
||||
value& push_back( value&& v );
|
||||
value& push_back( const value& v );
|
||||
value& operator[]( int32_t idx );
|
||||
const value& operator[]( int32_t idx )const;
|
||||
|
||||
|
|
@ -163,6 +165,7 @@ namespace fc {
|
|||
|
||||
aligned<40> holder;
|
||||
};
|
||||
typedef fc::optional<value> ovalue;
|
||||
bool operator == ( const value& v, std::nullptr_t );
|
||||
bool operator != ( const value& v, std::nullptr_t );
|
||||
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ namespace fc {
|
|||
v = fc::reflector<T>::from_string( fc::value_cast<fc::string>(jsv).c_str() );
|
||||
} else {
|
||||
// throw if invalid int, by attempting to convert to string
|
||||
fc::reflector<T>::to_string( v = value_cast<int64_t>(jsv) );
|
||||
fc::reflector<T>::to_string( v = static_cast<T>(value_cast<int64_t>(jsv)) );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
146
src/appender.cpp
Normal file
146
src/appender.cpp
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
#include <fc/appender.hpp>
|
||||
#include <fc/logger.hpp>
|
||||
#include <fc/value.hpp>
|
||||
#include <fc/unique_lock.hpp>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <fc/spin_lock.hpp>
|
||||
#include <fc/scoped_lock.hpp>
|
||||
#include <fc/console_defines.h>
|
||||
#include <fc/log.hpp>
|
||||
#include <fc/value_cast.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace fc {
|
||||
|
||||
static fc::spin_lock appender_spinlock;
|
||||
std::unordered_map<std::string,appender::ptr>& get_appender_map() {
|
||||
static std::unordered_map<std::string,appender::ptr> lm;
|
||||
return lm;
|
||||
}
|
||||
std::unordered_map<std::string,appender_factory::ptr>& get_appender_factory_map() {
|
||||
static std::unordered_map<std::string,appender_factory::ptr> lm;
|
||||
return lm;
|
||||
}
|
||||
appender::ptr appender::get( const fc::string& s ) {
|
||||
scoped_lock<spin_lock> lock(appender_spinlock);
|
||||
return get_appender_map()[s];
|
||||
}
|
||||
bool appender::register_appender( const fc::string& type, const appender_factory::ptr& f )
|
||||
{
|
||||
get_appender_factory_map()[type] = f;
|
||||
return true;
|
||||
}
|
||||
appender::ptr appender::create( const fc::string& name, const fc::string& type, const value& args )
|
||||
{
|
||||
auto fact_itr = get_appender_factory_map().find(type);
|
||||
if( fact_itr == get_appender_factory_map().end() ) {
|
||||
wlog( "Unknown appender type '%s'", type.c_str() );
|
||||
return appender::ptr();
|
||||
}
|
||||
auto ap = fact_itr->second->create( args );
|
||||
get_appender_map()[name] = ap;
|
||||
return ap;
|
||||
}
|
||||
|
||||
class console_appender : public appender{
|
||||
public:
|
||||
struct color {
|
||||
enum type {
|
||||
red,
|
||||
green,
|
||||
brown,
|
||||
blue,
|
||||
magenta,
|
||||
cyan,
|
||||
white,
|
||||
console_default,
|
||||
};
|
||||
};
|
||||
struct stream { enum type { std_out, std_error }; };
|
||||
|
||||
struct level_color {
|
||||
level_color( log_level::type l=log_level::all,
|
||||
color::type c=color::console_default )
|
||||
:level(l),color(c){}
|
||||
|
||||
log_level::type level;
|
||||
console_appender::color::type color;
|
||||
};
|
||||
|
||||
struct config {
|
||||
config()
|
||||
:format( "${when} ${thread} ${context} ${file}:${line} ${method} ${level}] ${message}" ),
|
||||
stream(console_appender::stream::std_error),flush(true){}
|
||||
|
||||
fc::string format;
|
||||
console_appender::stream::type stream;
|
||||
fc::vector<level_color> level_colors;
|
||||
bool flush;
|
||||
};
|
||||
|
||||
config cfg;
|
||||
color::type lc[log_level::off+1];
|
||||
|
||||
console_appender( const value& args );
|
||||
const char* get_color(color::type t ) {
|
||||
switch( t ) {
|
||||
case color::red: return CONSOLE_RED;
|
||||
case color::green: return CONSOLE_GREEN;
|
||||
case color::brown: return CONSOLE_BROWN;
|
||||
case color::blue: return CONSOLE_BLUE;
|
||||
case color::magenta: return CONSOLE_MAGENTA;
|
||||
case color::cyan: return CONSOLE_CYAN;
|
||||
case color::white: return CONSOLE_WHITE;
|
||||
case color::console_default:
|
||||
default:
|
||||
return CONSOLE_DEFAULT;
|
||||
}
|
||||
}
|
||||
const char* get_color( log_level::type l ) {
|
||||
return get_color( lc[l] );
|
||||
}
|
||||
|
||||
virtual void log( const log_message& m ) {
|
||||
fc::string message = fc::substitute( m.format, m.args );
|
||||
fc::value lmsg(m);
|
||||
|
||||
FILE* out = stream::std_error ? stderr : stdout;
|
||||
fc::string fmt_str = fc::substitute( cfg.format, value(m).set( "message", message) );
|
||||
|
||||
fc::unique_lock<boost::mutex> lock(log_mutex());
|
||||
#ifndef WIN32
|
||||
if(isatty(fileno(out))) fprintf( out, "\r%s", get_color( m.level ) );
|
||||
#endif
|
||||
|
||||
fprintf( out, "%s", fmt_str.c_str() );
|
||||
|
||||
#ifndef WIN32
|
||||
if(isatty(fileno(out))) fprintf( out, "\r%s", CONSOLE_DEFAULT );
|
||||
#endif
|
||||
fprintf( out, "\n" );
|
||||
if( cfg.flush ) fflush( out );
|
||||
}
|
||||
};
|
||||
} // namespace fc
|
||||
|
||||
FC_REFLECT_ENUM( fc::console_appender::stream::type, (std_out)(std_error) )
|
||||
FC_REFLECT_ENUM( fc::console_appender::color::type, (red)(green)(brown)(blue)(magenta)(cyan)(white)(console_default) )
|
||||
FC_REFLECT( fc::console_appender::level_color, (level)(color) )
|
||||
FC_REFLECT( fc::console_appender::config, (format)(stream)(level_colors)(flush) )
|
||||
|
||||
namespace fc {
|
||||
console_appender::console_appender( const value& args ) {
|
||||
cfg = fc::value_cast<config>(args);
|
||||
for( int i = 0; i < log_level::off+1; ++i )
|
||||
lc[i] = color::console_default;
|
||||
for( auto itr = cfg.level_colors.begin(); itr != cfg.level_colors.end(); ++itr )
|
||||
lc[itr->level] = itr->color;
|
||||
}
|
||||
|
||||
static bool reg_console_appender = appender::register_appender<console_appender>( "console" );
|
||||
} // namespace fc
|
||||
110
src/logger.cpp
Normal file
110
src/logger.cpp
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
#include <fc/logger.hpp>
|
||||
#include <fc/thread.hpp>
|
||||
#include <fc/spin_lock.hpp>
|
||||
#include <fc/scoped_lock.hpp>
|
||||
#include <fc/appender.hpp>
|
||||
#include <fc/filesystem.hpp>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
// tmp...
|
||||
#include <fc/json.hpp>
|
||||
|
||||
namespace fc {
|
||||
log_message::log_message(){}
|
||||
log_message::log_message(log_level::type ll, const string& f, int l, const string& fun, const string& fmt )
|
||||
:when( fc::time_point::now() ), level(ll), thread( fc::thread::current().name() ),file(fc::path(f).filename().generic_string()),line(l),method(fun),format(fmt){}
|
||||
|
||||
log_message& log_message::operator()( const fc::string& k, fc::value&& v ) {
|
||||
args[k] = fc::move(v);
|
||||
return *this;
|
||||
}
|
||||
log_message& log_message::operator()( fc::value&& v ) {
|
||||
args.push_back( fc::move(v) );
|
||||
return *this;
|
||||
}
|
||||
log_message& log_message::operator()( const fc::string& k, const fc::value& v ) {
|
||||
args[k] = v;
|
||||
return *this;
|
||||
}
|
||||
log_message& log_message::operator()( const fc::value& v ) {
|
||||
args.push_back( v );
|
||||
return *this;
|
||||
}
|
||||
|
||||
class logger::impl : public fc::retainable {
|
||||
public:
|
||||
impl()
|
||||
:_parent(nullptr),_enabled(true),_level(log_level::warn){}
|
||||
fc::string _name;
|
||||
logger _parent;
|
||||
bool _enabled;
|
||||
bool _additivity;
|
||||
log_level::type _level;
|
||||
|
||||
fc::vector<appender::ptr> _appenders;
|
||||
};
|
||||
|
||||
|
||||
logger::logger()
|
||||
:my( new impl() ){}
|
||||
|
||||
logger::logger(std::nullptr_t){}
|
||||
|
||||
logger::logger( const logger& l )
|
||||
:my(l.my){}
|
||||
|
||||
logger::logger( logger&& l )
|
||||
:my(fc::move(l.my)){}
|
||||
|
||||
logger::~logger(){}
|
||||
|
||||
logger& logger::operator=( const logger& l ){
|
||||
my = l.my;
|
||||
return *this;
|
||||
}
|
||||
logger& logger::operator=( logger&& l ){
|
||||
fc_swap(my,l.my);
|
||||
return *this;
|
||||
}
|
||||
bool operator==( const logger& l, std::nullptr_t ) { return !l.my; }
|
||||
bool operator!=( const logger& l, std::nullptr_t ) { return l.my; }
|
||||
|
||||
bool logger::is_enabled( log_level::type e )const {
|
||||
return e >= my->_level;
|
||||
}
|
||||
|
||||
void logger::log( log_message m ) {
|
||||
m.context = my->_name;
|
||||
for( auto itr = my->_appenders.begin(); itr != my->_appenders.end(); ++itr )
|
||||
(*itr)->log( m );
|
||||
|
||||
if( my->_additivity && my->_parent != nullptr) {
|
||||
my->_parent.log(m);
|
||||
}
|
||||
}
|
||||
void logger::set_name( const fc::string& n ) { my->_name = n; }
|
||||
const fc::string& logger::name()const { return my->_name; }
|
||||
|
||||
static fc::spin_lock logger_spinlock;
|
||||
std::unordered_map<std::string,logger>& get_logger_map() {
|
||||
static std::unordered_map<std::string,logger> lm;
|
||||
return lm;
|
||||
}
|
||||
|
||||
logger logger::get( const fc::string& s ) {
|
||||
scoped_lock<spin_lock> lock(logger_spinlock);
|
||||
return get_logger_map()[s];
|
||||
}
|
||||
|
||||
logger logger::get_parent()const { return my->_parent; }
|
||||
logger& logger::set_parent(const logger& p) { my->_parent = p; return *this; }
|
||||
|
||||
log_level::type logger::get_log_level()const { return my->_level; }
|
||||
logger& logger::set_log_level(log_level::type ll) { my->_level = ll; return *this; }
|
||||
|
||||
void logger::add_appender( const fc::shared_ptr<appender>& a )
|
||||
{ my->_appenders.push_back(a); }
|
||||
|
||||
|
||||
} // namespace fc
|
||||
77
src/logger_config.cpp
Normal file
77
src/logger_config.cpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include <fc/logger_config.hpp>
|
||||
#include <fc/appender.hpp>
|
||||
#include <fc/json.hpp>
|
||||
#include <fc/filesystem.hpp>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
namespace fc {
|
||||
std::unordered_map<std::string,logger>& get_logger_map();
|
||||
std::unordered_map<std::string,appender::ptr>& get_appender_map();
|
||||
|
||||
void configure_logging( const fc::path& lc )
|
||||
{
|
||||
configure_logging( fc::json::from_file<logging_config>(lc) );
|
||||
}
|
||||
bool configure_logging( const logging_config& cfg )
|
||||
{
|
||||
get_logger_map().clear();
|
||||
get_appender_map().clear();
|
||||
|
||||
slog( "\n%s", fc::json::to_pretty_string(cfg).c_str() );
|
||||
for( size_t i = 0; i < cfg.appenders.size(); ++i ) {
|
||||
appender::create( cfg.appenders[i].name, cfg.appenders[i].type, cfg.appenders[i].args );
|
||||
// TODO... process enabled
|
||||
}
|
||||
for( size_t i = 0; i < cfg.loggers.size(); ++i ) {
|
||||
auto lgr = logger::get( cfg.loggers[i].name );
|
||||
|
||||
// TODO: configure logger here...
|
||||
lgr.set_name(cfg.loggers[i].name);
|
||||
lgr.set_log_level( *cfg.loggers[i].level );
|
||||
|
||||
|
||||
for( auto a = cfg.loggers[i].appenders.begin();
|
||||
a != cfg.loggers[i].appenders.end(); ++a ){
|
||||
auto ap = appender::get( *a );
|
||||
if( ap ) { lgr.add_appender(ap); }
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
logging_config logging_config::default_config() {
|
||||
slog( "default cfg" );
|
||||
logging_config cfg;
|
||||
cfg.appenders.push_back(
|
||||
appender_config( "stderr", "console",
|
||||
fc::value()
|
||||
.set( "stream","std_error")
|
||||
.set( "level_colors",
|
||||
fc::value().push_back( fc::value().set( "level","debug").set("color", "green") )
|
||||
.push_back( fc::value().set( "level","warn").set("color", "brown") )
|
||||
.push_back( fc::value().set( "level","error").set("color", "red") )
|
||||
.push_back( fc::value().set( "level","fatal").set("color", "red") )
|
||||
)
|
||||
) );
|
||||
cfg.appenders.push_back(
|
||||
appender_config( "stdout", "console",
|
||||
fc::value()
|
||||
.set( "stream","std_out")
|
||||
.set( "level_colors",
|
||||
fc::value().push_back( fc::value().set( "level","debug").set("color", "green") )
|
||||
.push_back( fc::value().set( "level","warn").set("color", "brown") )
|
||||
.push_back( fc::value().set( "level","error").set("color", "red") )
|
||||
.push_back( fc::value().set( "level","fatal").set("color", "red") )
|
||||
)
|
||||
) );
|
||||
|
||||
logger_config dlc;
|
||||
dlc.name = "default";
|
||||
dlc.level = log_level::debug;
|
||||
dlc.appenders.push_back("stderr");
|
||||
cfg.loggers.push_back( dlc );
|
||||
return cfg;
|
||||
}
|
||||
static bool do_default_config = configure_logging( logging_config::default_config() );
|
||||
}
|
||||
43
src/ssh.cpp
43
src/ssh.cpp
|
|
@ -450,8 +450,41 @@ namespace fc { namespace ssh {
|
|||
return ssh::process( *this, cmd, pty_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo implement progress reporting.
|
||||
*/
|
||||
void client::scp_send_dir( const fc::path& local_dir, const fc::path& remote_path,
|
||||
std::function<bool(size_t,size_t)> progress )
|
||||
{
|
||||
fc::path remote_dir = remote_path;
|
||||
if( remote_dir.filename() == fc::path(".") )
|
||||
remote_dir /= local_dir.filename();
|
||||
|
||||
slog( "scp -r %s %s", local_dir.generic_string().c_str(), remote_dir.generic_string().c_str() );
|
||||
create_directories( remote_dir );
|
||||
|
||||
directory_iterator ditr(local_dir);
|
||||
directory_iterator dend;
|
||||
|
||||
while( ditr != dend ) {
|
||||
if( (*ditr).filename() == "." ||
|
||||
(*ditr).filename() == ".." )
|
||||
{ }
|
||||
else if( fc::is_directory(*ditr) )
|
||||
{
|
||||
scp_send_dir( (*ditr), remote_dir / (*ditr).filename() );
|
||||
} else if( fc::is_regular_file(*ditr) ) {
|
||||
scp_send( *ditr, remote_dir / (*ditr).filename() );
|
||||
} else {
|
||||
wlog( "Skipping %s", fc::canonical(*ditr).generic_string().c_str() );
|
||||
}
|
||||
++ditr;
|
||||
}
|
||||
}
|
||||
|
||||
void client::scp_send( const fc::path& local_path, const fc::path& remote_path,
|
||||
std::function<bool(size_t,size_t)> progress ) {
|
||||
slog( "scp %s %s", local_path.generic_string().c_str(), remote_path.generic_string().c_str() );
|
||||
/**
|
||||
* Tests have shown that if one scp is 'blocked' by a need to read (presumably to
|
||||
* ack recv for the trx window), and then a second transfer begins that the first
|
||||
|
|
@ -471,15 +504,21 @@ namespace fc { namespace ssh {
|
|||
}
|
||||
|
||||
// memory map the file
|
||||
file_mapping fmap( local_path.string().c_str(), read_only );
|
||||
size_t fsize = file_size(local_path);
|
||||
|
||||
if( fsize == 0 ) {
|
||||
// TODO: handle empty file case
|
||||
if( progress ) progress(0,0);
|
||||
return;
|
||||
}
|
||||
file_mapping fmap( local_path.string().c_str(), read_only );
|
||||
mapped_region mr( fmap, fc::read_only, 0, fsize );
|
||||
|
||||
LIBSSH2_CHANNEL* chan = 0;
|
||||
time_t now;
|
||||
memset( &now, 0, sizeof(now) );
|
||||
|
||||
// TODO: preserve creation / modification date
|
||||
// TODO: perserve permissions / exec bit?
|
||||
chan = libssh2_scp_send64( my->session, remote_path.generic_string().c_str(), 0700, fsize, now, now );
|
||||
while( chan == 0 ) {
|
||||
char* msg;
|
||||
|
|
|
|||
|
|
@ -391,8 +391,21 @@ void value::resize( size_t s ) {
|
|||
void value::reserve( size_t s ) {
|
||||
gh(holder)->reserve(s);
|
||||
}
|
||||
void value::push_back( value&& v ) {
|
||||
value& value::push_back( value&& v ) {
|
||||
if (strcmp(gh(holder)->type(), "void" ) == 0 ) {
|
||||
new (gh(holder)) detail::value_holder_impl<value::array>(value::array());
|
||||
return push_back( fc::move(v) );
|
||||
}
|
||||
gh(holder)->push_back(fc::move(v));
|
||||
return *this;
|
||||
}
|
||||
value& value::push_back( const value& v ) {
|
||||
if (strcmp(gh(holder)->type(), "void" ) == 0 ) {
|
||||
new (gh(holder)) detail::value_holder_impl<value::array>(value::array());
|
||||
return push_back( v );
|
||||
}
|
||||
gh(holder)->push_back(value(v));
|
||||
return *this;
|
||||
}
|
||||
value& value::operator[]( int32_t idx ) {
|
||||
return gh(holder)->at(idx);
|
||||
|
|
|
|||
12
tests/logger.cpp
Normal file
12
tests/logger.cpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include <fc/logger_config.hpp>
|
||||
|
||||
int main( int argc, char** argv ) {
|
||||
auto lgr = fc::logger::get();
|
||||
fc::configure_logging( fc::logging_config::default_config() );
|
||||
fc_dlog( lgr, "Hello Debug" );
|
||||
fc_ilog( lgr, "Hello Info" );
|
||||
fc_wlog( lgr, "Hello Warn" );
|
||||
fc_elog( lgr, "Hello Error" );
|
||||
fc_flog( lgr, "Hello Fatal" );
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue