GCC Code Coverage Report


Directory: ./
File: src/util/YAMLLog4cppConfiguratorImpl.cc
Date: 2025-09-01 06:19:01
Exec Total Coverage
Lines: 0 111 0.0%
Functions: 0 5 0.0%
Branches: 0 58 0.0%

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