Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : //
6 : // sandesh.cc
7 : //
8 : // Sandesh Implementation
9 : //
10 :
11 : #include <boost/filesystem.hpp>
12 : #include <boost/bind/bind.hpp>
13 : #include <boost/foreach.hpp>
14 : #include <boost/format.hpp>
15 : #include <boost/algorithm/string/predicate.hpp>
16 :
17 : #include <base/logging.h>
18 : #include <base/parse_object.h>
19 : #include <base/queue_task.h>
20 : #include <base/address_util.h>
21 : #include <http/http_session.h>
22 : #include <io/tcp_session.h>
23 :
24 : #include <sandesh/transport/TBufferTransports.h>
25 : #include <sandesh/transport/TSimpleFileTransport.h>
26 : #include <sandesh/protocol/TBinaryProtocol.h>
27 : #include <sandesh/protocol/TProtocol.h>
28 :
29 : #include <sandesh/sandesh_types.h>
30 : #include <sandesh/sandesh.h>
31 : #include <sandesh/sandesh_trace.h>
32 : #include <sandesh/sandesh_uve_types.h>
33 : #include "sandesh_statistics.h"
34 : #include "sandesh_uve.h"
35 : #include "sandesh_session.h"
36 : #include "sandesh_http.h"
37 : #include "sandesh_client.h"
38 : #include "sandesh_connection.h"
39 : #include "sandesh_state_machine.h"
40 :
41 : #include <log4cplus/helpers/pointer.h>
42 : #include <log4cplus/configurator.h>
43 : #include <log4cplus/fileappender.h>
44 : #include <log4cplus/syslogappender.h>
45 :
46 : using boost::asio::ip::tcp;
47 : using boost::asio::ip::address;
48 :
49 : using namespace contrail::sandesh::protocol;
50 : using namespace contrail::sandesh::transport;
51 : using namespace log4cplus;
52 : using namespace boost::placeholders;
53 :
54 : // Statics
55 : Sandesh::SandeshRole::type Sandesh::role_ = SandeshRole::Invalid;
56 : bool Sandesh::enable_local_log_ = false;
57 : bool Sandesh::enable_flow_log_ = false;
58 : bool Sandesh::enable_session_syslog_ = false;
59 : int Sandesh::http_port_ = 0;
60 : bool Sandesh::enable_trace_print_ = false;
61 : bool Sandesh::send_queue_enabled_ = true;
62 : bool Sandesh::connect_to_collector_ = false;
63 : bool Sandesh::disable_flow_collection_ = false;
64 : bool Sandesh::disable_sending_all_ = false;
65 : bool Sandesh::disable_sending_object_logs_ = false;
66 : bool Sandesh::disable_sending_flows_ = false;
67 : bool Sandesh::slo_to_collector_ = false;
68 : bool Sandesh::sampled_to_collector_ = false;
69 : bool Sandesh::slo_to_logger_ = false;
70 : bool Sandesh::sampled_to_logger_ = false;
71 : SandeshClient *Sandesh::client_ = NULL;
72 : SandeshConfig Sandesh::config_;
73 : std::unique_ptr<Sandesh::SandeshRxQueue> Sandesh::recv_queue_;
74 : std::string Sandesh::module_;
75 : std::string Sandesh::source_;
76 : std::string Sandesh::node_type_;
77 : std::string Sandesh::instance_id_;
78 : int Sandesh::recv_task_id_ = -1;
79 : SandeshContext* Sandesh::client_context_ = NULL;
80 : Sandesh::SandeshCallback Sandesh::response_callback_ = 0;
81 : SandeshLevel::type Sandesh::logging_level_ = SandeshLevel::INVALID;
82 : SandeshLevel::type Sandesh::logging_ut_level_ =
83 : getenv("SANDSH_UT_DEBUG") ? SandeshLevel::SYS_DEBUG : SandeshLevel::UT_DEBUG;
84 : std::string Sandesh::logging_category_;
85 : EventManager* Sandesh::event_manager_ = NULL;
86 : SandeshMessageStatistics Sandesh::msg_stats_;
87 : std::mutex Sandesh::stats_mutex_;
88 : log4cplus::Logger Sandesh::logger_ =
89 : log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("SANDESH"));
90 : log4cplus::Logger Sandesh::slo_logger_ =
91 : log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("SLO_SESSION"));
92 : log4cplus::Logger Sandesh::sampled_logger_ =
93 : log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("SAMPLED_SESSION"));
94 :
95 : Sandesh::ModuleContextMap Sandesh::module_context_;
96 : std::atomic<uint32_t> Sandesh::sandesh_send_ratelimit_;
97 :
98 : const char *loggingPattern = "%D{%Y-%m-%d %a %H:%M:%S:%Q %Z} "
99 : " %h [Thread %t, Pid %i]: %m%n";
100 :
101 86 : const char * Sandesh::SandeshRoleToString(SandeshRole::type role) {
102 86 : switch (role) {
103 83 : case SandeshRole::Generator:
104 83 : return "Generator";
105 0 : case SandeshRole::Collector:
106 0 : return "Collector";
107 3 : case SandeshRole::Test:
108 3 : return "Test";
109 0 : case SandeshRole::Invalid:
110 0 : return "Invalid";
111 0 : default:
112 0 : return "Unknown";
113 : }
114 : }
115 :
116 87 : void Sandesh::InitReceive(int recv_task_inst) {
117 87 : assert(recv_task_id_ == -1);
118 87 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
119 87 : recv_task_id_ = scheduler->GetTaskId("sandesh::RecvQueue");
120 174 : recv_queue_.reset(new SandeshRxQueue(recv_task_id_, recv_task_inst,
121 87 : &Sandesh::ProcessRecv));
122 87 : }
123 :
124 37 : void Sandesh::InitClient(EventManager *evm, Endpoint server,
125 : const SandeshConfig &config, bool periodicuve) {
126 37 : connect_to_collector_ = true;
127 37 : SANDESH_LOG(INFO, "SANDESH: CONNECT TO COLLECTOR: " <<
128 : connect_to_collector_);
129 : // Create and initialize the client
130 37 : assert(client_ == NULL);
131 37 : std::vector<Endpoint> collector_endpoints = boost::assign::list_of(server);
132 37 : client_ = new SandeshClient(evm, collector_endpoints, config,
133 37 : periodicuve);
134 37 : client_->Initiate();
135 37 : }
136 :
137 10 : static int32_t SandeshHttpCallback(SandeshRequest *rsnh) {
138 10 : return rsnh->Enqueue(Sandesh::recv_queue());
139 : }
140 :
141 : extern int PullSandeshGenStatsReq;
142 : extern int PullSandeshUVE;
143 : extern int PullSandeshTraceReq;
144 :
145 90 : bool Sandesh::Initialize(SandeshRole::type role,
146 : const std::string &module,
147 : const std::string &source,
148 : const std::string &node_type,
149 : const std::string &instance_id,
150 : EventManager *evm,
151 : unsigned short http_port,
152 : SandeshContext *client_context,
153 : const SandeshConfig &config) {
154 90 : PullSandeshGenStatsReq = 1;
155 90 : PullSandeshUVE = 1;
156 90 : PullSandeshTraceReq = 1;
157 :
158 90 : if (role_ != SandeshRole::Invalid || role == SandeshRole::Invalid) {
159 3 : return true;
160 : }
161 :
162 87 : SANDESH_LOG(INFO, "SANDESH: ROLE : " << SandeshRoleToString(role));
163 87 : SANDESH_LOG(INFO, "SANDESH: MODULE : " << module);
164 87 : SANDESH_LOG(INFO, "SANDESH: SOURCE : " << source);
165 87 : SANDESH_LOG(INFO, "SANDESH: NODE TYPE : " << node_type);
166 87 : SANDESH_LOG(INFO, "SANDESH: INSTANCE ID : " << instance_id);
167 87 : SANDESH_LOG(INFO, "SANDESH: HTTP SERVER PORT : " << http_port);
168 :
169 87 : role_ = role;
170 87 : module_ = module;
171 87 : source_ = source;
172 87 : node_type_ = node_type;
173 87 : instance_id_ = instance_id;
174 87 : client_context_ = client_context;
175 87 : config_ = config;
176 87 : event_manager_ = evm;
177 :
178 87 : set_send_rate_limit(config.system_logs_rate_limit);
179 87 : DisableSendingObjectLogs(config.disable_object_logs);
180 87 : InitReceive(Task::kTaskInstanceAny);
181 87 : bool success(SandeshHttp::Init(evm, module, http_port,
182 : &SandeshHttpCallback, &http_port_, config_));
183 87 : if (!success) {
184 0 : SANDESH_LOG(ERROR, "SANDESH: HTTP INIT FAILED (PORT " <<
185 : http_port << ")");
186 0 : return false;
187 : }
188 87 : RecordPort("http", module_, http_port_);
189 87 : return true;
190 : }
191 :
192 87 : void Sandesh::RecordPort(const std::string& name, const std::string& module, unsigned short port) {
193 : int fd;
194 87 : std::ostringstream myfifoss;
195 87 : myfifoss << "/tmp/" << module << "." << getppid() << "." << name << "_port";
196 87 : std::string myfifo = myfifoss.str();
197 87 : std::ostringstream hss;
198 87 : hss << port << "\n";
199 87 : std::string hstr = hss.str();
200 :
201 87 : fd = open(myfifo.c_str(), O_WRONLY | O_NONBLOCK);
202 87 : if (fd != -1) {
203 44 : SANDESH_LOG(INFO, "SANDESH: Write " << name << "_port " << port <<
204 : "TO : " << myfifo);
205 44 : write(fd, hstr.c_str(), hstr.length());
206 44 : close(fd);
207 : } else {
208 43 : SANDESH_LOG(INFO, "SANDESH: NOT Writing " << name << "_port " << port <<
209 : "TO : " << myfifo);
210 : }
211 87 : }
212 :
213 37 : bool Sandesh::ConnectToCollector(const std::string &collector_ip,
214 : int collector_port, bool periodicuve) {
215 37 : boost::system::error_code ec;
216 37 : address collector_addr = AddressFromString(collector_ip, &ec);
217 37 : if (ec) {
218 0 : SANDESH_LOG(ERROR, __func__ << ": Invalid collector address: " <<
219 : collector_ip << " Error: " << ec);
220 0 : return false;
221 : }
222 :
223 37 : SANDESH_LOG(INFO, "SANDESH: COLLECTOR : " << collector_ip);
224 37 : SANDESH_LOG(INFO, "SANDESH: COLLECTOR PORT : " << collector_port);
225 :
226 37 : tcp::endpoint collector(collector_addr, collector_port);
227 37 : InitClient(event_manager_, collector, Sandesh::config(), periodicuve);
228 37 : return true;
229 : }
230 :
231 0 : void Sandesh::ReConfigCollectors(const std::vector<std::string>& collector_list) {
232 0 : if (client_) {
233 0 : client_->ReConfigCollectors(collector_list);
234 : }
235 0 : }
236 :
237 47 : bool Sandesh::InitClient(EventManager *evm,
238 : const std::vector<std::string> &collectors,
239 : const SandeshConfig &config) {
240 47 : connect_to_collector_ = true;
241 47 : SANDESH_LOG(INFO, "SANDESH: CONNECT TO COLLECTOR: " <<
242 : connect_to_collector_);
243 47 : std::vector<Endpoint> collector_endpoints;
244 155 : BOOST_FOREACH(const std::string &collector, collectors) {
245 54 : Endpoint ep;
246 54 : if (!MakeEndpoint(&ep, collector)) {
247 0 : SANDESH_LOG(ERROR, __func__ << ": Invalid collector address: " <<
248 : collector);
249 0 : return false;
250 : }
251 54 : collector_endpoints.push_back(ep);
252 : }
253 47 : client_ = new SandeshClient(evm, collector_endpoints, config, true);
254 47 : client_->Initiate();
255 47 : return true;
256 47 : }
257 :
258 40 : bool Sandesh::InitGenerator(const std::string &module,
259 : const std::string &source,
260 : const std::string &node_type,
261 : const std::string &instance_id,
262 : EventManager *evm,
263 : unsigned short http_port,
264 : SandeshContext *client_context,
265 : DerivedStats ds,
266 : const SandeshConfig &config) {
267 40 : assert(SandeshUVETypeMaps::InitDerivedStats(ds));
268 40 : return Initialize(SandeshRole::Generator, module, source, node_type,
269 40 : instance_id, evm, http_port, client_context, config);
270 : }
271 :
272 47 : bool Sandesh::InitGenerator(const std::string &module,
273 : const std::string &source,
274 : const std::string &node_type,
275 : const std::string &instance_id,
276 : EventManager *evm,
277 : unsigned short http_port,
278 : const std::vector<std::string> &collectors,
279 : SandeshContext *client_context,
280 : DerivedStats ds,
281 : const SandeshConfig &config) {
282 47 : assert(SandeshUVETypeMaps::InitDerivedStats(ds));
283 47 : bool success(Initialize(SandeshRole::Generator, module, source, node_type,
284 : instance_id, evm, http_port, client_context,
285 : config));
286 47 : if (!success) {
287 0 : return false;
288 : }
289 47 : return InitClient(evm, collectors, config);
290 : }
291 :
292 : // Collector
293 0 : bool Sandesh::InitCollector(const std::string &module,
294 : const std::string &source,
295 : const std::string &node_type,
296 : const std::string &instance_id,
297 : EventManager *evm,
298 : const std::string &collector_ip, int collector_port,
299 : unsigned short http_port,
300 : SandeshContext *client_context,
301 : const SandeshConfig &config) {
302 0 : bool success(Initialize(SandeshRole::Collector, module, source, node_type,
303 : instance_id, evm, http_port, client_context,
304 : config));
305 0 : if (!success) {
306 0 : return false;
307 : }
308 0 : return ConnectToCollector(collector_ip, collector_port, true);
309 : }
310 :
311 3 : bool Sandesh::InitGeneratorTest(const std::string &module,
312 : const std::string &source,
313 : const std::string &node_type,
314 : const std::string &instance_id,
315 : EventManager *evm,
316 : unsigned short http_port,
317 : SandeshContext *client_context,
318 : const SandeshConfig &config) {
319 3 : return Initialize(SandeshRole::Test, module, source, node_type,
320 3 : instance_id, evm, http_port, client_context, config);
321 : }
322 :
323 84 : static void WaitForIdle() {
324 : static const int kTimeout = 15;
325 84 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
326 :
327 197 : for (int i = 0; i < (kTimeout * 1000); i++) {
328 197 : if (scheduler->IsEmpty()) {
329 84 : break;
330 : }
331 113 : usleep(1000);
332 : }
333 84 : }
334 :
335 9 : void Sandesh::SetDscpValue(uint8_t value) {
336 9 : SandeshClient *client = Sandesh::client();
337 9 : if (client) {
338 0 : client->SetDscpValue(value);
339 : }
340 9 : }
341 :
342 87 : void Sandesh::Uninit() {
343 :
344 : // Wait until all pending http session based tasks are cleaned up.
345 87 : long count = 60000;
346 87 : while (count--) {
347 87 : if (HttpSession::GetPendingTaskCount() == 0) break;
348 0 : usleep(1000);
349 : }
350 87 : SandeshHttp::Uninit();
351 87 : role_ = SandeshRole::Invalid;
352 87 : if (recv_queue_.get() != NULL) {
353 87 : recv_queue_->Shutdown();
354 87 : recv_queue_.reset(NULL);
355 87 : assert(recv_task_id_ != -1);
356 87 : recv_task_id_ = -1;
357 : } else {
358 0 : assert(recv_task_id_ == -1);
359 : }
360 87 : if (client_ != NULL) {
361 84 : client_->Shutdown();
362 175 : while (client()->IsSession()) usleep(100);
363 84 : WaitForIdle();
364 84 : client_->ClearSessions();
365 84 : TcpServerManager::DeleteServer(client_);
366 84 : client_ = NULL;
367 : }
368 87 : }
369 :
370 61 : void Sandesh::SetLoggingParams(bool enable_local_log, std::string category,
371 : std::string level, bool enable_trace_print, bool enable_flow_log,
372 : bool enable_session_syslog) {
373 61 : SetLocalLogging(enable_local_log);
374 61 : SetLoggingCategory(category);
375 61 : SetLoggingLevel(level);
376 61 : SetTracePrint(enable_trace_print);
377 61 : SetFlowLogging(enable_flow_log);
378 61 : SetSessionSyslogging(enable_session_syslog);
379 61 : }
380 :
381 273 : void Sandesh::SetLoggingParams(bool enable_local_log, std::string category,
382 : SandeshLevel::type level, bool enable_trace_print,
383 : bool enable_flow_log) {
384 273 : SetLocalLogging(enable_local_log);
385 273 : SetLoggingCategory(category);
386 273 : SetLoggingLevel(level);
387 273 : SetTracePrint(enable_trace_print);
388 273 : SetFlowLogging(enable_flow_log);
389 273 : }
390 :
391 61 : void Sandesh::SetLoggingLevel(std::string level) {
392 61 : SandeshLevel::type nlevel = StringToLevel(level);
393 61 : SetLoggingLevel(nlevel);
394 61 : }
395 :
396 12601378 : log4cplus::LogLevel SandeshLevelTolog4Level(
397 : SandeshLevel::type slevel) {
398 12601378 : switch (slevel) {
399 24 : case SandeshLevel::SYS_EMERG:
400 : case SandeshLevel::SYS_ALERT:
401 : case SandeshLevel::SYS_CRIT:
402 24 : return log4cplus::FATAL_LOG_LEVEL;
403 6017 : case SandeshLevel::SYS_ERR:
404 6017 : return log4cplus::ERROR_LOG_LEVEL;
405 19908 : case SandeshLevel::SYS_WARN:
406 : case SandeshLevel::SYS_NOTICE:
407 19908 : return log4cplus::WARN_LOG_LEVEL;
408 804090 : case SandeshLevel::SYS_INFO:
409 804090 : return log4cplus::INFO_LOG_LEVEL;
410 4895631 : case SandeshLevel::SYS_DEBUG:
411 4895631 : return log4cplus::DEBUG_LOG_LEVEL;
412 6875708 : default:
413 : case SandeshLevel::INVALID:
414 6875708 : return log4cplus::ALL_LOG_LEVEL;
415 : }
416 : }
417 :
418 335 : void Sandesh::SetLoggingLevel(SandeshLevel::type level) {
419 335 : log4cplus::LogLevel log4_new_level(SandeshLevelTolog4Level(level));
420 335 : log4cplus::LogLevel log4_old_level(logger_.getLogLevel());
421 335 : if (logging_level_ != level ||
422 : log4_old_level != log4_new_level) {
423 : const log4cplus::LogLevelManager &log4level_manager(
424 241 : log4cplus::getLogLevelManager());
425 241 : SANDESH_LOG(INFO, "SANDESH: Logging: LEVEL: " << "[ " <<
426 : LevelToString(logging_level_) << " ] -> [ " <<
427 : LevelToString(level) << " ] log4level: [ " <<
428 : log4level_manager.toString(log4_old_level) <<
429 : " ] -> [ " <<
430 : log4level_manager.toString(log4_new_level) <<
431 : " ]");
432 241 : logging_level_ = level;
433 241 : logger_.setLogLevel(log4_new_level);
434 : // Set the LogLevel on rootLogger
435 241 : ::SetLoggingLevel(log4_new_level);
436 : }
437 335 : }
438 :
439 334 : void Sandesh::SetLoggingCategory(std::string category) {
440 334 : if (logging_category_ != category) {
441 0 : SANDESH_LOG(INFO, "SANDESH: Logging: CATEGORY: " <<
442 : (logging_category_.empty() ? "*" : logging_category_) << " -> " <<
443 : (category.empty() ? "*" : category));
444 0 : logging_category_ = category;
445 : }
446 334 : }
447 :
448 341 : void Sandesh::SetLocalLogging(bool enable_local_log) {
449 341 : if (enable_local_log_ != enable_local_log) {
450 206 : SANDESH_LOG(INFO, "SANDESH: Logging: " <<
451 : (enable_local_log_ ? "ENABLED" : "DISABLED") << " -> " <<
452 : (enable_local_log ? "ENABLED" : "DISABLED"));
453 206 : enable_local_log_ = enable_local_log;
454 : }
455 341 : }
456 :
457 334 : void Sandesh::SetTracePrint(bool enable_trace_print) {
458 334 : if (enable_trace_print_ != enable_trace_print) {
459 0 : SANDESH_LOG(INFO, "SANDESH: Trace: PRINT: " <<
460 : (enable_trace_print_ ? "ENABLED" : "DISABLED") << " -> " <<
461 : (enable_trace_print ? "ENABLED" : "DISABLED"));
462 0 : enable_trace_print_ = enable_trace_print;
463 : }
464 334 : }
465 :
466 334 : void Sandesh::SetFlowLogging(bool enable_flow_log) {
467 334 : if (enable_flow_log_ != enable_flow_log) {
468 0 : SANDESH_LOG(INFO, "SANDESH: Flow Logging: " <<
469 : (enable_flow_log_ ? "ENABLED" : "DISABLED") << " -> " <<
470 : (enable_flow_log ? "ENABLED" : "DISABLED"));
471 0 : enable_flow_log_ = enable_flow_log;
472 : }
473 334 : }
474 :
475 61 : void Sandesh::SetSessionSyslogging(bool enable_session_syslog) {
476 61 : if (enable_session_syslog_ != enable_session_syslog) {
477 0 : SANDESH_LOG(INFO, "SANDESH: Flow Logging: " <<
478 : (enable_session_syslog_ ? "ENABLED" : "DISABLED") << " -> " <<
479 : (enable_session_syslog ? "ENABLED" : "DISABLED"));
480 0 : enable_session_syslog_ = enable_session_syslog;
481 : }
482 :
483 61 : }
484 :
485 0 : void Sandesh::DisableFlowCollection(bool disable) {
486 0 : if (disable_flow_collection_ != disable) {
487 0 : SANDESH_LOG(INFO, "SANDESH: Disable Flow Collection: " <<
488 : disable_flow_collection_ << " -> " << disable);
489 0 : disable_flow_collection_ = disable;
490 : }
491 0 : }
492 :
493 0 : void Sandesh::DisableSendingAllMessages(bool disable) {
494 0 : if (disable_sending_all_ != disable) {
495 0 : SANDESH_LOG(INFO, "SANDESH: Disable Sending ALL Messages: " <<
496 : disable_sending_all_ << " -> " << disable);
497 0 : disable_sending_all_ = disable;
498 : }
499 0 : }
500 :
501 198693 : bool Sandesh::IsSendingAllMessagesDisabled() {
502 198693 : return disable_sending_all_;
503 : }
504 :
505 87 : void Sandesh::DisableSendingObjectLogs(bool disable) {
506 87 : if (disable_sending_object_logs_ != disable) {
507 0 : SANDESH_LOG(INFO, "SANDESH: Disable Sending Object Logs: " <<
508 : disable_sending_object_logs_ << " -> " << disable);
509 0 : disable_sending_object_logs_ = disable;
510 : }
511 87 : }
512 :
513 9596 : bool Sandesh::IsSendingObjectLogsDisabled() {
514 9596 : return disable_sending_object_logs_;
515 : }
516 :
517 0 : void Sandesh::DisableSendingFlows(bool disable) {
518 0 : if (disable_sending_flows_ != disable) {
519 0 : SANDESH_LOG(INFO, "SANDESH: Disable Sending Flows: " <<
520 : disable_sending_flows_ << " -> " << disable);
521 0 : disable_sending_flows_ = disable;
522 : }
523 0 : }
524 :
525 0 : bool Sandesh::IsSendingFlowsDisabled() {
526 0 : return disable_sending_flows_;
527 : }
528 :
529 184551 : bool Sandesh::IsSendingSystemLogsDisabled() {
530 184551 : return sandesh_send_ratelimit_ == 0;
531 : }
532 :
533 87 : void Sandesh::set_send_rate_limit(int rate_limit) {
534 87 : if (rate_limit >= 0) {
535 87 : SANDESH_LOG(INFO, "SANDESH: System Log Send Rate Limit: " <<
536 : sandesh_send_ratelimit_ << " -> " << rate_limit);
537 87 : sandesh_send_ratelimit_ = rate_limit;
538 : }
539 87 : }
540 :
541 29614 : uint32_t Sandesh::get_send_rate_limit() {
542 29614 : return sandesh_send_ratelimit_;
543 : }
544 :
545 12857 : bool Sandesh::Enqueue(SandeshQueue *queue) {
546 12857 : if (!queue) {
547 0 : if (IsLoggingDroppedAllowed(type())) {
548 0 : SANDESH_LOG(ERROR, __func__ << ": SandeshQueue NULL : Dropping Message: "
549 : << ToString());
550 : }
551 0 : UpdateTxMsgFailStats(name_, 0, SandeshTxDropReason::NoQueue);
552 0 : Release();
553 0 : return false;
554 : }
555 : //Frame an elemet object and enqueue it
556 12857 : SandeshElement elem(this);
557 12857 : if (!queue->Enqueue(elem)) {
558 : // XXX Change when WorkQueue implements bounded queues
559 0 : return true;
560 : }
561 12857 : return true;
562 : }
563 :
564 10 : bool Sandesh::ProcessRecv(SandeshRequest *rsnh) {
565 10 : rsnh->HandleRequest();
566 10 : rsnh->Release();
567 10 : return true;
568 : }
569 :
570 2283 : void SandeshRequest::Release() { self_.reset(); }
571 :
572 2333 : int32_t Sandesh::WriteBinary(u_int8_t *buf, u_int32_t buf_len,
573 : int *error) {
574 : int32_t xfer;
575 : boost::shared_ptr<TMemoryBuffer> btrans =
576 : boost::shared_ptr<TMemoryBuffer>(
577 2333 : new TMemoryBuffer(buf, buf_len));
578 2331 : btrans->setWriteBuffer(buf, buf_len);
579 : boost::shared_ptr<TBinaryProtocol> prot =
580 2331 : boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(btrans));
581 2332 : xfer = Write(prot);
582 2328 : if (xfer < 0) {
583 0 : SANDESH_LOG(DEBUG, __func__ << "Write sandesh to " << buf_len <<
584 : " bytes FAILED" << std::endl);
585 0 : *error = EINVAL;
586 0 : return xfer;
587 : }
588 2328 : return xfer;
589 2328 : }
590 :
591 0 : int32_t Sandesh::ReadBinary(u_int8_t *buf, u_int32_t buf_len,
592 : int *error) {
593 0 : int32_t xfer = 0;
594 : boost::shared_ptr<TMemoryBuffer> btrans =
595 : boost::shared_ptr<TMemoryBuffer>(
596 0 : new TMemoryBuffer(buf, buf_len));
597 : boost::shared_ptr<TBinaryProtocol> prot =
598 0 : boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(btrans));
599 0 : xfer = Read(prot);
600 0 : if (xfer < 0) {
601 0 : SANDESH_LOG(DEBUG, __func__ << "Read sandesh from " << buf_len <<
602 : " bytes FAILED" << std::endl);
603 0 : *error = EINVAL;
604 0 : return xfer;
605 : }
606 0 : return xfer;
607 0 : }
608 :
609 0 : int32_t Sandesh::WriteBinaryToFile(const std::string& path, int *error) {
610 : int32_t xfer;
611 : boost::shared_ptr<TSimpleFileTransport> btrans =
612 : boost::shared_ptr<TSimpleFileTransport>(
613 0 : new TSimpleFileTransport(path, false, true));
614 : boost::shared_ptr<TBinaryProtocol> prot =
615 0 : boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(btrans));
616 0 : xfer = Write(prot);
617 0 : if (xfer < 0) {
618 0 : SANDESH_LOG(DEBUG, __func__ << "Write sandesh to file FAILED"
619 : << std::endl);
620 0 : *error = EINVAL;
621 0 : return xfer;
622 : }
623 0 : return xfer;
624 0 : }
625 :
626 0 : int32_t Sandesh::ReadBinaryFromFile(const std::string& path, int *error) {
627 : int32_t xfer;
628 : boost::shared_ptr<TSimpleFileTransport> btrans =
629 : boost::shared_ptr<TSimpleFileTransport>(
630 0 : new TSimpleFileTransport(path));
631 : boost::shared_ptr<TBinaryProtocol> prot =
632 0 : boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(btrans));
633 0 : xfer = Read(prot);
634 0 : if (xfer < 0) {
635 0 : SANDESH_LOG(DEBUG, __func__ << "Read sandesh from file FAILED"
636 : << std::endl);
637 0 : *error = EINVAL;
638 0 : return xfer;
639 : }
640 0 : return xfer;
641 0 : }
642 :
643 2333 : int32_t Sandesh::ReceiveBinaryMsgOne(u_int8_t *buf, u_int32_t buf_len,
644 : int *error, SandeshContext *client_context) {
645 : int32_t xfer;
646 2333 : std::string sandesh_name;
647 : boost::shared_ptr<TMemoryBuffer> btrans =
648 : boost::shared_ptr<TMemoryBuffer>(
649 2333 : new TMemoryBuffer(buf, buf_len));
650 : boost::shared_ptr<TBinaryProtocol> prot =
651 2333 : boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(btrans));
652 : // Extract sandesh name
653 2333 : xfer = prot->readSandeshBegin(sandesh_name);
654 2332 : if (xfer < 0) {
655 0 : SANDESH_LOG(DEBUG, __func__ << "Read sandesh begin from " << buf_len <<
656 : " bytes FAILED" << std::endl);
657 0 : *error = EINVAL;
658 0 : return xfer;
659 : }
660 : // Create and process the sandesh
661 2332 : Sandesh *sandesh = SandeshBaseFactory::CreateInstance(sandesh_name);
662 2333 : if (sandesh == NULL) {
663 0 : SANDESH_LOG(DEBUG, __func__ << " Unknown sandesh:" <<
664 : sandesh_name << std::endl);
665 0 : *error = EINVAL;
666 0 : return -1;
667 : }
668 : // Reinitialize buffer and protocol
669 4666 : btrans = boost::shared_ptr<TMemoryBuffer>(
670 4666 : new TMemoryBuffer(buf, buf_len));
671 2333 : prot = boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(btrans));
672 2333 : xfer = sandesh->Read(prot);
673 2333 : if (xfer < 0) {
674 0 : SANDESH_LOG(DEBUG, __func__ << " Decoding " << sandesh_name << " FAILED" <<
675 : std::endl);
676 0 : *error = EINVAL;
677 0 : return xfer;
678 : }
679 2333 : SandeshBuffer * bsnh = dynamic_cast<SandeshBuffer *>(sandesh);
680 2333 : if (bsnh) bsnh->Process(client_context);
681 2333 : sandesh->Release();
682 2333 : return xfer;
683 2333 : }
684 :
685 0 : int32_t Sandesh::ReceiveBinaryMsg(u_int8_t *buf, u_int32_t buf_len,
686 : int *error, SandeshContext *client_context) {
687 0 : u_int32_t xfer = 0;
688 : int ret;
689 0 : while (xfer < buf_len) {
690 0 : ret = ReceiveBinaryMsgOne(buf + xfer, buf_len - xfer, error,
691 : client_context);
692 0 : if (ret < 0) {
693 0 : SANDESH_LOG(DEBUG, __func__ << "Read sandesh from " << buf_len <<
694 : " bytes at offset " << xfer << " FAILED (" <<
695 : error << ")");
696 0 : return ret;
697 : }
698 0 : xfer += ret;
699 : }
700 0 : return xfer;
701 : }
702 :
703 11627 : bool Sandesh::SendEnqueue() {
704 11627 : if (!client_) {
705 2237 : if (IsLoggingDroppedAllowed(type())) {
706 2237 : if (IsConnectToCollectorEnabled()) {
707 0 : SANDESH_LOG(ERROR, "SANDESH: No client: " << ToString());
708 : } else {
709 2237 : Log();
710 : }
711 : }
712 2237 : UpdateTxMsgFailStats(name_, 0, SandeshTxDropReason::NoClient);
713 2237 : Release();
714 2237 : return false;
715 : }
716 9390 : if (!client_->SendSandesh(this)) {
717 0 : if (IsLoggingDroppedAllowed(type())) {
718 0 : SANDESH_LOG(ERROR, "SANDESH: Send FAILED: " << ToString());
719 : }
720 0 : UpdateTxMsgFailStats(name_, 0,
721 : SandeshTxDropReason::ClientSendFailed);
722 0 : Release();
723 0 : return false;
724 : }
725 9391 : return true;
726 : }
727 :
728 11664 : bool Sandesh::Dispatch(SandeshConnection * sconn) {
729 : // Sandesh client does not have a connection
730 11664 : if (sconn) {
731 37 : return sconn->SendSandesh(this);
732 : } else {
733 11627 : return SendEnqueue();
734 : }
735 : }
736 :
737 1943 : bool SandeshResponse::Dispatch(SandeshConnection * sconn) {
738 1943 : assert(sconn == NULL);
739 5819 : if ((context().find("http%") == 0) ||
740 3876 : (context().find("https%") == 0)) {
741 10 : SandeshHttp::Response(this, context());
742 10 : return true;
743 : }
744 1933 : if (response_callback_) {
745 1933 : response_callback_(this);
746 : }
747 1933 : return Sandesh::Dispatch(sconn);
748 : }
749 :
750 0 : bool SandeshTrace::Dispatch(SandeshConnection * sconn) {
751 0 : assert(sconn == NULL);
752 0 : if ((0 == context().find("http%")) ||
753 0 : (0 == context().find("https%"))) {
754 0 : SandeshHttp::Response(this, context());
755 0 : return true;
756 : }
757 0 : return Sandesh::Dispatch();
758 : }
759 :
760 201534 : bool SandeshUVE::Dispatch(SandeshConnection * sconn) {
761 201534 : assert(sconn == NULL);
762 604618 : if ((0 == context().find("http%")) ||
763 403093 : (0 == context().find("https%"))) {
764 0 : SandeshHttp::Response(this, context());
765 0 : return true;
766 : }
767 201552 : if (client_) {
768 4556 : if (IsSendingAllMessagesDisabled()) {
769 0 : Log();
770 0 : UpdateTxMsgFailStats(Name(), 0,
771 : SandeshTxDropReason::SendingDisabled);
772 0 : Release();
773 0 : return false;
774 : }
775 : // SandeshUVE has an implicit send level of SandeshLevel::SYS_UVE
776 : // which is irrespective of the level set by the user in the Send.
777 : // This is needed so that the send queue does not grow unbounded.
778 : // Once the send queue's sending level reaches SandeshLevel::SYS_UVE
779 : // we will reset the connection to the collector to initiate resync
780 : // of the UVE cache
781 4556 : if (SandeshLevel::SYS_UVE >= SendingLevel()) {
782 0 : client_->CloseSMSession();
783 : }
784 4556 : if (!client_->SendSandeshUVE(this)) {
785 0 : SANDESH_LOG(ERROR, "SandeshUVE : Send FAILED: " << ToString());
786 0 : UpdateTxMsgFailStats(Name(), 0,
787 : SandeshTxDropReason::ClientSendFailed);
788 0 : Release();
789 0 : return false;
790 : }
791 4556 : return true;
792 : }
793 196996 : if (IsConnectToCollectorEnabled()) {
794 84 : SANDESH_LOG(ERROR, "SANDESH: No Client: " << ToString());
795 : } else {
796 196915 : Log();
797 : }
798 196986 : UpdateTxMsgFailStats(Name(), 0, SandeshTxDropReason::NoClient);
799 197058 : Release();
800 197058 : return false;
801 : }
802 :
803 10 : bool SandeshRequest::Enqueue(SandeshRxQueue *queue) {
804 10 : if (!queue) {
805 0 : SANDESH_LOG(ERROR, "SandeshRequest: No RxQueue: " << ToString());
806 0 : UpdateRxMsgFailStats(Name(), 0, SandeshRxDropReason::NoQueue);
807 0 : Release();
808 0 : return false;
809 : }
810 10 : if (!queue->Enqueue(this)) {
811 : // XXX Change when WorkQueue implements bounded queues
812 0 : return true;
813 : }
814 10 : return true;
815 : }
816 :
817 236344 : bool Sandesh::IsLevelUT(SandeshLevel::type level) {
818 236344 : return level >= SandeshLevel::UT_START &&
819 236344 : level <= SandeshLevel::UT_END;
820 : }
821 :
822 21059771 : bool Sandesh::IsLevelCategoryLoggingAllowed(SandeshType::type type,
823 : SandeshLevel::type level,
824 : const std::string& category) {
825 : // Do not log UVEs unless explicitly configured via setting log_level
826 : // to INVALID. This is to avoid flooding the log files with UVEs
827 21059771 : if (type == SandeshType::UVE) {
828 200512 : level = SandeshLevel::INVALID;
829 : }
830 21059771 : bool level_allowed = logging_level_ >= level;
831 21059771 : bool category_allowed = !logging_category_.empty() ?
832 118 : logging_category_ == category : true;
833 21060865 : return level_allowed && category_allowed;
834 : }
835 :
836 12894 : bool Sandesh::IsLoggingAllowed() const {
837 12894 : if (type_ == SandeshType::FLOW || type_ == SandeshType::SESSION) {
838 0 : return enable_flow_log_;
839 : } else {
840 25735 : return IsLocalLoggingEnabled() &&
841 25735 : IsLevelCategoryLoggingAllowed(type_, level_, category_);
842 : }
843 : }
844 :
845 3327 : bool Sandesh::IsLoggingDroppedAllowed(SandeshType::type type) {
846 3327 : if (type == SandeshType::FLOW || type == SandeshType::SESSION) {
847 0 : return enable_flow_log_;
848 : } else {
849 3327 : return true;
850 : }
851 : }
852 :
853 12372527 : const char * Sandesh::LevelToString(SandeshLevel::type level) {
854 12372527 : std::map<int, const char*>::const_iterator it = _SandeshLevel_VALUES_TO_NAMES.find(level);
855 12371393 : if (it != _SandeshLevel_VALUES_TO_NAMES.end()) {
856 12371195 : return it->second;
857 : } else {
858 0 : return "UNKNOWN";
859 : }
860 : }
861 :
862 108 : SandeshLevel::type Sandesh::StringToLevel(std::string level) {
863 108 : std::map<int, const char*>::const_iterator it = _SandeshLevel_VALUES_TO_NAMES.begin();
864 921 : while (it != _SandeshLevel_VALUES_TO_NAMES.end()) {
865 921 : if (strncmp(level.c_str(), it->second, strlen(it->second)) == 0) {
866 108 : return static_cast<SandeshLevel::type>(it->first);
867 : }
868 813 : it++;
869 : }
870 0 : return SandeshLevel::INVALID;
871 : }
872 :
873 85 : void Sandesh::UpdateRxMsgStats(const std::string &msg_name,
874 : uint64_t bytes) {
875 85 : std::scoped_lock lock(stats_mutex_);
876 85 : msg_stats_.UpdateRecv(msg_name, bytes);
877 85 : }
878 :
879 0 : void Sandesh::UpdateRxMsgFailStats(const std::string &msg_name,
880 : uint64_t bytes, SandeshRxDropReason::type dreason) {
881 0 : std::scoped_lock lock(stats_mutex_);
882 0 : msg_stats_.UpdateRecvFailed(msg_name, bytes, dreason);
883 0 : }
884 :
885 12894 : void Sandesh::UpdateTxMsgStats(const std::string &msg_name,
886 : uint64_t bytes) {
887 12894 : std::scoped_lock lock(stats_mutex_);
888 12894 : msg_stats_.UpdateSend(msg_name, bytes);
889 12894 : }
890 :
891 384862 : void Sandesh::UpdateTxMsgFailStats(const std::string &msg_name,
892 : uint64_t bytes, SandeshTxDropReason::type dreason) {
893 384862 : std::scoped_lock lock(stats_mutex_);
894 384950 : msg_stats_.UpdateSendFailed(msg_name, bytes, dreason);
895 384950 : }
896 :
897 664 : void Sandesh::GetMsgStats(
898 : std::vector<SandeshMessageTypeStats> *mtype_stats,
899 : SandeshMessageStats *magg_stats) {
900 664 : std::scoped_lock lock(stats_mutex_);
901 664 : msg_stats_.Get(mtype_stats, magg_stats);
902 664 : }
903 :
904 0 : void Sandesh::GetMsgStats(
905 : boost::ptr_map<std::string, SandeshMessageTypeStats> *mtype_stats,
906 : SandeshMessageStats *magg_stats) {
907 0 : std::scoped_lock lock(stats_mutex_);
908 0 : msg_stats_.Get(mtype_stats, magg_stats);
909 0 : }
910 :
911 0 : void Sandesh::SetSendQueue(bool enable) {
912 0 : if (send_queue_enabled_ != enable) {
913 0 : SANDESH_LOG(INFO, "SANDESH: CLIENT: SEND QUEUE: " <<
914 : (send_queue_enabled_ ? "ENABLED" : "DISABLED") << " -> " <<
915 : (enable ? "ENABLED" : "DISABLED"));
916 0 : send_queue_enabled_ = enable;
917 0 : if (enable) {
918 0 : if (client_ && client_->IsSession()) {
919 0 : client_->session()->send_queue()->MayBeStartRunner();
920 : }
921 : }
922 : }
923 0 : }
924 :
925 : // In sandesh state machine on collector, we can only drop systemlog,
926 : // objectlog, and flow. UVEs can only be dropped after being dequeued from
927 : // the state machine and published on redis/kafka
928 12373 : bool DoDropSandeshMessage(const SandeshHeader &header,
929 : const SandeshLevel::type drop_level) {
930 12373 : SandeshType::type stype(header.get_Type());
931 12373 : if (stype == SandeshType::SYSTEM ||
932 3397 : stype == SandeshType::OBJECT ||
933 3397 : stype == SandeshType::FLOW ||
934 : stype == SandeshType::SESSION) {
935 : // Is level above drop level?
936 : SandeshLevel::type slevel(
937 8976 : static_cast<SandeshLevel::type>(header.get_Level()));
938 8976 : if (slevel >= drop_level) {
939 0 : return true;
940 : }
941 : }
942 : // Drop flow message if flow collection is disabled
943 12373 : if (Sandesh::IsFlowCollectionDisabled() &&
944 0 : (stype == SandeshType::FLOW || stype == SandeshType::SESSION)) {
945 0 : return true;
946 : }
947 12373 : return false;
948 : }
949 :
950 359 : SandeshContext *Sandesh::module_context(const std::string &module_name) {
951 359 : ModuleContextMap::const_iterator loc = module_context_.find(module_name);
952 359 : if (loc != module_context_.end()) {
953 359 : return loc->second;
954 : }
955 0 : return NULL;
956 : }
957 :
958 217 : void Sandesh::set_module_context(const std::string &module_name,
959 : SandeshContext *context) {
960 : std::pair<ModuleContextMap::iterator, bool> result =
961 217 : module_context_.insert(std::make_pair(module_name, context));
962 217 : if (!result.second) {
963 203 : result.first->second = context;
964 : }
965 217 : }
966 :
967 12372133 : bool Sandesh::HandleTest(SandeshLevel::type level,
968 : const std::string& category) {
969 : // Handle unit test scenario
970 12372133 : if (IsUnitTest() || IsLevelUT(level)) {
971 12178073 : return true;
972 : }
973 194151 : return false;
974 : }
975 :
976 14152 : SandeshLevel::type Sandesh::SendingLevel() {
977 14152 : if (client_) {
978 13835 : SandeshSession *sess = client_->session();
979 13835 : if (sess) {
980 13416 : return sess->SendingLevel();
981 : }
982 : }
983 736 : return SandeshLevel::INVALID;
984 : }
985 :
986 : template<>
987 12894 : size_t Sandesh::SandeshQueue::AtomicIncrementQueueCount(
988 : SandeshElement *element)
989 : {
990 12894 : size_t sandesh_size = element->GetSize();
991 25788 : return count_.fetch_add(sandesh_size) + sandesh_size;
992 : }
993 :
994 : template<>
995 12894 : size_t Sandesh::SandeshQueue::AtomicDecrementQueueCount(
996 : SandeshElement *element) {
997 12894 : size_t sandesh_size = element->GetSize();
998 25788 : return count_.fetch_sub(sandesh_size) - sandesh_size;
999 : }
1000 :
1001 : /*
1002 : * Add the configured appenders for the sample logger
1003 : */
1004 6 : void Sandesh::set_logger_appender(const std::string &file_name, long max_file_size,
1005 : int max_backup_index,
1006 : const std::string &syslog_facility,
1007 : const std::vector<std::string> &destn,
1008 : const std::string &ident,
1009 : bool is_sampled_logger) {
1010 6 : log4cplus::Logger logger;
1011 6 : if (is_sampled_logger) {
1012 3 : logger = Sandesh::sampled_logger();
1013 : } else {
1014 3 : logger = Sandesh::slo_logger();
1015 : }
1016 6 : logger.setAdditivity(false);
1017 : // Session messages log level is
1018 6 : logger.setLogLevel(SandeshLevel::SYS_NOTICE);
1019 : // Local logging for SLO logger
1020 6 : if (std::find(destn.begin(), destn.end(), "file") !=
1021 12 : destn.end()) {
1022 : // Append file appender to SLO logger
1023 : SharedAppenderPtr fileappender(new RollingFileAppender(file_name,
1024 0 : max_file_size, max_backup_index));
1025 0 : logger.addAppender(fileappender);
1026 0 : if (is_sampled_logger) {
1027 0 : Sandesh::sampled_to_logger_ = true;
1028 : } else {
1029 0 : Sandesh::slo_to_logger_ = true;
1030 : }
1031 0 : }
1032 : // SYSLOG appender for SLO logger
1033 6 : if (std::find(destn.begin(), destn.end(), "syslog") !=
1034 12 : destn.end()) {
1035 0 : helpers::Properties props;
1036 : std::string syslogident = boost::str(
1037 0 : boost::format("%1%[%2%]") % ident % getpid());
1038 0 : props.setProperty(LOG4CPLUS_TEXT("facility"),
1039 0 : boost::starts_with(syslog_facility, "LOG_")
1040 0 : ? syslog_facility.substr(4)
1041 : : syslog_facility);
1042 0 : props.setProperty(LOG4CPLUS_TEXT("ident"), syslogident);
1043 0 : props.setProperty(LOG4CPLUS_TEXT("additivity"), "false");
1044 0 : SharedAppenderPtr syslogappender(new SysLogAppender(props));
1045 : std::unique_ptr<Layout> syslog_layout_ptr(new PatternLayout(
1046 0 : loggingPattern));
1047 0 : syslogappender->setLayout(std::move(syslog_layout_ptr));
1048 0 : logger.addAppender(syslogappender);
1049 0 : if (is_sampled_logger) {
1050 0 : Sandesh::sampled_to_logger_ = true;
1051 : } else {
1052 0 : Sandesh::slo_to_logger_ = true;
1053 : }
1054 0 : }
1055 6 : }
1056 :
1057 3 : void Sandesh::set_send_to_collector_flags(
1058 : const std::vector<std::string> &sampled_destn,
1059 : const std::vector<std::string> &slo_destn) {
1060 3 : if (std::find(slo_destn.begin(), slo_destn.end(), "collector") !=
1061 6 : slo_destn.end()) {
1062 3 : Sandesh::slo_to_collector_ = true;
1063 : }
1064 3 : if (std::find(sampled_destn.begin(), sampled_destn.end(), "collector") !=
1065 6 : sampled_destn.end()) {
1066 3 : Sandesh::sampled_to_collector_ = true;
1067 : }
1068 3 : }
|