Commit | Line | Data |
---|---|---|
970ed795 | 1 | /////////////////////////////////////////////////////////////////////////////// |
3abe9331 | 2 | // Copyright (c) 2000-2015 Ericsson Telecom AB |
970ed795 EL |
3 | // All rights reserved. This program and the accompanying materials |
4 | // are made available under the terms of the Eclipse Public License v1.0 | |
5 | // which accompanies this distribution, and is available at | |
6 | // http://www.eclipse.org/legal/epl-v10.html | |
7 | /////////////////////////////////////////////////////////////////////////////// | |
8 | #include "LoggerPluginManager.hh" | |
9 | #include "LoggerPlugin.hh" | |
10 | #include "TitanLoggerApi.hh" | |
11 | #include "Runtime.hh" | |
12 | #include "Logger.hh" | |
13 | #include "ILoggerPlugin.hh" | |
14 | ||
15 | #include "../common/dbgnew.hh" | |
16 | #include "../core/Error.hh" | |
17 | #include "../common/static_check.h" | |
18 | ||
19 | #include <assert.h> | |
20 | #include <string.h> | |
21 | ||
22 | ||
23 | #ifdef WIN32 | |
24 | // On Cygwin/MinGW it's called DLL. | |
25 | #define SO_EXTENSION "dll" | |
26 | #else | |
27 | #define SO_EXTENSION "so" | |
28 | #endif | |
29 | ||
30 | namespace API = TitanLoggerApi; | |
31 | ||
32 | extern "C" cb_create_plugin create_legacy_logger; | |
33 | ||
34 | RingBuffer::~RingBuffer() | |
35 | { | |
36 | if (buffer != NULL) { | |
37 | delete[] buffer; | |
38 | } | |
39 | } | |
40 | ||
41 | bool RingBuffer::get(TitanLoggerApi::TitanLogEvent& data) | |
42 | { | |
43 | if(tail == head) | |
44 | return false; | |
45 | ||
46 | data = buffer[tail]; | |
47 | tail = (tail +1) % (size + 1); | |
48 | ||
49 | return true; | |
50 | } | |
51 | ||
52 | void RingBuffer::put(TitanLoggerApi::TitanLogEvent data) | |
53 | { | |
54 | buffer[head] = data; | |
55 | head = (head + 1) % (size + 1); | |
56 | ||
57 | if (head == tail) { | |
58 | tail = (tail +1 ) % (size + 1); | |
59 | } | |
60 | } | |
61 | ||
62 | void RingBuffer::set_size(unsigned int new_size) | |
63 | { | |
64 | if (buffer != NULL) return; | |
65 | ||
66 | size = new_size; | |
67 | buffer = new TitanLoggerApi::TitanLogEvent[size + 1]; | |
68 | } | |
69 | ||
70 | void RingBuffer::clear() | |
71 | { | |
72 | head = tail = 0; | |
73 | } | |
74 | ||
75 | LoggerPluginManager::LoggerPluginManager() | |
76 | : n_plugins_(1), plugins_(new LoggerPlugin*[1]), entry_list_(NULL), | |
77 | current_event_(NULL), logparams_head(NULL), logparams_tail(NULL), | |
78 | logplugins_head(NULL), logplugins_tail(NULL) | |
79 | { | |
80 | this->plugins_[0] = new LoggerPlugin(&create_legacy_logger); | |
81 | this->plugins_[0]->load(); | |
82 | } | |
83 | ||
84 | LoggerPluginManager::~LoggerPluginManager() | |
85 | { | |
86 | // It can happen that there're some unlogged events still in the buffer. E.g. | |
87 | // an exception is thrown and no `end_event()' etc. is called. | |
88 | while (this->entry_list_ != NULL) { | |
89 | LogEntry *next_entry = this->entry_list_->next_entry_; | |
90 | for (size_t i = 0; i < this->n_plugins_; ++i) { | |
91 | if (this->plugins_[i]->is_configured()) { | |
92 | this->plugins_[i]->log(this->entry_list_->event_, true, false, false); | |
93 | } | |
94 | } | |
95 | delete this->entry_list_; | |
96 | this->entry_list_ = next_entry; | |
97 | } | |
98 | this->entry_list_ = NULL; | |
99 | ||
100 | for (size_t i = 0; i < this->n_plugins_; ++i) { | |
101 | delete this->plugins_[i]; | |
102 | } | |
103 | delete [] this->plugins_; | |
104 | this->plugins_ = NULL; | |
105 | this->n_plugins_ = 0; | |
106 | ||
107 | if (this->current_event_ != NULL) { | |
108 | fputs("Some logging events in the buffer were not finished properly in " | |
109 | "the plug-in manager.\n", stderr); | |
110 | while (this->current_event_) { | |
111 | ActiveEvent *outer_event = this->current_event_->outer_event_; | |
112 | Free(this->current_event_->event_str_); | |
113 | delete this->current_event_; | |
114 | this->current_event_ = outer_event; | |
115 | } | |
116 | this->current_event_ = NULL; | |
117 | } | |
118 | } | |
119 | ||
120 | void LoggerPluginManager::ring_buffer_dump(bool do_close_file) | |
121 | { | |
122 | // in case of buffer all, flush the content of the ring buffer | |
123 | if (TTCN_Logger::get_emergency_logging_behaviour() == TTCN_Logger::BUFFER_ALL) { | |
124 | TitanLoggerApi::TitanLogEvent ring_event; | |
125 | // get all the events from the ring: buffer | |
126 | while (!ring_buffer.isEmpty()) { | |
127 | if (ring_buffer.get(ring_event)) { | |
128 | internal_log_to_all(ring_event, true, false, false); // buffer all: DO NOT log in separate file | |
129 | } | |
130 | } | |
131 | } | |
132 | ||
133 | if (do_close_file) { | |
134 | for (size_t i = 0; i < this->n_plugins_; ++i) { | |
135 | plugins_[i]->close_file(); | |
136 | } | |
137 | } | |
138 | ||
139 | ring_buffer.clear(); | |
140 | } | |
141 | ||
142 | void LoggerPluginManager::register_plugin(const component_id_t comp, | |
143 | char *identifier, char *filename) | |
144 | { | |
145 | logging_plugin_t *newplugin = new logging_plugin_t; | |
146 | newplugin->component.id_selector = comp.id_selector; | |
147 | switch (newplugin->component.id_selector) { | |
148 | case COMPONENT_ID_NAME: newplugin->component.id_name = mcopystr(comp.id_name); break; | |
149 | case COMPONENT_ID_COMPREF: newplugin->component.id_compref = comp.id_compref; break; | |
150 | default: newplugin->component.id_name = NULL; break; | |
151 | } | |
152 | newplugin->identifier = identifier; | |
153 | newplugin->filename = filename; | |
154 | newplugin->next = NULL; | |
155 | if (logplugins_head == NULL) logplugins_head = newplugin; | |
156 | if (logplugins_tail != NULL) logplugins_tail->next = newplugin; | |
157 | logplugins_tail = newplugin; | |
158 | } | |
159 | ||
160 | void LoggerPluginManager::load_plugins(component component_reference, | |
161 | const char *component_name) | |
162 | { | |
163 | if (logplugins_head == NULL) { | |
164 | // The LoggerPlugins option was not used in the configuration file. | |
165 | // The LegacyLogger plug-in is already active; nothing to do. | |
166 | return; | |
167 | } | |
168 | ||
169 | for (logging_plugin_t *p = logplugins_head; p != NULL; p = p->next) { | |
170 | switch (p->component.id_selector) { | |
171 | case COMPONENT_ID_NAME: | |
172 | if (component_name != NULL && | |
173 | !strcmp(p->component.id_name, component_name)) | |
174 | load_plugin(p->identifier, p->filename); | |
175 | break; | |
176 | case COMPONENT_ID_COMPREF: | |
177 | if (p->component.id_compref == component_reference) | |
178 | load_plugin(p->identifier, p->filename); | |
179 | break; | |
180 | case COMPONENT_ID_ALL: | |
181 | load_plugin(p->identifier, p->filename); | |
182 | break; | |
183 | default: | |
184 | break; | |
185 | } | |
186 | } | |
187 | } | |
188 | ||
189 | void LoggerPluginManager::load_plugin(const char *identifier, | |
190 | const char *filename) | |
191 | { | |
192 | bool is_legacylogger = | |
193 | !strncasecmp(identifier, "LegacyLogger", 12) ? true : false; | |
194 | static bool legacylogger_needed = false; | |
195 | if (!legacylogger_needed && is_legacylogger) legacylogger_needed = true; | |
196 | // LegacyLogger was listed explicitly. Otherwise, it's disabled. It is | |
197 | // always loaded as the first element of the list. | |
198 | this->plugins_[0]->set_configured(legacylogger_needed); | |
199 | ||
200 | if (is_legacylogger) { | |
201 | if (filename != NULL) | |
202 | TTCN_warning("The `LegacyLogger' plug-in should not have a path"); | |
203 | return; // It's already in the list. | |
204 | } | |
205 | ||
206 | char *pluginname = (filename != NULL && strlen(filename) > 0) ? | |
207 | mcopystr(filename) : mputprintf(NULL, "%s.%s", identifier, SO_EXTENSION); | |
208 | size_t pluginname_length = strlen(pluginname); | |
209 | for (size_t i = 0; i < this->n_plugins_; ++i) { | |
210 | // Our only static plug-in doesn't have a name, skip it. If we have a | |
211 | // name, we have a dynamic plug-in. | |
212 | if (!this->plugins_[i]->filename_) | |
213 | continue; | |
214 | if (!strncmp(pluginname, this->plugins_[i]->filename_, | |
215 | pluginname_length)) { | |
216 | TTCN_warning("A plug-in from the same path `%s' is already active, " | |
217 | "skipping plug-in", pluginname); | |
218 | Free(pluginname); | |
219 | return; | |
220 | } | |
221 | } | |
222 | ||
223 | this->plugins_ = (LoggerPlugin **)Realloc(this->plugins_, | |
224 | ++this->n_plugins_ * sizeof(LoggerPlugin *)); | |
225 | this->plugins_[this->n_plugins_ - 1] = new LoggerPlugin(pluginname); | |
226 | // Doesn't matter if load fails... | |
227 | Free(pluginname); | |
228 | this->plugins_[this->n_plugins_ - 1]->load(); | |
229 | } | |
230 | ||
231 | extern bool operator==(const component_id_t& left, const component_id_t& right); | |
232 | ||
233 | bool LoggerPluginManager::add_parameter(const logging_setting_t& logging_param) | |
234 | { | |
235 | bool duplication_warning = false; | |
236 | ||
237 | for (logging_setting_t *par = logparams_head; par != NULL; par = par->nextparam) { | |
238 | bool for_all_components = logging_param.component.id_selector == COMPONENT_ID_ALL || par->component.id_selector == COMPONENT_ID_ALL; | |
239 | bool for_all_plugins = logging_param.plugin_id == NULL || par->plugin_id == NULL || | |
240 | !strcmp(logging_param.plugin_id, "*") || !strcmp(par->plugin_id, "*"); | |
241 | bool component_overlaps = for_all_components || logging_param.component == par->component; | |
242 | bool plugin_overlaps = for_all_plugins || !strcmp(logging_param.plugin_id, par->plugin_id); | |
243 | bool parameter_overlaps = logging_param.logparam.log_param_selection == par->logparam.log_param_selection; | |
244 | if (parameter_overlaps && logging_param.logparam.log_param_selection == LP_PLUGIN_SPECIFIC) | |
245 | parameter_overlaps = strcmp(logging_param.logparam.param_name, par->logparam.param_name) == 0; | |
246 | duplication_warning = component_overlaps && plugin_overlaps && parameter_overlaps; | |
247 | if (duplication_warning) | |
248 | break; | |
249 | } | |
250 | ||
251 | logging_setting_t *newparam = new logging_setting_t(logging_param); | |
252 | newparam->nextparam = NULL; | |
253 | if (logparams_head == NULL) logparams_head = newparam; | |
254 | if (logparams_tail != NULL) logparams_tail->nextparam = newparam; | |
255 | logparams_tail = newparam; | |
256 | ||
257 | return duplication_warning; | |
258 | } | |
259 | ||
260 | void LoggerPluginManager::set_parameters(component component_reference, | |
261 | const char *component_name) | |
262 | { | |
263 | if (logparams_head == NULL) return; | |
264 | for (logging_setting_t *par = logparams_head; par != NULL; par = par->nextparam) | |
265 | switch (par->component.id_selector) { | |
266 | case COMPONENT_ID_NAME: | |
267 | if (component_name != NULL && | |
268 | !strcmp(par->component.id_name, component_name)) { | |
269 | apply_parameter(*par); | |
270 | } | |
271 | break; | |
272 | case COMPONENT_ID_COMPREF: | |
273 | if (par->component.id_compref == component_reference) | |
274 | apply_parameter(*par); | |
275 | break; | |
276 | case COMPONENT_ID_ALL: | |
277 | apply_parameter(*par); | |
278 | break; | |
279 | default: | |
280 | break; | |
281 | } | |
282 | } | |
283 | ||
284 | void LoggerPluginManager::apply_parameter(const logging_setting_t& logparam) | |
285 | { | |
286 | if (logparam.plugin_id && !(strlen(logparam.plugin_id) == 1 && !strncmp(logparam.plugin_id, "*", 1))) { | |
287 | // The parameter refers to a specific plug-in. If the plug-in is not | |
288 | // found the execution will stop. | |
289 | LoggerPlugin *plugin = find_plugin(logparam.plugin_id); | |
290 | if (plugin != NULL) { | |
291 | send_parameter_to_plugin(plugin, logparam); | |
292 | } else { | |
293 | TTCN_Logger::fatal_error("Logger plug-in with name `%s' was not found.", logparam.plugin_id); | |
294 | } | |
295 | } else { | |
296 | // The parameter refers to all plug-ins. | |
297 | for (size_t i = 0; i < this->n_plugins_; i++) { | |
298 | send_parameter_to_plugin(this->plugins_[i], logparam); | |
299 | } | |
300 | } | |
301 | } | |
302 | ||
303 | void LoggerPluginManager::send_parameter_to_plugin(LoggerPlugin *plugin, | |
304 | const logging_setting_t& logparam) | |
305 | { | |
306 | switch (logparam.logparam.log_param_selection) { | |
307 | case LP_FILEMASK: | |
308 | TTCN_Logger::set_file_mask(logparam.component, | |
309 | logparam.logparam.logoptions_val); | |
310 | break; | |
311 | case LP_CONSOLEMASK: | |
312 | TTCN_Logger::set_console_mask(logparam.component, | |
313 | logparam.logparam.logoptions_val); | |
314 | break; | |
315 | case LP_LOGFILESIZE: | |
316 | plugin->set_file_size(logparam.logparam.int_val); | |
317 | break; | |
318 | case LP_LOGFILENUMBER: | |
319 | plugin->set_file_number(logparam.logparam.int_val); | |
320 | break; | |
321 | case LP_DISKFULLACTION: | |
322 | plugin->set_disk_full_action(logparam.logparam.disk_full_action_value); | |
323 | break; | |
324 | case LP_LOGFILE: | |
325 | plugin->set_file_name(logparam.logparam.str_val, true); | |
326 | break; | |
327 | case LP_TIMESTAMPFORMAT: | |
328 | TTCN_Logger::set_timestamp_format(logparam.logparam.timestamp_value); | |
329 | break; | |
330 | case LP_SOURCEINFOFORMAT: | |
331 | TTCN_Logger::set_source_info_format(logparam.logparam.source_info_value); | |
332 | break; | |
333 | case LP_APPENDFILE: | |
334 | plugin->set_append_file(logparam.logparam.bool_val); | |
335 | break; | |
336 | case LP_LOGEVENTTYPES: | |
337 | TTCN_Logger::set_log_event_types(logparam.logparam.log_event_types_value); | |
338 | break; | |
339 | case LP_LOGENTITYNAME: | |
340 | TTCN_Logger::set_log_entity_name(logparam.logparam.bool_val); | |
341 | break; | |
342 | case LP_MATCHINGHINTS: | |
343 | TTCN_Logger::set_matching_verbosity(logparam.logparam.matching_verbosity_value); | |
344 | break; | |
345 | case LP_PLUGIN_SPECIFIC: | |
346 | plugin->set_parameter(logparam.logparam.param_name, logparam.logparam.str_val); | |
347 | break; | |
348 | case LP_EMERGENCY: | |
349 | TTCN_Logger::set_emergency_logging(logparam.logparam.emergency_logging); | |
350 | ring_buffer.set_size(TTCN_Logger::get_emergency_logging()); | |
351 | break; | |
352 | case LP_EMERGENCYBEHAVIOR: | |
353 | TTCN_Logger::set_emergency_logging_behaviour(logparam.logparam.emergency_logging_behaviour_value); | |
354 | break; | |
355 | case LP_EMERGENCYMASK: | |
356 | TTCN_Logger::set_emergency_logging_mask(logparam.component, | |
357 | logparam.logparam.logoptions_val); | |
358 | break; | |
359 | default: | |
360 | break; | |
361 | } | |
362 | } | |
363 | ||
364 | void LoggerPluginManager::clear_param_list() | |
365 | { | |
366 | for (logging_setting_t *par = logparams_head; par != NULL;) { | |
367 | Free(par->plugin_id); | |
368 | switch (par->logparam.log_param_selection) { | |
369 | case LP_PLUGIN_SPECIFIC: | |
370 | Free(par->logparam.param_name); | |
371 | // no break | |
372 | case LP_LOGFILE: | |
373 | Free(par->logparam.str_val); | |
374 | break; | |
375 | default: | |
376 | break; | |
377 | } | |
378 | if (par->component.id_selector == COMPONENT_ID_NAME) | |
379 | Free(par->component.id_name); | |
380 | logging_setting_t *tmp = par; | |
381 | par = par->nextparam; | |
382 | delete tmp; | |
383 | } | |
384 | logparams_head = logparams_tail = NULL; | |
385 | } | |
386 | ||
387 | void LoggerPluginManager::clear_plugin_list() | |
388 | { | |
389 | for (logging_plugin_t *plugin = logplugins_head; plugin != NULL;) { | |
390 | if (plugin->component.id_selector == COMPONENT_ID_NAME) | |
391 | Free(plugin->component.id_name); | |
392 | Free(plugin->identifier); | |
393 | Free(plugin->filename); | |
394 | logging_plugin_t *tmp = plugin; | |
395 | plugin = plugin->next; | |
396 | delete tmp; | |
397 | } | |
398 | logplugins_head = logplugins_tail = NULL; | |
399 | } | |
400 | ||
401 | void LoggerPluginManager::set_file_name(const char *new_filename_skeleton, | |
402 | bool from_config) | |
403 | { | |
404 | for (size_t i = 0; i < this->n_plugins_; ++i) | |
405 | this->plugins_[i]->set_file_name(new_filename_skeleton, from_config); | |
406 | } | |
407 | ||
408 | void LoggerPluginManager::reset() | |
409 | { | |
410 | for (size_t i = 0; i < this->n_plugins_; ++i) | |
411 | this->plugins_[i]->reset(); | |
412 | } | |
413 | ||
414 | void LoggerPluginManager::set_append_file(bool new_append_file) | |
415 | { | |
416 | for (size_t i = 0; i < this->n_plugins_; ++i) | |
417 | this->plugins_[i]->set_append_file(new_append_file); | |
418 | } | |
419 | ||
420 | bool LoggerPluginManager::set_file_size(component_id_t const& /*comp*/, int p_size) | |
421 | { | |
422 | bool ret_val = false; | |
423 | for (size_t i = 0; i < this->n_plugins_; ++i) | |
424 | if (this->plugins_[i]->set_file_size(p_size)) | |
425 | ret_val = true; | |
426 | return ret_val; | |
427 | } | |
428 | ||
429 | bool LoggerPluginManager::set_file_number(component_id_t const& /*comp*/, int p_number) | |
430 | { | |
431 | bool ret_val = false; | |
432 | for (size_t i = 0; i < this->n_plugins_; ++i) | |
433 | if (this->plugins_[i]->set_file_number(p_number)) | |
434 | ret_val = true; | |
435 | return ret_val; | |
436 | } | |
437 | ||
438 | bool LoggerPluginManager::set_disk_full_action(component_id_t const& /*comp*/, | |
439 | TTCN_Logger::disk_full_action_t p_disk_full_action) | |
440 | { | |
441 | bool ret_val = false; | |
442 | for (size_t i = 0; i < this->n_plugins_; ++i) | |
443 | if (this->plugins_[i]->set_disk_full_action(p_disk_full_action)) | |
444 | ret_val = true; | |
445 | return ret_val; | |
446 | } | |
447 | ||
448 | void LoggerPluginManager::open_file() | |
449 | { | |
450 | static bool is_first = true; | |
451 | bool free_entry_list = false; | |
452 | assert(this->n_plugins_ > 0); | |
453 | // In case of `EXECUTOR_LOGOPTIONS' write updated | |
454 | // `write_logger_settings(true)'. Try to log the buffered events, they not | |
455 | // necessarily be logged otherwise. | |
456 | for (size_t i = 0; i < this->n_plugins_; ++i) { | |
457 | this->plugins_[i]->open_file(is_first); | |
458 | if (this->plugins_[i]->is_configured()) { | |
459 | free_entry_list = true; | |
460 | LogEntry *entry = this->entry_list_, *next_entry = NULL; | |
461 | while (entry != NULL) { | |
462 | next_entry = entry->next_entry_; | |
463 | if ((TTCN_Logger::Severity)(int)entry->event_.severity() == | |
464 | TTCN_Logger::EXECUTOR_LOGOPTIONS) { | |
465 | char *new_log_message = TTCN_Logger::get_logger_settings_str(); | |
466 | entry->event_.logEvent().choice().executorEvent().choice().logOptions() = | |
467 | CHARSTRING(mstrlen(new_log_message), new_log_message); | |
468 | Free(new_log_message); | |
469 | } | |
470 | this->plugins_[i]->log(entry->event_, true, false, false); | |
471 | entry = next_entry; | |
472 | } | |
473 | } | |
474 | } | |
475 | if (free_entry_list) { | |
476 | while (this->entry_list_ != NULL) { | |
477 | LogEntry *next_entry = this->entry_list_->next_entry_; | |
478 | delete this->entry_list_; | |
479 | this->entry_list_ = next_entry; | |
480 | } | |
481 | this->entry_list_ = NULL; | |
482 | } | |
483 | is_first = false; | |
484 | } | |
485 | ||
486 | void LoggerPluginManager::close_file() | |
487 | { | |
488 | ||
489 | while (this->current_event_ != NULL) | |
490 | finish_event(); | |
491 | ||
492 | ring_buffer_dump(true); | |
493 | } | |
494 | ||
495 | void LoggerPluginManager::unload_plugins() | |
496 | { | |
497 | for (size_t i = 0; i < n_plugins_; ++i) | |
498 | plugins_[i]->unload(); | |
499 | } | |
500 | ||
501 | void LoggerPluginManager::fill_common_fields(API::TitanLogEvent& event, | |
502 | const TTCN_Logger::Severity& severity) | |
503 | { | |
504 | // Check at compile time that entity type can be directly assigned. | |
505 | ENSURE_EQUAL(API::LocationInfo_ent__type::unknown , TTCN_Location::LOCATION_UNKNOWN); | |
506 | ENSURE_EQUAL(API::LocationInfo_ent__type::controlpart, TTCN_Location::LOCATION_CONTROLPART); | |
507 | ENSURE_EQUAL(API::LocationInfo_ent__type::testcase__ , TTCN_Location::LOCATION_TESTCASE); | |
508 | ENSURE_EQUAL(API::LocationInfo_ent__type::altstep__ , TTCN_Location::LOCATION_ALTSTEP); | |
509 | ENSURE_EQUAL(API::LocationInfo_ent__type::function__ , TTCN_Location::LOCATION_FUNCTION); | |
510 | ENSURE_EQUAL(API::LocationInfo_ent__type::external__function, TTCN_Location::LOCATION_EXTERNALFUNCTION); | |
511 | ENSURE_EQUAL(API::LocationInfo_ent__type::template__ , TTCN_Location::LOCATION_TEMPLATE); | |
512 | ||
513 | // The detailed timestamp is used by the plug-ins. Don't stringify in this | |
514 | // stage. E.g. DISKFULL_RETRY uses these for comparison. TODO: Severity | |
515 | // should be an optional field, since the type of the event (in the XSD) is | |
516 | // always clear. It's now used to handle unhandled events. | |
517 | struct timeval tv; | |
518 | if (gettimeofday(&tv, NULL) < 0) | |
519 | TTCN_Logger::fatal_error("The gettimeofday() system call failed."); | |
520 | event.timestamp() = API::TimestampType(tv.tv_sec, tv.tv_usec); | |
521 | TTCN_Logger::source_info_format_t source_info_format = | |
522 | TTCN_Logger::get_source_info_format(); | |
523 | API::TitanLogEvent_sourceInfo__list& srcinfo = event.sourceInfo__list(); | |
524 | srcinfo = NULL_VALUE; // Make sure it's bound. | |
525 | if (source_info_format != TTCN_Logger::SINFO_NONE) { | |
526 | if (TTCN_Location::innermost_location != NULL) { | |
527 | size_t num_locations = 0; | |
528 | for (TTCN_Location *iter = TTCN_Location::outermost_location; iter != NULL; iter = iter->inner_location) { | |
529 | API::LocationInfo& loc = srcinfo[num_locations++]; | |
530 | loc.filename() = iter->file_name; | |
531 | loc.line() = iter->line_number; | |
532 | loc.ent__type() = iter->entity_type; | |
533 | loc.ent__name() = iter->entity_name; | |
534 | } | |
535 | } | |
536 | } | |
537 | event.severity() = severity; | |
538 | } | |
539 | ||
540 | void LoggerPluginManager::internal_prebuff_logevent(const TitanLoggerApi::TitanLogEvent& event) | |
541 | { | |
542 | LogEntry *new_entry = new LogEntry; | |
543 | new_entry->event_ = event; | |
544 | new_entry->next_entry_ = NULL; | |
545 | if (!this->entry_list_) { | |
546 | this->entry_list_ = new_entry; | |
547 | } else { | |
548 | LogEntry *current_entry = this->entry_list_; | |
549 | for (; current_entry; current_entry = current_entry->next_entry_) | |
550 | if (!current_entry->next_entry_) break; | |
551 | current_entry->next_entry_ = new_entry; | |
552 | } | |
553 | } | |
554 | ||
555 | void LoggerPluginManager::internal_log_prebuff_logevent() | |
556 | { | |
557 | LogEntry *entry = this->entry_list_, *next_entry = NULL; | |
558 | while (entry != NULL) { | |
559 | next_entry = entry->next_entry_; | |
560 | if ((TTCN_Logger::Severity)(int)entry->event_.severity() == | |
561 | TTCN_Logger::EXECUTOR_LOGOPTIONS) { | |
562 | char *new_log_message = TTCN_Logger::get_logger_settings_str(); | |
563 | entry->event_.logEvent().choice().executorEvent().choice().logOptions() = | |
564 | CHARSTRING(mstrlen(new_log_message), new_log_message); | |
565 | Free(new_log_message); | |
566 | } | |
567 | internal_log_to_all(entry->event_, true, false, false); | |
568 | delete entry; | |
569 | entry = next_entry; | |
570 | } | |
571 | ||
572 | this->entry_list_ = NULL; | |
573 | } | |
574 | ||
575 | void LoggerPluginManager::internal_log_to_all(const TitanLoggerApi::TitanLogEvent& event, | |
576 | bool log_buffered, bool separate_file, bool use_emergency_mask) | |
577 | { | |
578 | for (size_t i = 0; i < this->n_plugins_; ++i) { | |
579 | if (this->plugins_[i]->is_configured()) { | |
580 | this->plugins_[i]->log(event, log_buffered, separate_file, use_emergency_mask); | |
581 | } | |
582 | } | |
583 | } | |
584 | ||
585 | bool LoggerPluginManager::plugins_ready() const | |
586 | { | |
587 | for (size_t i = 0; i < this->n_plugins_; ++i) { | |
588 | if (this->plugins_[i]->is_configured()) { | |
589 | return true; | |
590 | } | |
591 | } | |
592 | return false; | |
593 | } | |
594 | ||
595 | void LoggerPluginManager::log(const API::TitanLogEvent& event) | |
596 | { | |
597 | if (!plugins_ready()) { | |
598 | // buffer quick events | |
599 | internal_prebuff_logevent(event); | |
600 | return; | |
601 | } | |
602 | ||
603 | // Init phase, log prebuffered events first if any. | |
604 | internal_log_prebuff_logevent(); | |
605 | ||
606 | if (TTCN_Logger::get_emergency_logging() == 0) { | |
607 | // If emergency buffering is not needed log the event | |
608 | internal_log_to_all(event, false, false, false); | |
609 | return; | |
610 | } | |
611 | ||
612 | // Log the buffered events first, if any. In the current scheme, | |
613 | // open_file() has already flushed this buffer at this time. | |
614 | // Send the event to the plugin if it is necessary. | |
615 | // ring_buffer content fill up | |
616 | if (TTCN_Logger::get_emergency_logging_behaviour() == TTCN_Logger::BUFFER_MASKED) { | |
617 | //ToDo: do it nicer | |
618 | //if(TTCN_Logger::log_this_event((TTCN_Logger::Severity)(int)event.severity())){ | |
3f84031e | 619 | internal_log_to_all(event, true, false, false); |
620 | if (!TTCN_Logger::should_log_to_file((TTCN_Logger::Severity)(int)event.severity()) && | |
621 | TTCN_Logger::should_log_to_emergency((TTCN_Logger::Severity)(int)event.severity())) { | |
622 | ring_buffer.put(event); | |
970ed795 EL |
623 | } |
624 | } else if (TTCN_Logger::get_emergency_logging_behaviour() == TTCN_Logger::BUFFER_ALL) { | |
625 | if (ring_buffer.isFull()) { | |
626 | TitanLoggerApi::TitanLogEvent ring_event; | |
627 | // the ring buffer is full, get the the oldest event | |
628 | // check does the user want this to be logged | |
629 | if (ring_buffer.get(ring_event)) { | |
630 | internal_log_to_all(ring_event, true, false, false); | |
631 | } else { | |
632 | // it is not wanted by the user, throw it away | |
633 | } | |
634 | } | |
635 | ring_buffer.put(event); | |
636 | } | |
637 | // ERROR, flush the ring buffer content | |
638 | if ((TTCN_Logger::Severity)(int)event.severity() == TTCN_Logger::ERROR_UNQUALIFIED) { | |
639 | TitanLoggerApi::TitanLogEvent ring_event; | |
640 | // get all the events from the ring: buffer | |
641 | while (!ring_buffer.isEmpty()) { | |
642 | if (ring_buffer.get(ring_event)) { | |
643 | if (TTCN_Logger::get_emergency_logging_behaviour() == TTCN_Logger::BUFFER_MASKED) { | |
644 | internal_log_to_all(ring_event, true, true, false); // log in separate file | |
645 | } else if (TTCN_Logger::get_emergency_logging_behaviour() == TTCN_Logger::BUFFER_ALL) { | |
646 | internal_log_to_all(ring_event, true, false, true); // DO NOT log in separate file | |
647 | } | |
648 | } | |
649 | } | |
650 | ||
651 | ring_buffer.clear(); | |
652 | } | |
653 | } | |
654 | ||
655 | // Start of externally callable log functions | |
656 | void LoggerPluginManager::log_unhandled_event(TTCN_Logger::Severity severity, | |
657 | const char *message_ptr, | |
658 | size_t message_len) | |
659 | { | |
660 | if (!TTCN_Logger::log_this_event(severity) && (TTCN_Logger::get_emergency_logging()<=0)) return; | |
661 | API::TitanLogEvent event; | |
662 | fill_common_fields(event, severity); | |
663 | ||
664 | event.logEvent().choice().unhandledEvent() = CHARSTRING(message_len, message_ptr); | |
665 | log(event); | |
666 | } | |
667 | ||
668 | void LoggerPluginManager::log_log_options(const char *message_ptr, | |
669 | size_t message_len) | |
670 | { | |
671 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_LOGOPTIONS) && (TTCN_Logger::get_emergency_logging()<=0)) | |
672 | return; | |
673 | API::TitanLogEvent event; | |
674 | fill_common_fields(event, TTCN_Logger::EXECUTOR_LOGOPTIONS); | |
675 | ||
676 | event.logEvent().choice().executorEvent().choice().logOptions() = | |
677 | CHARSTRING(message_len, message_ptr); | |
678 | log(event); | |
679 | } | |
680 | ||
681 | void LoggerPluginManager::log_timer_read(const char *timer_name, | |
682 | double start_val) | |
683 | { | |
684 | if (!TTCN_Logger::log_this_event(TTCN_Logger::TIMEROP_READ) && (TTCN_Logger::get_emergency_logging()<=0)) | |
685 | return; | |
686 | API::TitanLogEvent event; | |
687 | fill_common_fields(event, TTCN_Logger::TIMEROP_READ); | |
688 | ||
689 | API::TimerType& timer = event.logEvent().choice().timerEvent().choice().readTimer(); | |
690 | timer.name() = timer_name; | |
691 | timer.value__() = start_val; | |
692 | log(event); | |
693 | } | |
694 | ||
695 | void LoggerPluginManager::log_timer_start(const char *timer_name, | |
696 | double start_val) | |
697 | { | |
698 | if (!TTCN_Logger::log_this_event(TTCN_Logger::TIMEROP_START) && (TTCN_Logger::get_emergency_logging()<=0)) | |
699 | return; | |
700 | API::TitanLogEvent event; | |
701 | fill_common_fields(event, TTCN_Logger::TIMEROP_START); | |
702 | ||
703 | API::TimerType& timer = event.logEvent().choice().timerEvent().choice().startTimer(); | |
704 | timer.name() = timer_name; | |
705 | timer.value__() = start_val; | |
706 | log(event); | |
707 | } | |
708 | ||
709 | void LoggerPluginManager::log_timer_guard(double start_val) | |
710 | { | |
711 | if (!TTCN_Logger::log_this_event(TTCN_Logger::TIMEROP_GUARD) && (TTCN_Logger::get_emergency_logging()<=0)) | |
712 | return; | |
713 | API::TitanLogEvent event; | |
714 | fill_common_fields(event, TTCN_Logger::TIMEROP_GUARD); | |
715 | ||
716 | API::TimerGuardType& timer = event.logEvent().choice().timerEvent().choice().guardTimer(); | |
717 | timer.value__() = start_val; | |
718 | log(event); | |
719 | } | |
720 | ||
721 | void LoggerPluginManager::log_timer_stop(const char *timer_name, | |
722 | double stop_val) | |
723 | { | |
724 | if (!TTCN_Logger::log_this_event(TTCN_Logger::TIMEROP_STOP) && (TTCN_Logger::get_emergency_logging()<=0)) | |
725 | return; | |
726 | API::TitanLogEvent event; | |
727 | fill_common_fields(event, TTCN_Logger::TIMEROP_STOP); | |
728 | ||
729 | API::TimerType& timer = event.logEvent().choice().timerEvent().choice().stopTimer(); | |
730 | timer.name() = timer_name; | |
731 | timer.value__() = stop_val; | |
732 | log(event); | |
733 | } | |
734 | ||
735 | void LoggerPluginManager::log_timer_timeout(const char *timer_name, | |
736 | double timeout_val) | |
737 | { | |
738 | if (!TTCN_Logger::log_this_event(TTCN_Logger::TIMEROP_TIMEOUT) && (TTCN_Logger::get_emergency_logging()<=0)) | |
739 | return; | |
740 | API::TitanLogEvent event; | |
741 | fill_common_fields(event, TTCN_Logger::TIMEROP_TIMEOUT); | |
742 | ||
743 | API::TimerType& timer = event.logEvent().choice().timerEvent().choice().timeoutTimer(); | |
744 | timer.name() = timer_name; | |
745 | timer.value__() = timeout_val; | |
746 | log(event); | |
747 | } | |
748 | ||
749 | void LoggerPluginManager::log_timer_any_timeout() | |
750 | { | |
751 | if (!TTCN_Logger::log_this_event(TTCN_Logger::TIMEROP_TIMEOUT) && (TTCN_Logger::get_emergency_logging()<=0)) | |
752 | return; | |
753 | API::TitanLogEvent event; | |
754 | fill_common_fields(event, TTCN_Logger::TIMEROP_TIMEOUT); | |
755 | ||
756 | // Make `ALT_timeoutAnyTimer' selected in the union. No data fields here. | |
757 | event.logEvent().choice().timerEvent().choice().timeoutAnyTimer() = NULL_VALUE; | |
758 | log(event); | |
759 | } | |
760 | ||
761 | void LoggerPluginManager::log_timer_unqualified(const char *message) | |
762 | { | |
763 | if (!TTCN_Logger::log_this_event(TTCN_Logger::TIMEROP_UNQUALIFIED) && (TTCN_Logger::get_emergency_logging()<=0)) | |
764 | return; | |
765 | API::TitanLogEvent event; | |
766 | fill_common_fields(event, TTCN_Logger::TIMEROP_UNQUALIFIED); | |
767 | ||
768 | event.logEvent().choice().timerEvent().choice().unqualifiedTimer() = message; | |
769 | log(event); | |
770 | } | |
771 | ||
772 | void LoggerPluginManager::log_testcase_started(const qualified_name& testcase_name) | |
773 | { | |
774 | if (!TTCN_Logger::log_this_event(TTCN_Logger::TESTCASE_START) && (TTCN_Logger::get_emergency_logging()<=0)) | |
775 | return; | |
776 | API::TitanLogEvent event; | |
777 | fill_common_fields(event, TTCN_Logger::TESTCASE_START); | |
778 | ||
779 | API::QualifiedName& qname = event.logEvent().choice().testcaseOp().choice().testcaseStarted(); | |
780 | qname.module__name () = testcase_name.module_name; | |
781 | qname.testcase__name() = testcase_name.definition_name; | |
782 | log(event); | |
783 | } | |
784 | ||
785 | void LoggerPluginManager::log_testcase_finished(const qualified_name& testcase_name, | |
786 | verdicttype verdict, | |
787 | const char *reason) | |
788 | { | |
789 | if (!TTCN_Logger::log_this_event(TTCN_Logger::TESTCASE_FINISH) && (TTCN_Logger::get_emergency_logging()<=0)) | |
790 | return; | |
791 | API::TitanLogEvent event; | |
792 | fill_common_fields(event, TTCN_Logger::TESTCASE_FINISH); | |
793 | ||
794 | API::TestcaseType& testcase = event.logEvent().choice().testcaseOp().choice().testcaseFinished(); | |
795 | API::QualifiedName& qname = testcase.name(); | |
796 | qname.module__name () = testcase_name.module_name; | |
797 | qname.testcase__name() = testcase_name.definition_name; | |
798 | testcase.verdict() = verdict; | |
799 | testcase.reason() = reason; | |
800 | // FIXME: our caller had a CHARSTRING but gave us a C string. Now we have to measure it again :( | |
801 | log(event); | |
802 | } | |
803 | ||
804 | void LoggerPluginManager::log_controlpart_start_stop(const char *module_name, int finished) | |
805 | { | |
806 | if (!TTCN_Logger::log_this_event(TTCN_Logger::STATISTICS_UNQUALIFIED) && (TTCN_Logger::get_emergency_logging()<=0)) | |
807 | return; | |
808 | API::TitanLogEvent event; | |
809 | fill_common_fields(event, TTCN_Logger::STATISTICS_UNQUALIFIED); | |
810 | ||
811 | API::StatisticsType& stats = event.logEvent().choice().statistics(); | |
812 | if (finished) stats.choice().controlpartFinish() = module_name; | |
813 | else stats.choice().controlpartStart() = module_name; | |
814 | log(event); | |
815 | } | |
816 | ||
817 | void LoggerPluginManager::log_controlpart_errors(unsigned int error_count) | |
818 | { | |
819 | if (!TTCN_Logger::log_this_event(TTCN_Logger::STATISTICS_UNQUALIFIED) && (TTCN_Logger::get_emergency_logging()<=0)) | |
820 | return; | |
821 | API::TitanLogEvent event; | |
822 | fill_common_fields(event, TTCN_Logger::STATISTICS_UNQUALIFIED); | |
823 | ||
824 | event.logEvent().choice().statistics().choice().controlpartErrors() = error_count; | |
825 | log(event); | |
826 | } | |
827 | ||
828 | void LoggerPluginManager::log_setverdict(verdicttype new_verdict, verdicttype old_verdict, | |
829 | verdicttype local_verdict, const char *old_reason, const char *new_reason) | |
830 | { | |
831 | if (!TTCN_Logger::log_this_event(TTCN_Logger::VERDICTOP_SETVERDICT) && (TTCN_Logger::get_emergency_logging()<=0)) | |
832 | return; | |
833 | API::TitanLogEvent event; | |
834 | fill_common_fields(event, TTCN_Logger::VERDICTOP_SETVERDICT); | |
835 | API::SetVerdictType& set = event.logEvent().choice().verdictOp().choice().setVerdict(); | |
836 | set.newVerdict() = new_verdict; | |
837 | set.oldVerdict() = old_verdict; | |
838 | set.localVerdict() = local_verdict; | |
839 | if (old_reason != NULL) set.oldReason() = old_reason; | |
840 | else set.oldReason() = OMIT_VALUE; | |
841 | if (new_reason != NULL) set.newReason() = new_reason; | |
842 | else set.newReason() = OMIT_VALUE; | |
843 | log(event); | |
844 | } | |
845 | ||
846 | void LoggerPluginManager::log_getverdict(verdicttype verdict) | |
847 | { | |
848 | if (!TTCN_Logger::log_this_event(TTCN_Logger::VERDICTOP_GETVERDICT) && (TTCN_Logger::get_emergency_logging()<=0)) | |
849 | return; | |
850 | API::TitanLogEvent event; | |
851 | fill_common_fields(event, TTCN_Logger::VERDICTOP_GETVERDICT); | |
852 | event.logEvent().choice().verdictOp().choice().getVerdict() = verdict; | |
853 | log(event); | |
854 | } | |
855 | ||
856 | void LoggerPluginManager::log_final_verdict(bool is_ptc, | |
857 | verdicttype ptc_verdict, verdicttype local_verdict, verdicttype new_verdict, | |
858 | const char *verdict__reason, int notification, int ptc_compref, | |
859 | const char *ptc_name) | |
860 | { | |
861 | if (!TTCN_Logger::log_this_event(TTCN_Logger::VERDICTOP_FINAL) && (TTCN_Logger::get_emergency_logging()<=0)) | |
862 | return; | |
863 | API::TitanLogEvent event; | |
864 | fill_common_fields(event, TTCN_Logger::VERDICTOP_FINAL); | |
865 | API::FinalVerdictType& final = event.logEvent().choice().verdictOp().choice().finalVerdict(); | |
866 | if (notification >= 0) { | |
867 | final.choice().notification() = notification; | |
868 | } else { | |
869 | final.choice().info().is__ptc() = is_ptc; | |
870 | final.choice().info().ptc__verdict() = ptc_verdict; | |
871 | final.choice().info().local__verdict() = local_verdict; | |
872 | final.choice().info().new__verdict() = new_verdict; | |
873 | final.choice().info().ptc__compref() = ptc_compref; | |
874 | if (verdict__reason != NULL) | |
875 | final.choice().info().verdict__reason() = verdict__reason; | |
876 | else final.choice().info().verdict__reason() = OMIT_VALUE; | |
877 | if (ptc_name != NULL) | |
878 | final.choice().info().ptc__name() = ptc_name; | |
879 | else final.choice().info().ptc__name() = OMIT_VALUE; | |
880 | } | |
881 | log(event); | |
882 | } | |
883 | ||
884 | void LoggerPluginManager::log_verdict_statistics(size_t none_count, double none_percent, | |
885 | size_t pass_count, double pass_percent, | |
886 | size_t inconc_count, double inconc_percent, | |
887 | size_t fail_count, double fail_percent, | |
888 | size_t error_count, double error_percent) | |
889 | { | |
890 | if (!TTCN_Logger::log_this_event(TTCN_Logger::STATISTICS_VERDICT) && (TTCN_Logger::get_emergency_logging()<=0)) | |
891 | return; | |
892 | API::TitanLogEvent event; | |
893 | fill_common_fields(event, TTCN_Logger::STATISTICS_VERDICT); | |
894 | ||
895 | API::StatisticsType& statistics = event.logEvent().choice().statistics(); | |
896 | statistics.choice().verdictStatistics().none__() = none_count; | |
897 | statistics.choice().verdictStatistics().nonePercent() = none_percent; | |
898 | statistics.choice().verdictStatistics().pass__() = pass_count; | |
899 | statistics.choice().verdictStatistics().passPercent() = pass_percent; | |
900 | statistics.choice().verdictStatistics().inconc__() = inconc_count; | |
901 | statistics.choice().verdictStatistics().inconcPercent() = inconc_percent; | |
902 | statistics.choice().verdictStatistics().fail__() = fail_count; | |
903 | statistics.choice().verdictStatistics().failPercent() = fail_percent; | |
904 | statistics.choice().verdictStatistics().error__() = error_count; | |
905 | statistics.choice().verdictStatistics().errorPercent() = error_percent; | |
906 | log(event); | |
907 | } | |
908 | ||
909 | void LoggerPluginManager::log_defaultop_activate(const char *name, int id) | |
910 | { | |
911 | if (!TTCN_Logger::log_this_event(TTCN_Logger::DEFAULTOP_ACTIVATE) && (TTCN_Logger::get_emergency_logging()<=0)) | |
912 | return; | |
913 | API::TitanLogEvent event; | |
914 | fill_common_fields(event, TTCN_Logger::DEFAULTOP_ACTIVATE); | |
915 | ||
916 | API::DefaultOp& defaultop = event.logEvent().choice().defaultEvent().choice().defaultopActivate(); | |
917 | defaultop.name() = name; | |
918 | defaultop.id() = id; | |
919 | defaultop.end() = API::DefaultEnd::UNKNOWN_VALUE; // don't care | |
920 | log(event); | |
921 | } | |
922 | ||
923 | void LoggerPluginManager::log_defaultop_deactivate(const char *name, int id) | |
924 | { | |
925 | if (!TTCN_Logger::log_this_event(TTCN_Logger::DEFAULTOP_DEACTIVATE) && (TTCN_Logger::get_emergency_logging()<=0)) | |
926 | return; | |
927 | API::TitanLogEvent event; | |
928 | fill_common_fields(event, TTCN_Logger::DEFAULTOP_DEACTIVATE); | |
929 | ||
930 | API::DefaultOp& defaultop = event.logEvent().choice().defaultEvent().choice().defaultopDeactivate(); | |
931 | defaultop.name() = name; | |
932 | defaultop.id() = id; | |
933 | defaultop.end() = API::DefaultEnd::UNKNOWN_VALUE; // don't care | |
934 | log(event); // whoa, deja vu! | |
935 | } | |
936 | ||
937 | void LoggerPluginManager::log_defaultop_exit(const char *name, int id, int x) | |
938 | { | |
939 | if (!TTCN_Logger::log_this_event(TTCN_Logger::DEFAULTOP_EXIT) && (TTCN_Logger::get_emergency_logging()<=0)) | |
940 | return; | |
941 | API::TitanLogEvent event; | |
942 | fill_common_fields(event, TTCN_Logger::DEFAULTOP_EXIT); | |
943 | ||
944 | API::DefaultOp& defaultop = event.logEvent().choice().defaultEvent().choice().defaultopExit(); | |
945 | defaultop.name() = name; | |
946 | defaultop.id() = id; | |
947 | defaultop.end() = x; | |
948 | log(event); | |
949 | } | |
950 | ||
951 | void LoggerPluginManager::log_executor_runtime(API::ExecutorRuntime_reason reason) | |
952 | { | |
953 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_RUNTIME) && (TTCN_Logger::get_emergency_logging()<=0)) | |
954 | return; | |
955 | API::TitanLogEvent event; | |
956 | fill_common_fields(event, TTCN_Logger::EXECUTOR_RUNTIME); | |
957 | ||
958 | API::ExecutorRuntime& exec = event.logEvent().choice().executorEvent().choice().executorRuntime(); | |
959 | exec.reason() = reason; | |
960 | exec.module__name() = OMIT_VALUE; | |
961 | exec.testcase__name() = OMIT_VALUE; | |
962 | exec.pid() = OMIT_VALUE; | |
963 | exec.fd__setsize() = OMIT_VALUE; | |
964 | log(event); | |
965 | } | |
966 | ||
967 | void LoggerPluginManager::log_HC_start(const char *host) | |
968 | { | |
969 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_RUNTIME) && (TTCN_Logger::get_emergency_logging()<=0)) | |
970 | return; | |
971 | API::TitanLogEvent event; | |
972 | fill_common_fields(event, TTCN_Logger::EXECUTOR_RUNTIME); | |
973 | ||
974 | API::ExecutorRuntime& exec = event.logEvent().choice().executorEvent().choice().executorRuntime(); | |
975 | exec.reason() = API::ExecutorRuntime_reason::host__controller__started; | |
976 | exec.module__name() = host; // "reuse" charstring member | |
977 | exec.testcase__name() = OMIT_VALUE; | |
978 | exec.pid() = OMIT_VALUE; | |
979 | exec.fd__setsize() = OMIT_VALUE; | |
980 | log(event); | |
981 | } | |
982 | ||
983 | void LoggerPluginManager::log_fd_limits(int fd_limit, long fd_set_size) | |
984 | { | |
985 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_RUNTIME) && (TTCN_Logger::get_emergency_logging()<=0)) | |
986 | return; | |
987 | API::TitanLogEvent event; | |
988 | fill_common_fields(event, TTCN_Logger::EXECUTOR_RUNTIME); | |
989 | ||
990 | API::ExecutorRuntime& exec = event.logEvent().choice().executorEvent().choice().executorRuntime(); | |
991 | exec.reason() = API::ExecutorRuntime_reason::fd__limits; | |
992 | exec.module__name() = OMIT_VALUE; | |
993 | exec.testcase__name() = OMIT_VALUE; | |
994 | exec.pid() = fd_limit; | |
995 | exec.fd__setsize() = fd_set_size; | |
996 | log(event); | |
997 | } | |
998 | ||
999 | void LoggerPluginManager::log_not_overloaded(int pid) | |
1000 | { | |
1001 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_RUNTIME) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1002 | return; | |
1003 | API::TitanLogEvent event; | |
1004 | fill_common_fields(event, TTCN_Logger::EXECUTOR_RUNTIME); | |
1005 | ||
1006 | API::ExecutorRuntime& exec = event.logEvent().choice().executorEvent().choice().executorRuntime(); | |
1007 | exec.reason() = API::ExecutorRuntime_reason::overloaded__no__more; | |
1008 | exec.module__name() = OMIT_VALUE; | |
1009 | exec.testcase__name() = OMIT_VALUE; | |
1010 | exec.pid() = pid; | |
1011 | exec.fd__setsize() = OMIT_VALUE; | |
1012 | log(event); | |
1013 | } | |
1014 | ||
1015 | void LoggerPluginManager::log_testcase_exec(const char *tc, const char *module) | |
1016 | { | |
1017 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_RUNTIME) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1018 | return; | |
1019 | API::TitanLogEvent event; | |
1020 | fill_common_fields(event, TTCN_Logger::EXECUTOR_RUNTIME); | |
1021 | ||
1022 | API::ExecutorRuntime& exec = event.logEvent().choice().executorEvent().choice().executorRuntime(); | |
1023 | exec.reason() = API::ExecutorRuntime_reason::executing__testcase__in__module; | |
1024 | exec.module__name() = module; | |
1025 | exec.testcase__name() = tc; | |
1026 | exec.pid() = OMIT_VALUE; | |
1027 | exec.fd__setsize() = OMIT_VALUE; | |
1028 | log(event); | |
1029 | } | |
1030 | ||
1031 | void LoggerPluginManager::log_module_init(const char *module, bool finish) | |
1032 | { | |
1033 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_RUNTIME) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1034 | return; | |
1035 | API::TitanLogEvent event; | |
1036 | fill_common_fields(event, TTCN_Logger::EXECUTOR_RUNTIME); | |
1037 | ||
1038 | API::ExecutorRuntime& exec = event.logEvent().choice().executorEvent().choice().executorRuntime(); | |
1039 | exec.reason() = finish | |
1040 | ? API::ExecutorRuntime_reason::initialization__of__module__finished | |
1041 | : API::ExecutorRuntime_reason::initializing__module; | |
1042 | exec.module__name() = module; | |
1043 | exec.testcase__name() = OMIT_VALUE; | |
1044 | exec.pid() = OMIT_VALUE; | |
1045 | exec.fd__setsize() = OMIT_VALUE; | |
1046 | log(event); | |
1047 | } | |
1048 | ||
1049 | void LoggerPluginManager::log_mtc_created(long pid) | |
1050 | { | |
1051 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_RUNTIME) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1052 | return; | |
1053 | API::TitanLogEvent event; | |
1054 | fill_common_fields(event, TTCN_Logger::EXECUTOR_RUNTIME); | |
1055 | ||
1056 | API::ExecutorRuntime& exec = event.logEvent().choice().executorEvent().choice().executorRuntime(); | |
1057 | exec.reason() = API::ExecutorRuntime_reason::mtc__created; | |
1058 | exec.module__name() = OMIT_VALUE; | |
1059 | exec.testcase__name() = OMIT_VALUE; | |
1060 | exec.pid() = pid; | |
1061 | exec.fd__setsize() = OMIT_VALUE; | |
1062 | log(event); | |
1063 | } | |
1064 | ||
1065 | void LoggerPluginManager::log_configdata(int reason, const char *str) | |
1066 | { | |
1067 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_CONFIGDATA) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1068 | return; | |
1069 | API::TitanLogEvent event; | |
1070 | fill_common_fields(event, TTCN_Logger::EXECUTOR_CONFIGDATA); | |
1071 | ||
1072 | API::ExecutorConfigdata& cfg = event.logEvent().choice().executorEvent().choice().executorConfigdata(); | |
1073 | cfg.reason() = reason; | |
1074 | if (str != NULL) cfg.param__() = str; | |
1075 | else cfg.param__() = OMIT_VALUE; | |
1076 | log(event); | |
1077 | } | |
1078 | ||
1079 | void LoggerPluginManager::log_executor_component(int reason) | |
1080 | { | |
1081 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_COMPONENT) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1082 | return; | |
1083 | API::TitanLogEvent event; | |
1084 | fill_common_fields(event, TTCN_Logger::EXECUTOR_COMPONENT); | |
1085 | ||
1086 | API::ExecutorComponent& ec = event.logEvent().choice().executorEvent().choice().executorComponent(); | |
1087 | ec.reason() = reason; | |
1088 | ec.compref() = OMIT_VALUE; | |
1089 | log(event); | |
1090 | } | |
1091 | ||
1092 | void LoggerPluginManager::log_executor_misc(int reason, const char *name, | |
1093 | const char *address, int port) | |
1094 | { | |
1095 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_UNQUALIFIED) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1096 | return; | |
1097 | API::TitanLogEvent event; | |
1098 | fill_common_fields(event, TTCN_Logger::EXECUTOR_UNQUALIFIED); | |
1099 | ||
1100 | API::ExecutorUnqualified& ex = event.logEvent().choice().executorEvent().choice().executorMisc(); | |
1101 | ex.reason() = reason; | |
1102 | ex.name() = name; | |
1103 | ex.addr() = address; | |
1104 | ex.port__() = port; | |
1105 | ||
1106 | log(event); | |
1107 | } | |
1108 | ||
1109 | void LoggerPluginManager::log_extcommand(TTCN_Logger::extcommand_t action, | |
1110 | const char *cmd) | |
1111 | { | |
1112 | if (!TTCN_Logger::log_this_event(TTCN_Logger::EXECUTOR_EXTCOMMAND) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1113 | return; | |
1114 | API::TitanLogEvent event; | |
1115 | fill_common_fields(event, TTCN_Logger::EXECUTOR_EXTCOMMAND); | |
1116 | ||
1117 | CHARSTRING& str = (action == TTCN_Logger::EXTCOMMAND_START) | |
1118 | ? event.logEvent().choice().executorEvent().choice().extcommandStart() | |
1119 | : event.logEvent().choice().executorEvent().choice().extcommandSuccess(); | |
1120 | ||
1121 | str = cmd; | |
1122 | log(event); | |
1123 | } | |
1124 | ||
1125 | void LoggerPluginManager::log_matching_done(API::MatchingDoneType_reason reason, | |
1126 | const char *type, int ptc, const char *return_type) | |
1127 | { | |
1128 | if (!TTCN_Logger::log_this_event(TTCN_Logger::MATCHING_DONE) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1129 | return; | |
1130 | API::TitanLogEvent event; | |
1131 | fill_common_fields(event, TTCN_Logger::MATCHING_DONE); | |
1132 | ||
1133 | API::MatchingDoneType& mp = event.logEvent().choice().matchingEvent().choice().matchingDone(); | |
1134 | mp.reason() = reason; | |
1135 | mp.type__() = type; | |
1136 | mp.ptc() = ptc; | |
1137 | mp.return__type() = return_type; | |
1138 | log(event); | |
1139 | } | |
1140 | ||
1141 | void LoggerPluginManager::log_matching_problem(int reason, int operation, | |
1142 | boolean check, boolean anyport, const char *port_name) | |
1143 | { | |
1144 | if (!TTCN_Logger::log_this_event(TTCN_Logger::MATCHING_PROBLEM) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1145 | return; | |
1146 | API::TitanLogEvent event; | |
1147 | fill_common_fields(event, TTCN_Logger::MATCHING_PROBLEM); | |
1148 | ||
1149 | API::MatchingProblemType& mp = event.logEvent().choice().matchingEvent().choice().matchingProblem(); | |
1150 | mp.reason() = reason; | |
1151 | mp.any__port() = anyport; | |
1152 | mp.check__() = check; | |
1153 | mp.operation() = operation; | |
1154 | mp.port__name()= port_name; | |
1155 | log(event); | |
1156 | } | |
1157 | ||
1158 | void LoggerPluginManager::log_matching_success(int port_type, const char *port_name, | |
1159 | int compref, const CHARSTRING& info) | |
1160 | { | |
1161 | TTCN_Logger::Severity sev; | |
1162 | if (compref == SYSTEM_COMPREF) { | |
1163 | sev = (port_type == API::PortType::message__) | |
1164 | ? TTCN_Logger::MATCHING_MMSUCCESS : TTCN_Logger::MATCHING_PMSUCCESS; | |
1165 | } | |
1166 | else { | |
1167 | sev = (port_type == API::PortType::message__) | |
1168 | ? TTCN_Logger::MATCHING_MCSUCCESS : TTCN_Logger::MATCHING_PCSUCCESS; | |
1169 | } | |
1170 | if (!TTCN_Logger::log_this_event(sev) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1171 | return; | |
1172 | API::TitanLogEvent event; | |
1173 | fill_common_fields(event, sev); | |
1174 | ||
1175 | API::MatchingSuccessType& ms = event.logEvent().choice().matchingEvent().choice().matchingSuccess(); | |
1176 | ms.port__type() = port_type; | |
1177 | ms.port__name() = port_name; | |
1178 | ms.info() = info; | |
1179 | log(event); | |
1180 | } | |
1181 | ||
1182 | void LoggerPluginManager::log_matching_failure(int port_type, const char *port_name, | |
1183 | int compref, int reason, const CHARSTRING& info) | |
1184 | { | |
1185 | TTCN_Logger::Severity sev; | |
1186 | if (compref == SYSTEM_COMPREF) { | |
1187 | sev = (port_type == API::PortType::message__) | |
1188 | ? TTCN_Logger::MATCHING_MMUNSUCC : TTCN_Logger::MATCHING_PMUNSUCC; | |
1189 | } | |
1190 | else { | |
1191 | sev = (port_type == API::PortType::message__) | |
1192 | ? TTCN_Logger::MATCHING_MCUNSUCC : TTCN_Logger::MATCHING_PCUNSUCC; | |
1193 | } | |
1194 | if (!TTCN_Logger::log_this_event(sev) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1195 | return; | |
1196 | API::TitanLogEvent event; | |
1197 | fill_common_fields(event, sev); | |
1198 | ||
1199 | API::MatchingFailureType& mf = event.logEvent().choice().matchingEvent().choice().matchingFailure(); | |
1200 | mf.port__type() = port_type; | |
1201 | mf.port__name() = port_name; | |
1202 | mf.reason() = reason; | |
1203 | ||
1204 | if (compref == SYSTEM_COMPREF) { | |
1205 | mf.choice().system__(); | |
1206 | } | |
1207 | else mf.choice().compref() = compref; | |
1208 | ||
1209 | mf.info() = info; | |
1210 | ||
1211 | log(event); | |
1212 | } | |
1213 | ||
1214 | void LoggerPluginManager::log_matching_timeout(const char *timer_name) | |
1215 | { | |
1216 | if (!TTCN_Logger::log_this_event(TTCN_Logger::MATCHING_PROBLEM) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1217 | return; | |
1218 | API::TitanLogEvent event; | |
1219 | fill_common_fields(event, TTCN_Logger::MATCHING_PROBLEM); | |
1220 | ||
1221 | API::MatchingTimeout& mt = event.logEvent().choice().matchingEvent().choice().matchingTimeout(); | |
1222 | if (timer_name) mt.timer__name() = timer_name; | |
1223 | else mt.timer__name() = OMIT_VALUE; | |
1224 | log(event); | |
1225 | } | |
1226 | ||
1227 | void LoggerPluginManager::log_random(int action, double v, unsigned long u) | |
1228 | { | |
1229 | if (!TTCN_Logger::log_this_event(TTCN_Logger::FUNCTION_RND) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1230 | return; | |
1231 | API::TitanLogEvent event; | |
1232 | fill_common_fields(event, TTCN_Logger::FUNCTION_RND); | |
1233 | ||
1234 | API::FunctionEvent_choice_random &r = event.logEvent().choice().functionEvent().choice().random(); | |
1235 | r.operation()= action; | |
1236 | r.retval() = v; | |
1237 | r.intseed() = u; | |
1238 | log(event); | |
1239 | } | |
1240 | ||
1241 | /** Pretend that the control part is executed by a separate component. | |
1242 | * | |
1243 | * In TITAN, the control part is executed on the MTC. | |
1244 | * This does not match the standard, which states: | |
1245 | * "The MTC shall be created by the system automatically at the start | |
1246 | * of each test case execution"; so the MTC is not supposed to exist | |
1247 | * in a control part. For the purpose of logging, we pretend that in the | |
1248 | * control part the current component is not the MTC but another "artificial" | |
1249 | * component "control", similar to "null", "system", or "all". | |
1250 | * | |
1251 | * @param compref | |
1252 | * @return the input value, but substitute CONTROLPART_COMPREF for MTC_COMPREF | |
1253 | * if inside a controlpart. | |
1254 | */ | |
1255 | inline int adjust_compref(int compref) | |
1256 | { | |
1257 | if (compref == MTC_COMPREF) { | |
1258 | switch (TTCN_Runtime::get_state()) { | |
1259 | case TTCN_Runtime::MTC_CONTROLPART: | |
1260 | case TTCN_Runtime::SINGLE_CONTROLPART: | |
1261 | compref = CONTROL_COMPREF; | |
1262 | break; | |
1263 | default: | |
1264 | break; | |
1265 | } | |
1266 | } | |
1267 | ||
1268 | return compref; | |
1269 | } | |
1270 | ||
1271 | void LoggerPluginManager::log_portconnmap(int operation, int src_compref, | |
1272 | const char *src_port, int dst_compref, const char *dst_port) | |
1273 | { | |
1274 | TTCN_Logger::Severity event_severity; | |
1275 | switch (operation) { | |
1276 | case API::ParPort_operation::connect__: | |
1277 | case API::ParPort_operation::disconnect__: | |
1278 | event_severity = TTCN_Logger::PARALLEL_PORTCONN; | |
1279 | break; | |
1280 | case API::ParPort_operation::map__: | |
1281 | case API::ParPort_operation::unmap__: | |
1282 | event_severity = TTCN_Logger::PARALLEL_PORTMAP; | |
1283 | break; | |
1284 | default: | |
1285 | TTCN_error("Invalid operation"); | |
1286 | } | |
1287 | ||
1288 | if (!TTCN_Logger::log_this_event(event_severity) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1289 | return; | |
1290 | API::TitanLogEvent event; | |
1291 | fill_common_fields(event, event_severity); | |
1292 | ||
1293 | API::ParPort & pp = event.logEvent().choice().parallelEvent().choice().parallelPort(); | |
1294 | pp.operation() = operation; | |
1295 | pp.srcCompref() = adjust_compref(src_compref); | |
1296 | pp.srcPort() = src_port; | |
1297 | pp.dstCompref() = adjust_compref(dst_compref); | |
1298 | pp.dstPort() = dst_port; | |
1299 | log(event); | |
1300 | } | |
1301 | ||
1302 | void LoggerPluginManager::log_par_ptc(int reason, | |
1303 | const char *module, const char *name, int compref, | |
1304 | const char *compname, const char *tc_loc, int alive_pid, int status) | |
1305 | { | |
1306 | TTCN_Logger::Severity sev = | |
1307 | (alive_pid && reason == API::ParallelPTC_reason::function__finished) | |
1308 | ? TTCN_Logger::PARALLEL_UNQUALIFIED : TTCN_Logger::PARALLEL_PTC; | |
1309 | if (!TTCN_Logger::log_this_event(sev) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1310 | return; | |
1311 | API::TitanLogEvent event; | |
1312 | fill_common_fields(event, sev); | |
1313 | ||
1314 | API::ParallelPTC& ptc = event.logEvent().choice().parallelEvent().choice().parallelPTC(); | |
1315 | ptc.reason() = reason; | |
1316 | ptc.module__() = module; | |
1317 | ptc.name() = name; | |
1318 | ptc.compref() = compref; | |
1319 | ptc.tc__loc() = tc_loc; | |
1320 | ptc.compname() = compname; | |
1321 | ptc.alive__pid() = alive_pid; | |
1322 | ptc.status() = status; | |
1323 | log(event); | |
1324 | } | |
1325 | ||
1326 | void LoggerPluginManager::log_port_queue(int operation, const char *port_name, | |
1327 | int compref, int id, const CHARSTRING& address, const CHARSTRING& param) | |
1328 | { | |
1329 | TTCN_Logger::Severity sev; | |
1330 | switch (operation) { | |
1331 | case API::Port__Queue_operation::enqueue__msg: | |
1332 | case API::Port__Queue_operation::extract__msg: | |
1333 | sev = TTCN_Logger::PORTEVENT_MQUEUE; | |
1334 | break; | |
1335 | case API::Port__Queue_operation::enqueue__call: | |
1336 | case API::Port__Queue_operation::enqueue__exception: | |
1337 | case API::Port__Queue_operation::enqueue__reply: | |
1338 | case API::Port__Queue_operation::extract__op: | |
1339 | sev = TTCN_Logger::PORTEVENT_PQUEUE; | |
1340 | break; | |
1341 | default: | |
1342 | TTCN_error("Invalid operation"); | |
1343 | } | |
1344 | ||
1345 | if (!TTCN_Logger::log_this_event(sev) && (TTCN_Logger::get_emergency_logging()<=0)) return; | |
1346 | API::TitanLogEvent event; | |
1347 | fill_common_fields(event, sev); | |
1348 | ||
1349 | API::Port__Queue& pq = event.logEvent().choice().portEvent().choice().portQueue(); | |
1350 | pq.operation() = operation; | |
1351 | pq.port__name() = port_name; | |
1352 | pq.compref() = adjust_compref(compref); | |
1353 | pq.msgid() = id; | |
1354 | pq.address__() = address; | |
1355 | pq.param__() = param; | |
1356 | log(event); | |
1357 | } | |
1358 | ||
1359 | void LoggerPluginManager::log_port_state(int operation, const char *port_name) | |
1360 | { | |
1361 | if (!TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_STATE)) return; | |
1362 | API::TitanLogEvent event; | |
1363 | fill_common_fields(event, TTCN_Logger::PORTEVENT_STATE); | |
1364 | ||
1365 | API::Port__State& ps = event.logEvent().choice().portEvent().choice().portState(); | |
1366 | ps.operation() = operation; | |
1367 | ps.port__name() = port_name; | |
1368 | log(event); | |
1369 | } | |
1370 | ||
1371 | void LoggerPluginManager::log_procport_send(const char *portname, int operation, | |
1372 | int compref, const CHARSTRING& system, const CHARSTRING& param) | |
1373 | { | |
1374 | TTCN_Logger::Severity event_severity = (compref == SYSTEM_COMPREF) | |
1375 | ? TTCN_Logger::PORTEVENT_PMOUT : TTCN_Logger::PORTEVENT_PCOUT; | |
1376 | if (!TTCN_Logger::log_this_event(event_severity) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1377 | return; | |
1378 | API::TitanLogEvent event; | |
1379 | fill_common_fields(event, event_severity); | |
1380 | ||
1381 | API::Proc__port__out& pt = event.logEvent().choice().portEvent().choice().procPortSend(); | |
1382 | pt.port__name() = portname; | |
1383 | pt.operation() = operation; | |
1384 | pt.compref() = compref; | |
1385 | if (compref == SYSTEM_COMPREF) { // it's mapped | |
1386 | pt.sys__name() = system; | |
1387 | } | |
1388 | pt.parameter() = param; | |
1389 | ||
1390 | log(event); | |
1391 | } | |
1392 | ||
1393 | void LoggerPluginManager::log_procport_recv(const char *portname, int operation, | |
1394 | int compref, boolean check, const CHARSTRING& param, int id) | |
1395 | { | |
1396 | TTCN_Logger::Severity event_severity = (compref == SYSTEM_COMPREF) | |
1397 | ? TTCN_Logger::PORTEVENT_PMIN : TTCN_Logger::PORTEVENT_PCIN; | |
1398 | if (!TTCN_Logger::log_this_event(event_severity) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1399 | return; | |
1400 | API::TitanLogEvent event; | |
1401 | fill_common_fields(event, event_severity); | |
1402 | ||
1403 | API::Proc__port__in& pt = event.logEvent().choice().portEvent().choice().procPortRecv(); | |
1404 | pt.port__name() = portname; | |
1405 | pt.operation() = operation; | |
1406 | pt.compref() = compref; | |
1407 | pt.check__() = check; | |
1408 | pt.parameter() = param; | |
1409 | pt.msgid() = id; | |
1410 | ||
1411 | log(event); | |
1412 | } | |
1413 | ||
1414 | void LoggerPluginManager::log_msgport_send(const char *portname, int compref, | |
1415 | const CHARSTRING& param) | |
1416 | { | |
1417 | TTCN_Logger::Severity event_severity = (compref == SYSTEM_COMPREF) | |
1418 | ? TTCN_Logger::PORTEVENT_MMSEND : TTCN_Logger::PORTEVENT_MCSEND; | |
1419 | if (!TTCN_Logger::log_this_event(event_severity) && (TTCN_Logger::get_emergency_logging()<=0)) return; | |
1420 | API::TitanLogEvent event; | |
1421 | fill_common_fields(event, event_severity); | |
1422 | ||
1423 | API::Msg__port__send& ms = event.logEvent().choice().portEvent().choice().msgPortSend(); | |
1424 | ms.port__name() = portname; | |
1425 | ms.compref() = compref; | |
1426 | ms.parameter() = param; | |
1427 | ||
1428 | log(event); | |
1429 | } | |
1430 | ||
1431 | void LoggerPluginManager::log_msgport_recv(const char *portname, int operation, | |
1432 | int compref, const CHARSTRING& system, const CHARSTRING& param, int id) | |
1433 | { | |
1434 | TTCN_Logger::Severity event_severity = (compref == SYSTEM_COMPREF) | |
1435 | ? TTCN_Logger::PORTEVENT_MMRECV : TTCN_Logger::PORTEVENT_MCRECV; | |
1436 | if (!TTCN_Logger::log_this_event(event_severity) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1437 | return; | |
1438 | API::TitanLogEvent event; | |
1439 | fill_common_fields(event, event_severity); | |
1440 | ||
1441 | API::Msg__port__recv& ms = event.logEvent().choice().portEvent().choice().msgPortRecv(); | |
1442 | ms.port__name() = portname; | |
1443 | ms.compref() = compref; | |
1444 | if (compref == SYSTEM_COMPREF) { // it's mapped | |
1445 | ms.sys__name() = system; | |
1446 | } | |
1447 | ms.operation() = operation; | |
1448 | ms.msgid() = id; | |
1449 | ms.parameter() = param; | |
1450 | ||
1451 | log(event); | |
1452 | } | |
1453 | ||
1454 | void LoggerPluginManager::log_dualport_map(boolean incoming, const char *target_type, | |
1455 | const CHARSTRING& value, int id) | |
1456 | { | |
1457 | TTCN_Logger::Severity event_severity = incoming | |
1458 | ? TTCN_Logger::PORTEVENT_DUALRECV : TTCN_Logger::PORTEVENT_DUALSEND; | |
1459 | if (!TTCN_Logger::log_this_event(event_severity) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1460 | return; | |
1461 | API::TitanLogEvent event; | |
1462 | fill_common_fields(event, event_severity); | |
1463 | ||
1464 | API::Dualface__mapped& dual = event.logEvent().choice().portEvent().choice().dualMapped(); | |
1465 | dual.incoming() = incoming; | |
1466 | dual.target__type() = target_type; | |
1467 | dual.value__() = value; | |
1468 | dual.msgid() = id; | |
1469 | ||
1470 | log(event); | |
1471 | } | |
1472 | ||
1473 | void LoggerPluginManager::log_dualport_discard(boolean incoming, const char *target_type, | |
1474 | const char *port_name, boolean unhandled) | |
1475 | { | |
1476 | TTCN_Logger::Severity event_severity = incoming | |
1477 | ? TTCN_Logger::PORTEVENT_DUALRECV : TTCN_Logger::PORTEVENT_DUALSEND; | |
1478 | if (!TTCN_Logger::log_this_event(event_severity) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1479 | return; | |
1480 | API::TitanLogEvent event; | |
1481 | fill_common_fields(event, event_severity); | |
1482 | ||
1483 | API::Dualface__discard& dualop = event.logEvent().choice().portEvent().choice().dualDiscard(); | |
1484 | dualop.incoming() = incoming; | |
1485 | dualop.target__type() = target_type; | |
1486 | dualop.port__name() = port_name; | |
1487 | dualop.unhandled() = unhandled; | |
1488 | ||
1489 | log(event); | |
1490 | } | |
1491 | ||
1492 | void LoggerPluginManager::log_port_misc(int reason, const char *port_name, | |
1493 | int remote_component, const char *remote_port, const char *ip_address, | |
1494 | int tcp_port, int new_size) | |
1495 | { | |
1496 | if (!TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_UNQUALIFIED) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1497 | return; | |
1498 | API::TitanLogEvent event; | |
1499 | fill_common_fields(event, TTCN_Logger::PORTEVENT_UNQUALIFIED); | |
1500 | ||
1501 | API::Port__Misc& portmisc = event.logEvent().choice().portEvent().choice().portMisc(); | |
1502 | portmisc.reason() = reason; | |
1503 | portmisc.port__name() = port_name; | |
1504 | portmisc.remote__component() = remote_component; | |
1505 | portmisc.remote__port() = remote_port; | |
1506 | portmisc.ip__address() = ip_address; | |
1507 | portmisc.tcp__port() = tcp_port; | |
1508 | portmisc.new__size() = new_size; | |
1509 | ||
1510 | log(event); | |
1511 | } | |
1512 | ||
1513 | ||
1514 | // End of externally callable functions | |
1515 | ||
1516 | /// Construct an event string, one by one. Event construction is not | |
1517 | /// supported for all event types. E.g. those event types with fixed format | |
1518 | /// like TIMEROP_* events have nothing to do with this at all. | |
1519 | void LoggerPluginManager::append_event_str(const char *str) | |
1520 | { | |
1521 | if (!this->current_event_) return; | |
1522 | ActiveEvent& curr = *this->current_event_; | |
1523 | const size_t str_len = strlen(str); | |
1524 | if (!str_len) return; // don't bother with empty string | |
1525 | ||
1526 | if (curr.event_str_ != NULL) { // event_str_ already allocated | |
1527 | if (!curr.fake_) { | |
1528 | // pieces_ may be NULL, in which case Realloc calls Malloc | |
1529 | curr.pieces_ = (size_t*)Realloc(curr.pieces_, sizeof(size_t) * curr.num_pieces_); | |
1530 | // Remember the current end | |
1531 | curr.pieces_[curr.num_pieces_++-1] = curr.event_str_len_; | |
1532 | } | |
1533 | // Don't bother remembering the pieces for a log2str event | |
1534 | ||
1535 | if ( curr.event_str_len_ + str_len > curr.event_str_size_) { | |
1536 | for (; curr.event_str_len_ + str_len > curr.event_str_size_; | |
1537 | curr.event_str_size_ *= 2) ; // double until it fits | |
1538 | curr.event_str_ = (char *)Realloc(curr.event_str_, curr.event_str_size_); | |
1539 | memset(curr.event_str_ + curr.event_str_len_, '\0', | |
1540 | curr.event_str_size_ - curr.event_str_len_); | |
1541 | } | |
1542 | memcpy(curr.event_str_ + curr.event_str_len_, str, str_len); | |
1543 | curr.event_str_len_ += str_len; | |
1544 | } else { // the first piece | |
1545 | curr.event_str_len_ = str_len; | |
1546 | curr.event_str_size_ = str_len * 2; // must be strictly bigger than str_len | |
1547 | curr.event_str_ = (char *)Malloc(curr.event_str_size_); | |
1548 | memcpy(curr.event_str_, str, str_len); | |
1549 | memset(curr.event_str_ + str_len, '\0', | |
1550 | curr.event_str_size_ - str_len); | |
1551 | curr.num_pieces_++; | |
1552 | // Do not allocate memory for the first piece; it ends at event_str_len_ | |
1553 | } | |
1554 | } | |
1555 | ||
1556 | char* LoggerPluginManager::get_current_event_str() | |
1557 | { | |
1558 | if (!this->current_event_) return 0; | |
1559 | size_t str_len = current_event_->event_str_len_ + 1; | |
1560 | char* result = (char*)Malloc(str_len); | |
1561 | memcpy(result, current_event_->event_str_, str_len - 1); | |
1562 | result[str_len - 1] = '\0'; | |
1563 | return result; | |
1564 | } | |
1565 | ||
1566 | void LoggerPluginManager::begin_event(TTCN_Logger::Severity msg_severity, | |
1567 | bool log2str) | |
1568 | { | |
1569 | event_destination_t event_dest; | |
1570 | if (log2str) event_dest = ED_STRING; | |
1571 | else event_dest = | |
1572 | TTCN_Logger::log_this_event(msg_severity) ? ED_FILE : ED_NONE; | |
1573 | // We are in the middle of another event, allocate a new entry for this | |
1574 | // event. The other active events are available through outer events. | |
1575 | // We're not (re)using the `outermost_event' buffer. | |
1576 | ActiveEvent *new_event = new ActiveEvent(log2str, event_dest); | |
1577 | if (!log2str) fill_common_fields(new_event->get_event(), msg_severity); | |
1578 | new_event->outer_event_ = this->current_event_; | |
1579 | this->current_event_ = new_event; | |
1580 | } | |
1581 | ||
1582 | void LoggerPluginManager::end_event() | |
1583 | { | |
1584 | if (this->current_event_ == NULL) { | |
1585 | // Invalid usage. | |
1586 | const char *message = "TTCN_Logger::end_event(): not in event."; | |
1587 | log_unhandled_event(TTCN_Logger::WARNING_UNQUALIFIED, message, strlen(message)); | |
1588 | return; | |
1589 | } | |
1590 | ||
1591 | ActiveEvent& curr = *this->current_event_; | |
1592 | switch (curr.event_destination_) { | |
1593 | case ED_NONE: | |
1594 | break; | |
1595 | case ED_FILE: | |
1596 | switch ((TTCN_Logger::Severity)(int)curr.get_event().severity()) { | |
1597 | case TTCN_Logger::DEBUG_ENCDEC: | |
1598 | case TTCN_Logger::DEBUG_TESTPORT: | |
1599 | case TTCN_Logger::DEBUG_UNQUALIFIED: | |
1600 | curr.get_event().logEvent().choice().debugLog().text() = | |
1601 | CHARSTRING(curr.event_str_len_, curr.event_str_); | |
1602 | curr.get_event().logEvent().choice().debugLog().category() = 0; // not yet used | |
1603 | break; | |
1604 | ||
1605 | case TTCN_Logger::ERROR_UNQUALIFIED: | |
1606 | curr.get_event().logEvent().choice().errorLog().text() = | |
1607 | CHARSTRING(curr.event_str_len_, curr.event_str_); | |
1608 | curr.get_event().logEvent().choice().errorLog().category() = 0; // not yet used | |
1609 | break; | |
1610 | ||
1611 | case TTCN_Logger::ACTION_UNQUALIFIED: | |
1612 | // fall through | |
1613 | case TTCN_Logger::USER_UNQUALIFIED: { | |
1614 | // Select the list for either userLog or action; treatment is the same. | |
1615 | API::Strings_str__list& slist = (curr.get_event().severity() == TTCN_Logger::USER_UNQUALIFIED) | |
1616 | ? curr.get_event().logEvent().choice().userLog().str__list() | |
1617 | : curr.get_event().logEvent().choice().actionEvent().str__list(); | |
1618 | if (curr.num_pieces_ > 0) { | |
1619 | // First piece. If num_pieces_==1, pieces_ is not allocated, use the full length. | |
1620 | size_t len0 = curr.num_pieces_ > 1 ? curr.pieces_[0] : curr.event_str_len_; | |
1621 | slist[0] = CHARSTRING(len0, curr.event_str_); | |
1622 | // Subsequent pieces from pieces_[i-1] to pieces_[i] (exclusive) | |
1623 | for (size_t i = 1; i < curr.num_pieces_ - 1; ++i) { | |
1624 | slist[i] = CHARSTRING( | |
1625 | curr.pieces_[i] - curr.pieces_[i - 1], | |
1626 | curr.event_str_ + curr.pieces_[i - 1]); | |
1627 | } | |
1628 | // Last piece (if it's not the same as the first) | |
1629 | if (curr.num_pieces_ > 1) { // i == num_pieces_-1 | |
1630 | slist[curr.num_pieces_ - 1]= CHARSTRING( | |
1631 | curr.event_str_len_ - curr.pieces_[curr.num_pieces_-2], | |
1632 | curr.event_str_ + curr.pieces_[curr.num_pieces_-2]); | |
1633 | } | |
1634 | } | |
1635 | else slist = NULL_VALUE; // make sure it's bound but empty | |
1636 | break; } | |
1637 | ||
1638 | case TTCN_Logger::WARNING_UNQUALIFIED: | |
1639 | curr.get_event().logEvent().choice().warningLog().text() = | |
1640 | CHARSTRING(curr.event_str_len_, curr.event_str_); | |
1641 | curr.get_event().logEvent().choice().warningLog().category() = 0; // not yet used | |
1642 | break; | |
1643 | ||
1644 | default: | |
1645 | curr.get_event().logEvent().choice().unhandledEvent() = | |
1646 | CHARSTRING(curr.event_str_len_, curr.event_str_); | |
1647 | break; | |
1648 | } // switch(severity) | |
1649 | log(curr.get_event()); | |
1650 | break; | |
1651 | case ED_STRING: | |
1652 | TTCN_Logger::fatal_error("TTCN_Logger::end_event(): event with string " | |
1653 | "destination was found, missing call of " | |
1654 | "TTCN_Logger::end_event_log2str()."); | |
1655 | default: | |
1656 | TTCN_Logger::fatal_error("TTCN_Logger::end_event(): invalid event " | |
1657 | "destination."); | |
1658 | } // switch(event_destination) | |
1659 | ||
1660 | // Remove the current (already logged) event from the list of pending | |
1661 | // events and select a higher level event on the stack. We're not | |
1662 | // following the old implementation regarding the `outermost_event' stuff. | |
1663 | ActiveEvent *outer_event = curr.outer_event_; | |
1664 | Free(curr.event_str_); | |
1665 | Free(curr.pieces_); | |
1666 | delete this->current_event_; | |
1667 | this->current_event_ = outer_event; | |
1668 | } | |
1669 | ||
1670 | CHARSTRING LoggerPluginManager::end_event_log2str() | |
1671 | { | |
1672 | if (this->current_event_ == NULL) { | |
1673 | // Invalid usage. | |
1674 | const char *message = "TTCN_Logger::end_event_log2str(): not in event."; | |
1675 | log_unhandled_event(TTCN_Logger::WARNING_UNQUALIFIED, message, strlen(message)); | |
1676 | return CHARSTRING(); // unbound! | |
1677 | } | |
1678 | ||
1679 | ActiveEvent& curr = *this->current_event_; | |
1680 | CHARSTRING ret_val(curr.event_str_len_, curr.event_str_); | |
1681 | ||
1682 | ActiveEvent *outer_event = curr.outer_event_; | |
1683 | Free(curr.event_str_); | |
1684 | Free(curr.pieces_); | |
1685 | delete this->current_event_; | |
1686 | // Otherwise, we don't save the current event to be `outermost_event', | |
1687 | // like the previous implementation. An initialized `outermost_event' is | |
1688 | // not the sign of an initialized logger. NULL or not, assign. | |
1689 | this->current_event_ = outer_event; | |
1690 | return ret_val; | |
1691 | } | |
1692 | ||
1693 | void LoggerPluginManager::finish_event() | |
1694 | { | |
1695 | // Drop events which have string destination in case of log2str() | |
1696 | // operations. There is no try-catch block to delete the event. Avoid | |
1697 | // data/log file corruption if there's an exception inside a log2str(), | |
1698 | // which is inside a log(). | |
1699 | while (this->current_event_ != NULL && | |
1700 | this->current_event_->event_destination_ == ED_STRING) | |
1701 | (void)end_event_log2str(); | |
1702 | ||
1703 | if (this->current_event_ != NULL) { | |
1704 | log_event_str("<unfinished>"); | |
1705 | end_event(); | |
1706 | } | |
1707 | } | |
1708 | ||
1709 | // Simply append the contents STR_PTR to the end of the current event. | |
1710 | // Everything is a string here. | |
1711 | void LoggerPluginManager::log_event_str(const char *str_ptr) | |
1712 | { | |
1713 | if (this->current_event_ != NULL) { | |
1714 | if (this->current_event_->event_destination_ == ED_NONE) return; | |
1715 | if (str_ptr == NULL) str_ptr = "<NULL pointer>"; | |
1716 | append_event_str(str_ptr); | |
1717 | } else { | |
1718 | // Invalid usage. | |
1719 | const char *message = "TTCN_Logger::log_event_str(): not in event."; | |
1720 | log_unhandled_event(TTCN_Logger::WARNING_UNQUALIFIED, message, strlen(message)); | |
1721 | } | |
1722 | } | |
1723 | ||
1724 | void LoggerPluginManager::log_char(char c) | |
1725 | { | |
1726 | if (this->current_event_ != NULL) { | |
1727 | if (this->current_event_->event_destination_ == ED_NONE || c == '\0') return; | |
1728 | const char c_str[2] = { c, 0 }; | |
1729 | append_event_str(c_str); | |
1730 | } else { | |
1731 | // Invalid usage. | |
1732 | const char *message = "TTCN_Logger::log_char(): not in event."; | |
1733 | log_unhandled_event(TTCN_Logger::WARNING_UNQUALIFIED, message, strlen(message)); | |
1734 | } | |
1735 | } | |
1736 | ||
1737 | void LoggerPluginManager::log_event_va_list(const char *fmt_str, | |
1738 | va_list p_var) | |
1739 | { | |
1740 | if (this->current_event_ != NULL) { | |
1741 | if (this->current_event_->event_destination_ == ED_NONE) return; | |
1742 | if (fmt_str == NULL) fmt_str = "<NULL format string>"; | |
1743 | char *message = mprintf_va_list(fmt_str, p_var); | |
1744 | append_event_str(message); | |
1745 | Free(message); | |
1746 | } else { | |
1747 | // Invalid usage. | |
1748 | const char *message = "TTCN_Logger::log_event(): not in event."; | |
1749 | log_unhandled_event(TTCN_Logger::WARNING_UNQUALIFIED, message, strlen(message)); | |
1750 | } | |
1751 | } | |
1752 | ||
1753 | void LoggerPluginManager::log_va_list(TTCN_Logger::Severity msg_severity, | |
1754 | const char *fmt_str, va_list p_var) | |
1755 | { | |
1756 | if (!TTCN_Logger::log_this_event(msg_severity) && (TTCN_Logger::get_emergency_logging()<=0)) | |
1757 | return; | |
1758 | if (fmt_str == NULL) fmt_str = "<NULL format string>"; | |
1759 | // Allocate a temporary buffer for this event. | |
1760 | char *message_buf = mprintf_va_list(fmt_str, p_var); | |
1761 | log_unhandled_event(msg_severity, message_buf, mstrlen(message_buf)); | |
1762 | Free(message_buf); | |
1763 | } | |
1764 | ||
1765 | ||
1766 | LoggerPlugin *LoggerPluginManager::find_plugin(const char *name) | |
1767 | { | |
1768 | assert(name != NULL); | |
1769 | for (size_t i = 0; i < this->n_plugins_; i++) { | |
1770 | const char *plugin_name = this->plugins_[i]->ref_->plugin_name(); | |
1771 | // TODO: If the name is not set in the plug-in, a warning should be | |
1772 | // reported instead. | |
1773 | if (plugin_name != NULL && !strcmp(name, plugin_name)) { | |
1774 | return this->plugins_[i]; | |
1775 | } | |
1776 | } | |
1777 | return NULL; | |
1778 | } | |
1779 | ||
1780 | #ifdef MEMORY_DEBUG | |
1781 | // new has been redefined in dbgnew.hh, undo it | |
1782 | #undef new | |
1783 | #endif | |
1784 | ||
1785 | inline void * operator new (size_t, void * p) throw() { return p ; } | |
1786 | ||
1787 | LoggerPluginManager::ActiveEvent::ActiveEvent(bool fake_event, event_destination_t dest) | |
1788 | : event_() | |
1789 | , event_str_(NULL) | |
1790 | , event_str_len_(0) | |
1791 | , event_str_size_(0) | |
1792 | , event_destination_(dest) | |
1793 | , outer_event_(NULL) | |
1794 | , num_pieces_(0) | |
1795 | , pieces_(NULL) | |
1796 | , fake_(fake_event) | |
1797 | { | |
1798 | if (!fake_event) { | |
1799 | new (event_) TitanLoggerApi::TitanLogEvent(); // placement new | |
1800 | } | |
1801 | } | |
1802 | ||
1803 | LoggerPluginManager::ActiveEvent::~ActiveEvent() | |
1804 | { | |
1805 | if (!fake_) { | |
1806 | get_event().~TitanLogEvent(); // explicit destructor call | |
1807 | } | |
1808 | } |