| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "YAMLLog4cppConfiguratorImpl.hh" | ||
| 2 | #include "na64util/streambuf-redirect.hh" | ||
| 3 | #include "na64util/uri.hh" | ||
| 4 | |||
| 5 | #include <cassert> | ||
| 6 | //#include <iostream> | ||
| 7 | |||
| 8 | namespace na64dp { | ||
| 9 | namespace util { | ||
| 10 | |||
| 11 | // aux: returns category name from path tokens | ||
| 12 | static std::string | ||
| 13 | ✗ | _cat_name_from_ptoks( const std::list<std::string> & catNames ) { | |
| 14 | ✗ | std::string catPath; | |
| 15 | ✗ | for( auto ptok : catNames ) { | |
| 16 | ✗ | if( !catPath.empty() ) catPath += "."; | |
| 17 | ✗ | catPath += ptok; | |
| 18 | } | ||
| 19 | ✗ | return catPath; | |
| 20 | } | ||
| 21 | |||
| 22 | // aux function recursively creating categories from YAML node | ||
| 23 | void | ||
| 24 | ✗ | YAMLLog4cppConfiguratorImpl::_configure_category_from_YAML( const YAML::Node & catCfg | |
| 25 | , log4cpp::Category & cat | ||
| 26 | , std::list<std::string> & catNames | ||
| 27 | ) { | ||
| 28 | ✗ | log4cpp::Priority::Value priority = log4cpp::Priority::NOTSET; | |
| 29 | ✗ | bool additivity = true; | |
| 30 | ✗ | for( const auto & catEntry : catCfg ) { | |
| 31 | ✗ | std::string catParName = catEntry.first.as<std::string>(); | |
| 32 | ✗ | if( "_threshold" == catParName ) { | |
| 33 | priority | ||
| 34 | ✗ | = log4cpp::Priority::getPriorityValue(catEntry.second.as<std::string>()); | |
| 35 | ✗ | continue; | |
| 36 | } | ||
| 37 | ✗ | if( "_appenders" == catParName ) { | |
| 38 | ✗ | assert( catEntry.second.IsSequence() ); // TODO | |
| 39 | ✗ | for( auto appenderName : catEntry.second ) { | |
| 40 | ✗ | auto appIt = appenders.find( appenderName.as<std::string>() ); | |
| 41 | ✗ | if(appenders.end() == appIt) { | |
| 42 | std::cerr << "Can not associate category \"" | ||
| 43 | ✗ | << _cat_name_from_ptoks(catNames) | |
| 44 | << "\" with appender \"" | ||
| 45 | ✗ | << appenderName.as<std::string>() | |
| 46 | ✗ | << "\"" | |
| 47 | ✗ | << std::endl; | |
| 48 | ✗ | continue; // TODO: error on missed appender? | |
| 49 | } | ||
| 50 | ✗ | cat.addAppender(*(appIt->second)); | |
| 51 | // ^^^ NOTE: there are two kinds of this method in Category. | ||
| 52 | // Passing appender by ptr makes the category instance own the | ||
| 53 | // appender while passing by reference makes weak association | ||
| 54 | } | ||
| 55 | ✗ | continue; | |
| 56 | } | ||
| 57 | ✗ | if( "_additivity" == catParName ) { | |
| 58 | ✗ | additivity = catEntry.second.as<bool>(); | |
| 59 | ✗ | continue; | |
| 60 | } | ||
| 61 | // otherwise, the `catParName' contains the sub-category name | ||
| 62 | ✗ | catNames.push_back(catParName); { | |
| 63 | ✗ | std::string catPath = _cat_name_from_ptoks(catNames); | |
| 64 | ✗ | if( log4cpp::Category::exists(catPath) ) { | |
| 65 | std::cerr << "Warning: re-configuring logging category \"" | ||
| 66 | ✗ | << catPath << "\" that already was in use." << std::endl; | |
| 67 | } | ||
| 68 | // ^^^ this is really an assertion. Category must not exist | ||
| 69 | // before first invocation of creating `getInstance' func. | ||
| 70 | ✗ | _configure_category_from_YAML( | |
| 71 | ✗ | catEntry.second | |
| 72 | , log4cpp::Category::getInstance(catPath) | ||
| 73 | , catNames | ||
| 74 | ); | ||
| 75 | ✗ | } catNames.pop_back(); | |
| 76 | } | ||
| 77 | ✗ | cat.setPriority(priority); | |
| 78 | ✗ | cat.setAdditivity(additivity); | |
| 79 | } | ||
| 80 | |||
| 81 | static void | ||
| 82 | ✗ | _configure_std_streams(const YAML::Node & cfg) { | |
| 83 | ✗ | if( cfg["cout"] ) { | |
| 84 | int defaultLevel | ||
| 85 | = ( cfg["cout"]["priority"] | ||
| 86 | ✗ | ? log4cpp::Priority::getPriorityValue(cfg["cout"]["priority"].as<std::string>()) | |
| 87 | ✗ | : log4cpp::Priority::NOTSET | |
| 88 | ✗ | ); | |
| 89 | const std::string category | ||
| 90 | = ( cfg["cout"]["category"] | ||
| 91 | ✗ | ? cfg["cout"]["category"].as<std::string>() | |
| 92 | ✗ | : "unhandled" | |
| 93 | ✗ | ); | |
| 94 | auto sbr = new util::Log4Cpp_StreambufRedirect( | ||
| 95 | log4cpp::Category::getInstance(category) | ||
| 96 | , static_cast<log4cpp::Priority::PriorityLevel>(defaultLevel) | ||
| 97 | ✗ | ); | |
| 98 | ✗ | std::cout.rdbuf(sbr); | |
| 99 | } | ||
| 100 | ✗ | if( cfg["cerr"] ) { | |
| 101 | int defaultLevel | ||
| 102 | = ( cfg["cerr"]["priority"] | ||
| 103 | ✗ | ? log4cpp::Priority::getPriorityValue(cfg["cerr"]["priority"].as<std::string>()) | |
| 104 | ✗ | : log4cpp::Priority::WARN | |
| 105 | ✗ | ); | |
| 106 | const std::string category | ||
| 107 | = ( cfg["cerr"]["category"] | ||
| 108 | ✗ | ? cfg["cerr"]["category"].as<std::string>() | |
| 109 | ✗ | : "unhandled" | |
| 110 | ✗ | ); | |
| 111 | auto sbr = new util::Log4Cpp_StreambufRedirect( | ||
| 112 | log4cpp::Category::getInstance(category) | ||
| 113 | , static_cast<log4cpp::Priority::PriorityLevel>(defaultLevel) | ||
| 114 | ✗ | ); | |
| 115 | ✗ | std::cerr.rdbuf(sbr); | |
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | void | ||
| 120 | ✗ | YAMLLog4cppConfiguratorImpl::doConfigure(const std::string & filename) { | |
| 121 | ✗ | YAML::Node cfgLog; | |
| 122 | ✗ | cfgLog = YAML::LoadFile( util::expand_name(filename) ); | |
| 123 | ✗ | doConfigure(cfgLog); | |
| 124 | ✗ | if(cfgLog["interceptStdStreams"]) { | |
| 125 | ✗ | _configure_std_streams(cfgLog["interceptStdStreams"]); | |
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | void | ||
| 130 | ✗ | YAMLLog4cppConfiguratorImpl::doConfigure( const YAML::Node & cfg ) { | |
| 131 | // Instantiate all appenders | ||
| 132 | ✗ | assert( cfg["appenders"].IsMap() ); // TODO | |
| 133 | ✗ | for( const auto appenderEntry : cfg["appenders"] ) { | |
| 134 | ✗ | const std::string & appenderName = appenderEntry.first.as<std::string>(); | |
| 135 | ✗ | const YAML::Node & appenderCfg = appenderEntry.second; | |
| 136 | // priority of current appender | ||
| 137 | ✗ | log4cpp::Priority::Value priority = log4cpp::Priority::NOTSET; | |
| 138 | ✗ | assert( appenderEntry.second.IsMap() ); // TODO | |
| 139 | // iterate over appender's properties and convert them into log4cpp | ||
| 140 | // factory's parameters | ||
| 141 | ✗ | log4cpp::FactoryParams appFPs; | |
| 142 | ✗ | std::string appenderClassName; | |
| 143 | ✗ | log4cpp::Layout * appenderLayout = nullptr; | |
| 144 | ✗ | for( const auto appenderParameterEntry : appenderCfg ) { | |
| 145 | const std::string & appenderParamName | ||
| 146 | ✗ | = appenderParameterEntry.first.as<std::string>(); | |
| 147 | ✗ | const YAML::Node & appenderParamValue | |
| 148 | = appenderParameterEntry.second; | ||
| 149 | ✗ | if( "_type" == appenderParamName ) { | |
| 150 | // has special meaning: appender class to choose | ||
| 151 | ✗ | appenderClassName = appenderParamValue.as<std::string>(); | |
| 152 | ✗ | continue; // do not create the log4cpp's property from "type" | |
| 153 | } | ||
| 154 | ✗ | if( "_layout" == appenderParamName ) { | |
| 155 | // handle "layout" node | ||
| 156 | ✗ | std::string layoutClassName; | |
| 157 | ✗ | log4cpp::FactoryParams lytFPs; | |
| 158 | // - iterate over layout parameters | ||
| 159 | ✗ | assert(appenderParamValue.IsMap()); // TODO | |
| 160 | ✗ | for( const auto layoutParameterEntry : appenderParamValue ) { | |
| 161 | ✗ | if("_type" == layoutParameterEntry.first.as<std::string>() ) { | |
| 162 | ✗ | layoutClassName = layoutParameterEntry.second.as<std::string>(); | |
| 163 | ✗ | continue; // do not create the log4cpp's property from "type" | |
| 164 | } | ||
| 165 | // create log4cpp property for layout | ||
| 166 | ✗ | lytFPs[layoutParameterEntry.first.as<std::string>()] | |
| 167 | ✗ | = layoutParameterEntry.second.as<std::string>(); | |
| 168 | } | ||
| 169 | ✗ | assert(log4cpp::LayoutsFactory::getInstance().registed( | |
| 170 | layoutClassName)); // TODO | ||
| 171 | ✗ | appenderLayout = log4cpp::LayoutsFactory::getInstance().create( | |
| 172 | ✗ | layoutClassName, lytFPs ).release(); | |
| 173 | ✗ | continue; // do not create the log4cpp's property from "layout" | |
| 174 | } | ||
| 175 | ✗ | if( "_threshold" == appenderParamName ) { | |
| 176 | priority | ||
| 177 | ✗ | = log4cpp::Priority::getPriorityValue(appenderEntry.second.as<std::string>()); | |
| 178 | ✗ | continue; | |
| 179 | } | ||
| 180 | // TODO: support for "_filters" -- we currently do not | ||
| 181 | // use it, but it somehow do exist in log4cpp, as an interface | ||
| 182 | // otherwise, it is an "ordinary" appender's parameter -- create | ||
| 183 | // property | ||
| 184 | ✗ | appFPs[appenderParamName] = appenderParamValue.as<std::string>(); | |
| 185 | } | ||
| 186 | ✗ | appFPs["name"] = appenderName; | |
| 187 | ✗ | if( ! log4cpp::AppendersFactory::getInstance().registered( | |
| 188 | appenderClassName)) { | ||
| 189 | std::cerr << "Warning: unknown log4cpp appender class \"" | ||
| 190 | << appenderClassName << "\" (supplementary logging destination" | ||
| 191 | ✗ | " disabled)." << std::endl; | |
| 192 | ✗ | continue; | |
| 193 | } | ||
| 194 | // Instantiate the appender | ||
| 195 | log4cpp::Appender * appender | ||
| 196 | ✗ | = log4cpp::AppendersFactory::getInstance() | |
| 197 | ✗ | .create(appenderClassName, appFPs).release(); | |
| 198 | ✗ | if( appenderLayout ) { | |
| 199 | ✗ | appender->setLayout(appenderLayout); | |
| 200 | } else { | ||
| 201 | ✗ | assert(!appender->requiresLayout()); // TODO | |
| 202 | } | ||
| 203 | ✗ | appender->setThreshold(priority); | |
| 204 | ✗ | appenders[appenderName] = appender; | |
| 205 | } | ||
| 206 | // Iterate over the "categories" | ||
| 207 | ✗ | assert(cfg["categories"].IsMap()); | |
| 208 | ✗ | std::list<std::string> catNames; | |
| 209 | ✗ | _configure_category_from_YAML( cfg["categories"] | |
| 210 | , log4cpp::Category::getRoot() | ||
| 211 | , catNames ); | ||
| 212 | } | ||
| 213 | |||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 |