Commit | Line | Data |
---|---|---|
d44e3c4f | 1 | /****************************************************************************** |
2 | * Copyright (c) 2000-2016 Ericsson Telecom AB | |
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 | * Contributors: | |
9 | * Balasko, Jeno | |
10 | * Baranyi, Botond | |
11 | * Beres, Szabolcs | |
12 | * Delic, Adam | |
13 | * Feher, Csaba | |
14 | * Forstner, Matyas | |
15 | * Kovacs, Ferenc | |
16 | * Raduly, Csaba | |
17 | * Szabados, Kristof | |
18 | * Szabo, Janos Zoltan – initial implementation | |
19 | * Zalanyi, Balazs Andor | |
20 | * Pandi, Krisztian | |
21 | * | |
22 | ******************************************************************************/ | |
970ed795 EL |
23 | #include <stdio.h> |
24 | #include <string.h> | |
25 | #include <ctype.h> | |
26 | #include <stdarg.h> | |
27 | #include <stdlib.h> | |
28 | #include <errno.h> | |
29 | #include <unistd.h> | |
30 | #include <netdb.h> | |
31 | #include <time.h> | |
32 | #include <sys/time.h> | |
33 | #include <sys/types.h> | |
34 | ||
35 | #include "../common/memory.h" | |
36 | #include "Logger.hh" | |
37 | #include "Communication.hh" | |
38 | #include "Component.hh" | |
39 | #include "LoggingBits.hh" | |
40 | #include "LoggerPluginManager.hh" | |
41 | #include "Charstring.hh" | |
42 | #include "LoggingParam.hh" | |
43 | #include "TCov.hh" | |
44 | ||
45 | /** work-around for missing va_copy() in GCC */ | |
46 | #if defined(__GNUC__) && !defined(va_copy) | |
47 | # ifdef __va_copy | |
48 | # define va_copy(dest, src) __va_copy(dest, src) | |
49 | # else | |
50 | # define va_copy(dest, src) (dest) = (src) | |
51 | # endif | |
52 | #endif | |
53 | ||
54 | #define MIN_BUFFER_SIZE 1024 | |
55 | ||
56 | ||
57 | /** @brief Return a string identifying the component | |
58 | ||
59 | If \p comp.id_selector is COMPONENT_ID_NAME, returns \p comp.id_name | |
60 | ||
61 | If \p comp.id_selector is COMPONENT_ID_COMPREF, returns a pointer | |
62 | to a static buffer, containing a string representation of \p comp.id_compref | |
63 | ||
64 | If \p comp.id_selector is COMPONENT_ID_ALL, returns "All". | |
65 | ||
66 | If \p comp.id_selector is COMPONENT_ID_SYSTEM, returns "System". | |
67 | ||
68 | @param comp component identifier | |
69 | @return string | |
70 | */ | |
71 | expstring_t component_string(const component_id_t& comp); | |
72 | ||
73 | ||
74 | /** @name Private data structures | |
75 | @{ | |
76 | */ | |
77 | ||
78 | /** Log mask | |
79 | ||
80 | For TTCN_Logger internal use, no user serviceable parts. | |
81 | */ | |
82 | struct TTCN_Logger::log_mask_struct | |
83 | { | |
84 | component_id_t component_id; /**< Component */ | |
85 | Logging_Bits mask; /**< Settings for logging to console or file */ | |
86 | }; | |
87 | ||
88 | /** @} */ | |
89 | ||
90 | class LogEventType; | |
91 | ||
92 | /* Static members */ | |
93 | ||
94 | LoggerPluginManager *TTCN_Logger::plugins_ = NULL; | |
95 | ||
96 | /* No point in initializing here; will be done in initialize_logger() */ | |
97 | TTCN_Logger::log_mask_struct TTCN_Logger::console_log_mask; | |
98 | TTCN_Logger::log_mask_struct TTCN_Logger::file_log_mask; | |
99 | TTCN_Logger::log_mask_struct TTCN_Logger::emergency_log_mask; | |
100 | ||
101 | TTCN_Logger::emergency_logging_behaviour_t TTCN_Logger::emergency_logging_behaviour = BUFFER_MASKED; | |
102 | size_t TTCN_Logger::emergency_logging; | |
d44e3c4f | 103 | boolean TTCN_Logger::emergency_logging_for_fail_verdict = FALSE; |
970ed795 EL |
104 | |
105 | TTCN_Logger::matching_verbosity_t TTCN_Logger::matching_verbosity = VERBOSITY_COMPACT; | |
106 | ||
107 | /** Timestamp format in the log files. */ | |
108 | TTCN_Logger::timestamp_format_t TTCN_Logger::timestamp_format = TIMESTAMP_TIME; | |
109 | ||
110 | /** LogSourceInfo/SourceInfoFormat */ | |
111 | TTCN_Logger::source_info_format_t TTCN_Logger::source_info_format = SINFO_SINGLE; | |
112 | ||
113 | /** LogEventTypes */ | |
114 | TTCN_Logger::log_event_types_t TTCN_Logger::log_event_types = LOGEVENTTYPES_NO; | |
115 | ||
116 | // This array should contain all the _UNQUALIFIED severities. | |
117 | const TTCN_Logger::Severity TTCN_Logger::sev_categories[] = | |
118 | { | |
119 | TTCN_Logger::NOTHING_TO_LOG, // 0 | |
120 | TTCN_Logger::ACTION_UNQUALIFIED, // 1 | |
121 | TTCN_Logger::DEFAULTOP_UNQUALIFIED, // 5 | |
122 | TTCN_Logger::ERROR_UNQUALIFIED, // 6 | |
3f84031e | 123 | TTCN_Logger::EXECUTOR_UNQUALIFIED, // 12 |
124 | TTCN_Logger::FUNCTION_UNQUALIFIED, // 14 | |
125 | TTCN_Logger::PARALLEL_UNQUALIFIED, // 18 | |
126 | TTCN_Logger::TESTCASE_UNQUALIFIED, // 21 | |
127 | TTCN_Logger::PORTEVENT_UNQUALIFIED, // 35 | |
128 | TTCN_Logger::STATISTICS_UNQUALIFIED, // 37 | |
129 | TTCN_Logger::TIMEROP_UNQUALIFIED, // 43 | |
130 | TTCN_Logger::USER_UNQUALIFIED, // 44 | |
131 | TTCN_Logger::VERDICTOP_UNQUALIFIED, // 48 | |
132 | TTCN_Logger::WARNING_UNQUALIFIED, // 49 | |
133 | TTCN_Logger::MATCHING_UNQUALIFIED, // 61 | |
134 | TTCN_Logger::DEBUG_UNQUALIFIED, // 66 | |
970ed795 EL |
135 | }; |
136 | ||
137 | const char* TTCN_Logger::severity_category_names[] = | |
138 | { | |
139 | NULL, | |
140 | "ACTION", | |
141 | "DEFAULTOP", | |
142 | "ERROR", | |
143 | "EXECUTOR", | |
144 | "FUNCTION", | |
145 | "PARALLEL", | |
146 | "TESTCASE", | |
147 | "PORTEVENT", | |
148 | "STATISTICS", | |
149 | "TIMEROP", | |
150 | "USER", | |
151 | "VERDICTOP", | |
152 | "WARNING", | |
153 | "MATCHING", | |
154 | "DEBUG", | |
155 | }; | |
156 | ||
157 | ||
158 | /** Sub-category names for all Severity enum values, | |
159 | * used when TTCN_Logger::log_event_types is set to log sub-categories */ | |
160 | const char* TTCN_Logger::severity_subcategory_names[NUMBER_OF_LOGSEVERITIES] = { | |
161 | "", | |
162 | // ACTION: | |
163 | "UNQUALIFIED", | |
164 | // DEFAULTOP: | |
165 | "ACTIVATE", | |
166 | "DEACTIVATE", | |
167 | "EXIT", | |
168 | "UNQUALIFIED", | |
169 | // ERROR: | |
170 | "UNQUALIFIED", | |
171 | // EXECUTOR: | |
172 | "RUNTIME", | |
173 | "CONFIGDATA", | |
174 | "EXTCOMMAND", | |
175 | "COMPONENT", | |
176 | "LOGOPTIONS", | |
177 | "UNQUALIFIED", | |
178 | // FUNCTION: | |
179 | "RND", | |
180 | "UNQUALIFIED", | |
181 | // PARALLEL: | |
182 | "PTC", | |
183 | "PORTCONN", | |
184 | "PORTMAP", | |
185 | "UNQUALIFIED", | |
186 | // TESTCASE: | |
187 | "START", | |
188 | "FINISH", | |
189 | "UNQUALIFIED", | |
190 | // PORTEVENT: | |
191 | "PQUEUE", | |
192 | "MQUEUE", | |
193 | "STATE", | |
194 | "PMIN", | |
195 | "PMOUT", | |
196 | "PCIN", | |
197 | "PCOUT", | |
198 | "MMRECV", | |
199 | "MMSEND", | |
200 | "MCRECV", | |
201 | "MCSEND", | |
202 | "DUALRECV", | |
203 | "DUALSEND", | |
204 | "UNQUALIFIED", | |
205 | // STATISTICS: | |
206 | "VERDICT", | |
207 | "UNQUALIFIED", | |
208 | // TIMEROP: | |
209 | "READ", | |
210 | "START", | |
211 | "GUARD", | |
212 | "STOP", | |
213 | "TIMEOUT", | |
214 | "UNQUALIFIED", | |
215 | // USER: | |
216 | "UNQUALIFIED", | |
217 | // VERDICTOP: | |
218 | "GETVERDICT", | |
219 | "SETVERDICT", | |
220 | "FINAL", | |
221 | "UNQUALIFIED", | |
222 | // WARNING: | |
223 | "UNQUALIFIED", | |
224 | // MATCHING: | |
225 | "DONE", | |
226 | "TIMEOUT", | |
227 | "PCSUCCESS", | |
228 | "PCUNSUCC", | |
229 | "PMSUCCESS", | |
230 | "PMUNSUCC", | |
231 | "MCSUCCESS", | |
232 | "MCUNSUCC", | |
233 | "MMSUCCESS", | |
234 | "MMUNSUCC", | |
235 | "PROBLEM", | |
236 | "UNQUALIFIED", | |
237 | // DEBUG: | |
238 | "ENCDEC", | |
239 | "TESTPORT", | |
3f84031e | 240 | "USER", |
241 | "FRAMEWORK", | |
970ed795 EL |
242 | "UNQUALIFIED" |
243 | }; | |
244 | ||
245 | char* TTCN_Logger::logmatch_buffer = NULL; | |
246 | size_t TTCN_Logger::logmatch_buffer_len = 0; | |
247 | size_t TTCN_Logger::logmatch_buffer_size = 0; | |
248 | boolean TTCN_Logger::logmatch_printed = false; | |
249 | ||
250 | // TODO: Matching related stuff stays here for now. It just appends the | |
251 | // string to the end of the current (active) event. | |
252 | size_t TTCN_Logger::get_logmatch_buffer_len() | |
253 | { | |
254 | return logmatch_buffer_len; | |
255 | } | |
256 | ||
257 | void TTCN_Logger::set_logmatch_buffer_len(size_t new_len) | |
258 | { | |
259 | logmatch_buffer_len = new_len; | |
260 | logmatch_buffer_size = MIN_BUFFER_SIZE; | |
261 | while (logmatch_buffer_size < new_len) | |
262 | logmatch_buffer_size *= 2; | |
263 | logmatch_buffer = (char *)Realloc(logmatch_buffer, logmatch_buffer_size); | |
264 | logmatch_buffer[new_len] = '\0'; | |
265 | } | |
266 | ||
267 | void TTCN_Logger::print_logmatch_buffer() | |
268 | { | |
269 | if (logmatch_printed) TTCN_Logger::log_event_str(" , "); | |
270 | else logmatch_printed = true; | |
271 | if (logmatch_buffer_size > 0) | |
272 | TTCN_Logger::log_event_str(logmatch_buffer); | |
273 | } | |
274 | ||
275 | void TTCN_Logger::log_logmatch_info(const char *fmt_str, ...) | |
276 | { | |
277 | va_list p_var; | |
278 | va_start(p_var, fmt_str); | |
279 | ||
280 | if (fmt_str == NULL) fmt_str = "<NULL format string>"; | |
281 | for ( ; ; ) { | |
282 | size_t free_space = logmatch_buffer_size - logmatch_buffer_len; | |
283 | // Make a copy of p_var to allow multiple calls of vsnprintf(). | |
284 | va_list p_var2; | |
285 | va_copy(p_var2, p_var); | |
286 | int fragment_len = vsnprintf(logmatch_buffer + logmatch_buffer_len, | |
287 | free_space, fmt_str, p_var2); | |
288 | va_end(p_var2); | |
289 | if (fragment_len < 0) set_logmatch_buffer_len(logmatch_buffer_size * 2); | |
290 | else if ((size_t)fragment_len >= free_space) | |
291 | set_logmatch_buffer_len(logmatch_buffer_len + fragment_len + 1); | |
292 | else { | |
293 | logmatch_buffer_len += fragment_len; | |
294 | break; | |
295 | } | |
296 | } | |
297 | va_end(p_var); | |
298 | } | |
299 | ||
300 | /** The "beginning of time" for the logger (seconds and microseconds | |
301 | * since the Epoch) | |
302 | */ | |
303 | struct timeval TTCN_Logger::start_time; | |
304 | ||
305 | /** The base name of the current executable (no path, no extension) */ | |
306 | char *TTCN_Logger::executable_name = NULL; | |
307 | ||
308 | /// True to log type (controlpart/altstep/testcase/function/...) and name | |
309 | /// of the entity responsible for the log message, false to suppress it. | |
310 | boolean TTCN_Logger::log_entity_name = FALSE; | |
311 | ||
312 | /// The default log format is the legacy (original) format. | |
313 | TTCN_Logger::data_log_format_t TTCN_Logger::data_log_format = LF_LEGACY; | |
314 | ||
315 | #include <assert.h> | |
316 | ||
317 | /** @brief Equality operator for component_id_t | |
318 | ||
319 | @param left component identifier | |
320 | @param right component identifier | |
321 | @return true if \p left and \p right refer to the same component | |
322 | ||
323 | @note This functions tests the equality of the component identifiers, | |
324 | not the components themselves. It can't detect that component named "foo" is | |
325 | the same as component number 3. | |
326 | ||
327 | @li If the selectors differ, returns \c false. | |
328 | @li If both selectors are COMPONENT_ID_NAME, compares the names. | |
329 | @li If both selectors are COMPONENT_ID_COMPREF, compares the comp. references. | |
330 | @li If both selectors are COMPONENT_ID_ALL or COMPONENT_ID_SYSTEM, | |
331 | returns \c true. | |
332 | ||
333 | */ | |
334 | bool operator==(const component_id_t& left, const component_id_t& right) | |
335 | { | |
336 | if (left.id_selector != right.id_selector) | |
337 | return false; | |
338 | ||
339 | // The selectors are the same. | |
340 | switch (left.id_selector) { | |
341 | case COMPONENT_ID_NAME: | |
342 | return !strcmp(left.id_name, right.id_name); | |
343 | case COMPONENT_ID_COMPREF: | |
344 | return left.id_compref == right.id_compref; | |
345 | default: // Should be MTC or SYSTEM; identified by the selector. | |
346 | return true; | |
347 | } | |
348 | } | |
349 | ||
350 | char *TTCN_Logger::mputstr_severity(char *str, const TTCN_Logger::Severity& severity) | |
351 | { | |
352 | switch (severity) { | |
353 | case TTCN_Logger::ACTION_UNQUALIFIED: | |
354 | return mputstr(str, "ACTION"); | |
355 | case TTCN_Logger::DEFAULTOP_ACTIVATE: | |
356 | case TTCN_Logger::DEFAULTOP_DEACTIVATE: | |
357 | case TTCN_Logger::DEFAULTOP_EXIT: | |
358 | case TTCN_Logger::DEFAULTOP_UNQUALIFIED: | |
359 | return mputstr(str, "DEFAULTOP"); | |
360 | case TTCN_Logger::ERROR_UNQUALIFIED: | |
361 | return mputstr(str, "ERROR"); | |
362 | case TTCN_Logger::EXECUTOR_RUNTIME: | |
363 | case TTCN_Logger::EXECUTOR_CONFIGDATA: | |
364 | case TTCN_Logger::EXECUTOR_EXTCOMMAND: | |
365 | case TTCN_Logger::EXECUTOR_COMPONENT: | |
366 | case TTCN_Logger::EXECUTOR_LOGOPTIONS: | |
367 | case TTCN_Logger::EXECUTOR_UNQUALIFIED: | |
368 | return mputstr(str, "EXECUTOR"); | |
369 | case TTCN_Logger::FUNCTION_RND: | |
370 | case TTCN_Logger::FUNCTION_UNQUALIFIED: | |
371 | return mputstr(str, "FUNCTION"); | |
372 | case TTCN_Logger::PARALLEL_PTC: | |
373 | case TTCN_Logger::PARALLEL_PORTCONN: | |
374 | case TTCN_Logger::PARALLEL_PORTMAP: | |
375 | case TTCN_Logger::PARALLEL_UNQUALIFIED: | |
376 | return mputstr(str, "PARALLEL"); | |
377 | case TTCN_Logger::TESTCASE_START: | |
378 | case TTCN_Logger::TESTCASE_FINISH: | |
379 | case TTCN_Logger::TESTCASE_UNQUALIFIED: | |
380 | return mputstr(str, "TESTCASE"); | |
381 | case TTCN_Logger::PORTEVENT_PQUEUE: | |
382 | case TTCN_Logger::PORTEVENT_MQUEUE: | |
383 | case TTCN_Logger::PORTEVENT_STATE: | |
384 | case TTCN_Logger::PORTEVENT_PMIN: | |
385 | case TTCN_Logger::PORTEVENT_PMOUT: | |
386 | case TTCN_Logger::PORTEVENT_PCIN: | |
387 | case TTCN_Logger::PORTEVENT_PCOUT: | |
388 | case TTCN_Logger::PORTEVENT_MMRECV: | |
389 | case TTCN_Logger::PORTEVENT_MMSEND: | |
390 | case TTCN_Logger::PORTEVENT_MCRECV: | |
391 | case TTCN_Logger::PORTEVENT_MCSEND: | |
392 | case TTCN_Logger::PORTEVENT_DUALRECV: | |
393 | case TTCN_Logger::PORTEVENT_DUALSEND: | |
394 | case TTCN_Logger::PORTEVENT_UNQUALIFIED: | |
395 | return mputstr(str, "PORTEVENT"); | |
396 | case TTCN_Logger::STATISTICS_VERDICT: | |
397 | case TTCN_Logger::STATISTICS_UNQUALIFIED: | |
398 | return mputstr(str, "STATISTICS"); | |
399 | case TTCN_Logger::TIMEROP_READ: | |
400 | case TTCN_Logger::TIMEROP_START: | |
401 | case TTCN_Logger::TIMEROP_GUARD: | |
402 | case TTCN_Logger::TIMEROP_STOP: | |
403 | case TTCN_Logger::TIMEROP_TIMEOUT: | |
404 | case TTCN_Logger::TIMEROP_UNQUALIFIED: | |
405 | return mputstr(str, "TIMEROP"); | |
406 | case TTCN_Logger::USER_UNQUALIFIED: | |
407 | return mputstr(str, "USER"); | |
408 | break; | |
409 | case TTCN_Logger::VERDICTOP_GETVERDICT: | |
410 | case TTCN_Logger::VERDICTOP_SETVERDICT: | |
411 | case TTCN_Logger::VERDICTOP_FINAL: | |
412 | case TTCN_Logger::VERDICTOP_UNQUALIFIED: | |
413 | return mputstr(str, "VERDICTOP"); | |
414 | case TTCN_Logger::WARNING_UNQUALIFIED: | |
415 | return mputstr(str, "WARNING"); | |
416 | case TTCN_Logger::MATCHING_DONE: | |
417 | case TTCN_Logger::MATCHING_TIMEOUT: | |
418 | case TTCN_Logger::MATCHING_PCSUCCESS: | |
419 | case TTCN_Logger::MATCHING_PCUNSUCC: | |
420 | case TTCN_Logger::MATCHING_PMSUCCESS: | |
421 | case TTCN_Logger::MATCHING_PMUNSUCC: | |
422 | case TTCN_Logger::MATCHING_MCSUCCESS: | |
423 | case TTCN_Logger::MATCHING_MCUNSUCC: | |
424 | case TTCN_Logger::MATCHING_MMSUCCESS: | |
425 | case TTCN_Logger::MATCHING_MMUNSUCC: | |
426 | case TTCN_Logger::MATCHING_PROBLEM: | |
427 | case TTCN_Logger::MATCHING_UNQUALIFIED: | |
428 | return mputstr(str, "MATCHING"); | |
429 | case TTCN_Logger::DEBUG_ENCDEC: | |
430 | case TTCN_Logger::DEBUG_TESTPORT: | |
3f84031e | 431 | case TTCN_Logger::DEBUG_USER: |
432 | case TTCN_Logger::DEBUG_FRAMEWORK: | |
970ed795 EL |
433 | case TTCN_Logger::DEBUG_UNQUALIFIED: |
434 | return mputstr(str, "DEBUG"); | |
435 | default: | |
436 | return mputstr(str, "UNKNOWN"); | |
437 | } | |
438 | } | |
439 | ||
440 | char *TTCN_Logger::mputstr_timestamp(char *str, | |
441 | timestamp_format_t p_timestamp_format, | |
442 | const struct timeval *tv) | |
443 | { | |
444 | if (p_timestamp_format == TIMESTAMP_SECONDS) { | |
445 | struct timeval diff; | |
446 | if (tv->tv_usec < start_time.tv_usec) { | |
447 | diff.tv_sec = tv->tv_sec - start_time.tv_sec - 1; | |
448 | diff.tv_usec = tv->tv_usec + (1000000L - start_time.tv_usec); | |
449 | } else { | |
450 | diff.tv_sec = tv->tv_sec - start_time.tv_sec; | |
451 | diff.tv_usec = tv->tv_usec - start_time.tv_usec; | |
452 | } | |
453 | str = mputprintf(str, "%ld.%06ld", (long)diff.tv_sec, diff.tv_usec); | |
454 | } else { | |
455 | time_t tv_sec = tv->tv_sec; | |
456 | struct tm *lt = localtime(&tv_sec); | |
457 | if (lt == NULL) fatal_error("localtime() call failed."); | |
458 | if (p_timestamp_format == TIMESTAMP_TIME) { | |
459 | str = mputprintf(str, "%02d:%02d:%02d.%06ld", | |
460 | lt->tm_hour, lt->tm_min, lt->tm_sec, tv->tv_usec); | |
461 | } else { | |
462 | static const char * const month_names[] = { "Jan", "Feb", "Mar", | |
463 | "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; | |
464 | str = mputprintf(str, "%4d/%s/%02d %02d:%02d:%02d.%06ld", | |
465 | lt->tm_year + 1900, month_names[lt->tm_mon], | |
466 | lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, | |
467 | tv->tv_usec); | |
468 | } | |
469 | } | |
470 | return str; | |
471 | } | |
472 | ||
473 | CHARSTRING TTCN_Logger::get_timestamp_str(timestamp_format_t p_timestamp_format) | |
474 | { | |
475 | struct timeval tv; | |
476 | if (gettimeofday(&tv, NULL) == -1) | |
477 | fatal_error("gettimeofday() system call failed."); | |
478 | char *str = mputstr_timestamp(NULL, p_timestamp_format, &tv); | |
479 | CHARSTRING ret_val(mstrlen(str), str); | |
480 | Free(str); | |
481 | return ret_val; | |
482 | } | |
483 | ||
484 | CHARSTRING TTCN_Logger::get_source_info_str(source_info_format_t | |
485 | p_source_info_format) | |
486 | { | |
487 | if (p_source_info_format == SINFO_NONE) return CHARSTRING(); | |
488 | char *source_info = TTCN_Location::print_location( | |
489 | p_source_info_format == SINFO_STACK, TRUE, log_entity_name); | |
490 | if (source_info == NULL) return CHARSTRING('-'); | |
491 | CHARSTRING ret_val(mstrlen(source_info),source_info); | |
492 | Free(source_info); | |
493 | return ret_val; | |
494 | } | |
495 | ||
496 | /** @brief Logs a fatal error and terminates the application. | |
497 | This function doesn't return: it calls \c exit(EXIT_FAILURE); | |
498 | @param err_msg printf-style format string | |
499 | */ | |
500 | void TTCN_Logger::fatal_error(const char *err_msg, ...) | |
501 | { | |
502 | fputs("Fatal error during logging: ", stderr); | |
503 | va_list p_var; | |
504 | va_start(p_var, err_msg); | |
505 | vfprintf(stderr, err_msg, p_var); | |
506 | va_end(p_var); | |
507 | OS_error(); | |
508 | fputs(" Exiting.\n", stderr); | |
509 | exit(EXIT_FAILURE); | |
510 | } | |
511 | ||
512 | void TTCN_Logger::initialize_logger() | |
513 | { | |
514 | console_log_mask.component_id.id_selector = COMPONENT_ID_ALL; | |
515 | console_log_mask.component_id.id_compref = ALL_COMPREF; | |
516 | // setting id_compref is optional when id_selector==COMPONENT_ID_ALL | |
517 | console_log_mask.mask = Logging_Bits::default_console_mask; | |
518 | ||
519 | file_log_mask.component_id.id_selector = COMPONENT_ID_ALL; | |
520 | file_log_mask.component_id.id_compref = ALL_COMPREF; | |
521 | // setting id_compref is optional when id_selector==COMPONENT_ID_ALL | |
522 | file_log_mask.mask = Logging_Bits::log_all; | |
523 | ||
524 | emergency_log_mask.component_id.id_selector = COMPONENT_ID_ALL; | |
525 | emergency_log_mask.component_id.id_compref = ALL_COMPREF; | |
526 | // setting id_compref is optional when id_selector==COMPONENT_ID_ALL | |
527 | emergency_log_mask.mask = Logging_Bits::log_all; | |
528 | ||
529 | logmatch_buffer = (char*)Malloc(MIN_BUFFER_SIZE); | |
530 | logmatch_buffer[0] = '\0'; | |
531 | logmatch_buffer_len = 0; | |
532 | logmatch_buffer_size = MIN_BUFFER_SIZE; | |
533 | } | |
534 | ||
535 | void TTCN_Logger::terminate_logger() | |
536 | { | |
537 | // Get rid of plug-ins at first. | |
538 | if (plugins_) { | |
539 | plugins_->unload_plugins(); | |
540 | delete plugins_; | |
541 | plugins_ = NULL; | |
542 | } | |
543 | ||
544 | Free(executable_name); | |
545 | executable_name = NULL; | |
546 | ||
547 | // Clean up the log masks. *_log_masks (which points to the start of | |
548 | // actual_*_log_mask) is borrowed as the "next" pointer. | |
549 | if (COMPONENT_ID_NAME == console_log_mask.component_id.id_selector) { | |
550 | Free(console_log_mask.component_id.id_name); | |
551 | } | |
552 | ||
553 | if (COMPONENT_ID_NAME == file_log_mask.component_id.id_selector) { | |
554 | Free(file_log_mask.component_id.id_name); | |
555 | } | |
556 | ||
557 | if (COMPONENT_ID_NAME == emergency_log_mask.component_id.id_selector) { | |
558 | Free(emergency_log_mask.component_id.id_name); | |
559 | } | |
560 | ||
561 | Free(logmatch_buffer); | |
562 | logmatch_buffer = NULL; | |
563 | } | |
564 | ||
565 | bool TTCN_Logger::is_logger_up() | |
566 | { | |
567 | if (logmatch_buffer == NULL) return FALSE; | |
568 | return get_logger_plugin_manager()->plugins_ready(); | |
569 | } | |
570 | ||
571 | void TTCN_Logger::reset_configuration() | |
572 | { | |
573 | file_log_mask .mask = Logging_Bits::log_all; | |
574 | console_log_mask.mask = Logging_Bits::default_console_mask; | |
575 | emergency_log_mask.mask = Logging_Bits::log_all; | |
576 | ||
577 | timestamp_format = TIMESTAMP_TIME; | |
578 | source_info_format = SINFO_NONE; | |
579 | log_event_types = LOGEVENTTYPES_NO; | |
580 | log_entity_name = FALSE; | |
581 | ||
582 | get_logger_plugin_manager()->reset(); | |
583 | } | |
584 | ||
585 | void TTCN_Logger::set_executable_name(const char *argv_0) | |
586 | { | |
587 | Free(executable_name); | |
588 | size_t name_end = strlen(argv_0); | |
589 | // Cut the '.exe' suffix from the end (if present). | |
590 | if (name_end >= 4 && !strncasecmp(argv_0 + name_end - 4, ".exe", 4)) | |
591 | name_end -= 4; | |
592 | size_t name_begin = 0; | |
593 | // Find the last '/' (if present) to cut the leading directory part. | |
594 | for (int i = name_end - 1; i >= 0; i--) { | |
595 | if (argv_0[i] == '/') { | |
596 | name_begin = i + 1; | |
597 | break; | |
598 | } | |
599 | } | |
600 | int name_len = name_end - name_begin; | |
601 | if (name_len > 0) { | |
602 | executable_name = (char*)Malloc(name_len + 1); | |
603 | memcpy(executable_name, argv_0 + name_begin, name_len); | |
604 | executable_name[name_len] = '\0'; | |
605 | } else executable_name = NULL; | |
606 | } | |
607 | ||
608 | bool TTCN_Logger::add_parameter(const logging_setting_t& logging_param) | |
609 | { | |
610 | return get_logger_plugin_manager()->add_parameter(logging_param); | |
611 | } | |
612 | ||
613 | void TTCN_Logger::set_plugin_parameters(component component_reference, | |
614 | const char *component_name) | |
615 | { | |
616 | get_logger_plugin_manager()->set_parameters(component_reference, | |
617 | component_name); | |
618 | } | |
619 | ||
620 | void TTCN_Logger::load_plugins(component component_reference, | |
621 | const char *component_name) | |
622 | { | |
623 | get_logger_plugin_manager()->load_plugins(component_reference, | |
624 | component_name); | |
625 | } | |
626 | ||
627 | void TTCN_Logger::set_file_name(const char *new_filename_skeleton, | |
628 | boolean from_config) | |
629 | { | |
630 | // Pass the file's name to all plug-ins loaded. Not all of them is | |
631 | // interested in this. | |
632 | get_logger_plugin_manager()-> | |
633 | set_file_name(new_filename_skeleton, from_config); | |
634 | } | |
635 | ||
636 | bool TTCN_Logger::set_file_size(component_id_t const& comp, int p_size) | |
637 | { | |
638 | return get_logger_plugin_manager()->set_file_size(comp, p_size); | |
639 | } | |
640 | ||
641 | bool TTCN_Logger::set_file_number(component_id_t const& comp, int p_number) | |
642 | { | |
643 | return get_logger_plugin_manager()->set_file_number(comp, p_number); | |
644 | } | |
645 | ||
646 | bool TTCN_Logger::set_disk_full_action(component_id_t const& comp, | |
647 | disk_full_action_t p_disk_full_action) | |
648 | { | |
649 | return get_logger_plugin_manager() | |
650 | ->set_disk_full_action(comp, p_disk_full_action); | |
651 | } | |
652 | ||
653 | void TTCN_Logger::set_start_time() | |
654 | { | |
655 | if (gettimeofday(&start_time, NULL) == -1) { | |
656 | fatal_error("gettimeofday() system call failed."); | |
657 | } | |
658 | } | |
659 | ||
660 | LoggerPluginManager *TTCN_Logger::get_logger_plugin_manager() | |
661 | { | |
662 | if (!plugins_) plugins_ = new LoggerPluginManager(); | |
663 | return plugins_; | |
664 | } | |
665 | ||
666 | ||
667 | // These masks can control not only file and console! They're general purpose | |
668 | // event filters, hence their name is not changed. Stay here. | |
669 | void TTCN_Logger::set_file_mask(component_id_t const& cmpt, const Logging_Bits& new_file_mask) | |
670 | { | |
671 | // If FileMask was set with a component-specific value, do not allow | |
672 | // overwriting with a generic value. | |
673 | if (file_log_mask.component_id.id_selector == COMPONENT_ID_COMPREF | |
674 | && cmpt.id_selector == COMPONENT_ID_ALL) return; | |
675 | file_log_mask.mask = new_file_mask; | |
676 | if (cmpt.id_selector == COMPONENT_ID_NAME) { // deep copy needed | |
677 | if (file_log_mask.component_id.id_selector == COMPONENT_ID_NAME) | |
678 | Free(file_log_mask.component_id.id_name); | |
679 | file_log_mask.component_id.id_selector = COMPONENT_ID_NAME; | |
680 | file_log_mask.component_id.id_name = mcopystr(cmpt.id_name); | |
681 | } else file_log_mask.component_id = cmpt; | |
682 | } | |
683 | ||
684 | void TTCN_Logger::set_console_mask(component_id_t const& cmpt, const Logging_Bits& new_console_mask) | |
685 | { | |
686 | // If ConsoleMask was set with a component-specific value, do not allow | |
687 | // overwriting with a generic value. | |
688 | if (console_log_mask.component_id.id_selector == COMPONENT_ID_COMPREF | |
689 | && cmpt.id_selector == COMPONENT_ID_ALL) return; | |
690 | console_log_mask.mask = new_console_mask; | |
691 | if (cmpt.id_selector == COMPONENT_ID_NAME) { // deep copy needed | |
692 | if (console_log_mask.component_id.id_selector == COMPONENT_ID_NAME) | |
693 | Free(console_log_mask.component_id.id_name); | |
694 | console_log_mask.component_id.id_selector = COMPONENT_ID_NAME; | |
695 | console_log_mask.component_id.id_name = mcopystr(cmpt.id_name); | |
696 | } else console_log_mask.component_id = cmpt; | |
697 | } | |
698 | ||
699 | void TTCN_Logger::set_emergency_logging_mask(component_id_t const& cmpt, const Logging_Bits& new_logging_mask) | |
700 | { | |
701 | // If Emergency Logging Mask was set with a component-specific value, do not allow | |
702 | // overwriting with a generic value. | |
703 | if (emergency_log_mask.component_id.id_selector == COMPONENT_ID_COMPREF | |
704 | && cmpt.id_selector == COMPONENT_ID_ALL) return; | |
705 | emergency_log_mask.mask = new_logging_mask; | |
706 | if (cmpt.id_selector == COMPONENT_ID_NAME) { // deep copy needed | |
707 | if (emergency_log_mask.component_id.id_selector == COMPONENT_ID_NAME) | |
708 | Free(emergency_log_mask.component_id.id_name); | |
709 | emergency_log_mask.component_id.id_selector = COMPONENT_ID_NAME; | |
710 | emergency_log_mask.component_id.id_name = mcopystr(cmpt.id_name); | |
711 | } else emergency_log_mask.component_id = cmpt; | |
712 | } | |
713 | ||
714 | void TTCN_Logger::set_emergency_logging_behaviour(emergency_logging_behaviour_t behaviour) | |
715 | { | |
716 | emergency_logging_behaviour= behaviour; | |
717 | } | |
718 | ||
719 | TTCN_Logger::emergency_logging_behaviour_t TTCN_Logger::get_emergency_logging_behaviour() | |
720 | { | |
721 | return emergency_logging_behaviour; | |
722 | } | |
723 | ||
724 | size_t TTCN_Logger::get_emergency_logging() | |
725 | { | |
726 | return emergency_logging; | |
727 | } | |
728 | ||
729 | void TTCN_Logger::set_emergency_logging(size_t size) | |
730 | { | |
731 | emergency_logging = size; | |
732 | } | |
733 | ||
d44e3c4f | 734 | boolean TTCN_Logger::get_emergency_logging_for_fail_verdict() |
735 | { | |
736 | return emergency_logging_for_fail_verdict; | |
737 | } | |
738 | ||
739 | void TTCN_Logger::set_emergency_logging_for_fail_verdict(boolean b) | |
740 | { | |
741 | emergency_logging_for_fail_verdict = b; | |
742 | } | |
743 | ||
970ed795 EL |
744 | Logging_Bits const& TTCN_Logger::get_file_mask() |
745 | { | |
746 | return file_log_mask.mask; | |
747 | } | |
748 | ||
749 | Logging_Bits const& TTCN_Logger::get_console_mask() | |
750 | { | |
751 | return console_log_mask.mask; | |
752 | } | |
753 | ||
754 | Logging_Bits const& TTCN_Logger::get_emergency_logging_mask() | |
755 | { | |
756 | return emergency_log_mask.mask; | |
757 | } | |
758 | ||
759 | void TTCN_Logger::register_plugin(const component_id_t comp, char *identifier, char *filename) | |
760 | { | |
761 | get_logger_plugin_manager()->register_plugin(comp, identifier, filename); | |
762 | } | |
763 | ||
764 | char *TTCN_Logger::get_logger_settings_str() | |
765 | { | |
766 | static const char *timestamp_format_names[] = { | |
767 | "Time", "DateTime", "Seconds" | |
768 | }; | |
769 | static const char *logeventtype_names[] = { | |
770 | "No", "Yes", "Subcategories" | |
771 | }; | |
772 | static const char *source_info_format_names[] = { | |
773 | "None", "Single", "Stack" | |
774 | }; | |
775 | ||
776 | expstring_t filemask_origin = | |
777 | component_string(file_log_mask.component_id); | |
778 | expstring_t consolemask_origin = | |
779 | component_string(console_log_mask.component_id); | |
780 | expstring_t filemask_description = file_log_mask.mask.describe(); | |
781 | expstring_t consolemask_description = console_log_mask.mask.describe(); | |
782 | ||
783 | // Global options, common stuff for all plug-ins. | |
784 | expstring_t new_log_message = mprintf("TTCN Logger v%d.%d options: " | |
785 | "TimeStampFormat:=%s; LogEntityName:=%s; LogEventTypes:=%s; " | |
786 | "SourceInfoFormat:=%s; %s.FileMask:=%s; %s.ConsoleMask:=%s;", | |
787 | TTCN_Logger::major_version, TTCN_Logger::minor_version, | |
788 | timestamp_format_names[timestamp_format], | |
789 | logeventtype_names[log_entity_name], | |
790 | logeventtype_names[log_event_types], | |
791 | source_info_format_names[source_info_format], filemask_origin, | |
792 | filemask_description, consolemask_origin, consolemask_description); | |
793 | ||
794 | Free(filemask_origin); | |
795 | Free(consolemask_origin); | |
796 | Free(filemask_description); | |
797 | Free(consolemask_description); | |
798 | ||
799 | return new_log_message; | |
800 | } | |
801 | ||
802 | void TTCN_Logger::write_logger_settings(bool /*opening*/) | |
803 | { | |
804 | expstring_t new_log_message = get_logger_settings_str(); | |
805 | ||
806 | // If we get called too early (and become buffered), the logger options | |
807 | // must be updated. By default the initial values are used. | |
808 | get_logger_plugin_manager()->log_log_options(new_log_message, | |
809 | mstrlen(new_log_message)); | |
810 | ||
811 | Free(new_log_message); | |
812 | } | |
813 | ||
814 | boolean TTCN_Logger::should_log_to_file(TTCN_Logger::Severity sev) | |
815 | { | |
816 | if (sev > 0 && sev < TTCN_Logger::NUMBER_OF_LOGSEVERITIES) { | |
817 | return file_log_mask.mask.bits[sev]; | |
818 | } | |
819 | return false; | |
820 | } | |
821 | ||
822 | boolean TTCN_Logger::should_log_to_console(TTCN_Logger::Severity sev) | |
823 | { | |
824 | // CR_TR00015406: Always log external scripts to the console | MCTR. | |
825 | if (sev == TTCN_Logger::EXECUTOR_EXTCOMMAND) return true; | |
826 | if (sev > 0 && sev < TTCN_Logger::NUMBER_OF_LOGSEVERITIES) { | |
827 | return console_log_mask.mask.bits[sev]; | |
828 | } | |
829 | return false; | |
830 | } | |
831 | ||
832 | boolean TTCN_Logger::should_log_to_emergency(TTCN_Logger::Severity sev) | |
833 | { | |
834 | if (sev > 0 && sev < TTCN_Logger::NUMBER_OF_LOGSEVERITIES) { | |
835 | return emergency_log_mask.mask.bits[sev]; | |
836 | } | |
837 | return false; | |
838 | } | |
839 | ||
840 | void TTCN_Logger::set_timestamp_format(timestamp_format_t new_timestamp_format) | |
841 | { | |
842 | timestamp_format = new_timestamp_format; | |
843 | } | |
844 | ||
845 | void TTCN_Logger::set_source_info_format(source_info_format_t new_source_info_format) | |
846 | { | |
847 | source_info_format = new_source_info_format; | |
848 | } | |
849 | ||
850 | void TTCN_Logger::set_log_event_types(log_event_types_t new_log_event_types) | |
851 | { | |
852 | log_event_types = new_log_event_types; | |
853 | } | |
854 | ||
855 | void TTCN_Logger::set_append_file(boolean new_append_file) | |
856 | { | |
857 | get_logger_plugin_manager()->set_append_file(new_append_file); | |
858 | } | |
859 | ||
860 | void TTCN_Logger::set_log_entity_name(boolean new_log_entity_name) | |
861 | { | |
862 | log_entity_name = new_log_entity_name; | |
863 | } | |
864 | ||
865 | void TTCN_Logger::open_file() | |
866 | { | |
867 | get_logger_plugin_manager()->open_file(); | |
868 | } | |
869 | ||
870 | void TTCN_Logger::close_file() | |
871 | { | |
872 | get_logger_plugin_manager()->close_file(); | |
873 | } | |
874 | ||
875 | void TTCN_Logger::ring_buffer_dump(bool do_close_file) | |
876 | { | |
877 | get_logger_plugin_manager()->ring_buffer_dump(do_close_file); | |
878 | } | |
879 | ||
880 | unsigned int TTCN_Logger::get_mask() | |
881 | { | |
882 | TTCN_warning("TTCN_Logger::get_mask() is deprecated, please use " | |
883 | "TTCN_Logger::should_log_to_file() or " | |
884 | "TTCN_Logger::should_log_to_console() instead."); | |
885 | return LOG_ALL_IMPORTANT | MATCHING_UNQUALIFIED | DEBUG_UNQUALIFIED; | |
886 | } | |
887 | ||
888 | TTCN_Logger::matching_verbosity_t TTCN_Logger::get_matching_verbosity() | |
889 | { | |
890 | return matching_verbosity; | |
891 | } | |
892 | ||
893 | void TTCN_Logger::set_matching_verbosity(TTCN_Logger::matching_verbosity_t v) | |
894 | { | |
895 | matching_verbosity = v; | |
896 | } | |
897 | ||
898 | // Called from the generated code and many more places... Stay here. The | |
899 | // existence of the file descriptors etc. is the responsibility of the | |
900 | // plug-ins. | |
901 | boolean TTCN_Logger::log_this_event(TTCN_Logger::Severity event_severity) | |
902 | { | |
903 | //ToDO: emergency logging = true | |
904 | if (should_log_to_file(event_severity)) return TRUE; | |
905 | else if (should_log_to_console(event_severity)) return TRUE; | |
906 | else if (should_log_to_emergency(event_severity) && (get_emergency_logging() > 0)) return TRUE; | |
907 | else return FALSE; | |
908 | } | |
909 | ||
910 | void TTCN_Logger::log(TTCN_Logger::Severity msg_severity, | |
911 | const char *fmt_str, ...) | |
912 | { | |
913 | va_list p_var; | |
914 | va_start(p_var, fmt_str); | |
915 | log_va_list(msg_severity, fmt_str, p_var); | |
916 | va_end(p_var); | |
917 | } | |
918 | ||
919 | void TTCN_Logger::send_event_as_error() | |
920 | { | |
921 | char* error_msg = get_logger_plugin_manager()->get_current_event_str(); | |
922 | if (!error_msg) | |
923 | return; | |
924 | ||
925 | if (TTCN_Communication::is_mc_connected()) { | |
926 | TTCN_Communication::send_error("%s", error_msg); | |
927 | } else { | |
928 | fprintf(stderr, "%s\n", error_msg); | |
929 | } | |
930 | Free(error_msg); | |
931 | } | |
932 | ||
933 | // Part of the external interface. Don't touch. | |
934 | void TTCN_Logger::log_str(TTCN_Logger::Severity msg_severity, | |
935 | const char *str_ptr) | |
936 | { | |
937 | if (!log_this_event(msg_severity)) return; | |
938 | if (str_ptr == NULL) | |
939 | str_ptr = "<NULL pointer>"; | |
940 | get_logger_plugin_manager()->log_unhandled_event(msg_severity, | |
941 | str_ptr, strlen(str_ptr)); | |
942 | logmatch_printed = false; | |
943 | } | |
944 | ||
945 | void TTCN_Logger::log_va_list(TTCN_Logger::Severity msg_severity, | |
946 | const char *fmt_str, va_list p_var) | |
947 | { | |
948 | get_logger_plugin_manager()->log_va_list(msg_severity, fmt_str, p_var); | |
949 | logmatch_printed = false; | |
950 | } | |
951 | ||
952 | void TTCN_Logger::begin_event(TTCN_Logger::Severity msg_severity, boolean log2str) | |
953 | { | |
954 | get_logger_plugin_manager()->begin_event(msg_severity, log2str); | |
955 | } | |
956 | ||
957 | void TTCN_Logger::end_event() | |
958 | { | |
959 | get_logger_plugin_manager()->end_event(); | |
960 | // TODO: Find another place for these... | |
961 | logmatch_printed = false; | |
962 | } | |
963 | ||
964 | CHARSTRING TTCN_Logger::end_event_log2str() | |
965 | { | |
966 | CHARSTRING ret_val = get_logger_plugin_manager()->end_event_log2str(); | |
967 | logmatch_printed = false; | |
968 | return ret_val; | |
969 | } | |
970 | ||
971 | void TTCN_Logger::finish_event() | |
972 | { | |
973 | get_logger_plugin_manager()->finish_event(); | |
974 | } | |
975 | ||
976 | void TTCN_Logger::log_event(const char *fmt_str, ...) | |
977 | { | |
978 | va_list p_var; | |
979 | va_start(p_var, fmt_str); | |
980 | log_event_va_list(fmt_str, p_var); | |
981 | va_end(p_var); | |
982 | } | |
983 | ||
984 | void TTCN_Logger::log_event_str(const char *str_ptr) | |
985 | { | |
986 | get_logger_plugin_manager()->log_event_str(str_ptr); | |
987 | logmatch_printed = false; | |
988 | } | |
989 | ||
990 | void TTCN_Logger::log_event_va_list(const char *fmt_str, va_list p_var) | |
991 | { | |
992 | get_logger_plugin_manager()->log_event_va_list(fmt_str, p_var); | |
993 | logmatch_printed = false; | |
994 | } | |
995 | ||
996 | void TTCN_Logger::log_event_unbound() | |
997 | { | |
998 | switch (data_log_format) { | |
999 | case LF_LEGACY: | |
1000 | log_event_str("<unbound>"); | |
1001 | break; | |
1002 | case LF_TTCN: | |
1003 | log_char('-'); | |
1004 | break; | |
1005 | default: | |
1006 | log_event_str("<unknown>"); | |
1007 | } | |
1008 | } | |
1009 | ||
1010 | void TTCN_Logger::log_event_uninitialized() | |
1011 | { | |
1012 | switch (data_log_format) { | |
1013 | case LF_LEGACY: | |
1014 | log_event_str("<uninitialized template>"); | |
1015 | break; | |
1016 | case LF_TTCN: | |
1017 | log_char('-'); | |
1018 | break; | |
1019 | default: | |
1020 | log_event_str("<unknown>"); | |
1021 | } | |
1022 | } | |
1023 | ||
1024 | void TTCN_Logger::log_event_enum(const char* enum_name_str, int enum_value) | |
1025 | { | |
1026 | switch (data_log_format) { | |
1027 | case LF_LEGACY: | |
1028 | TTCN_Logger::log_event("%s (%d)", enum_name_str, enum_value); | |
1029 | break; | |
1030 | case LF_TTCN: | |
1031 | log_event_str(enum_name_str); | |
1032 | break; | |
1033 | default: | |
1034 | log_event_str("<unknown>"); | |
1035 | } | |
1036 | } | |
1037 | ||
1038 | void TTCN_Logger::log_char(char c) | |
1039 | { | |
1040 | get_logger_plugin_manager()->log_char(c); | |
1041 | logmatch_printed = false; | |
1042 | } | |
1043 | ||
1044 | boolean TTCN_Logger::is_printable(unsigned char c) | |
1045 | { | |
1046 | if (!isascii(c)) return FALSE; | |
1047 | else if (isprint(c)) return TRUE; | |
1048 | else { | |
1049 | switch (c) { | |
1050 | case '\a': | |
1051 | case '\b': | |
1052 | case '\t': | |
1053 | case '\n': | |
1054 | case '\v': | |
1055 | case '\f': | |
1056 | case '\r': | |
1057 | return TRUE; | |
1058 | default: | |
1059 | return FALSE; | |
1060 | } | |
1061 | } | |
1062 | } | |
1063 | ||
1064 | void TTCN_Logger::log_char_escaped(unsigned char c) | |
1065 | { | |
1066 | switch (c) { | |
1067 | case '\n': | |
1068 | log_event_str("\\n"); | |
1069 | break; | |
1070 | case '\t': | |
1071 | log_event_str("\\t"); | |
1072 | break; | |
1073 | case '\v': | |
1074 | log_event_str("\\v"); | |
1075 | break; | |
1076 | case '\b': | |
1077 | log_event_str("\\b"); | |
1078 | break; | |
1079 | case '\r': | |
1080 | log_event_str("\\r"); | |
1081 | break; | |
1082 | case '\f': | |
1083 | log_event_str("\\f"); | |
1084 | break; | |
1085 | case '\a': | |
1086 | log_event_str("\\a"); | |
1087 | break; | |
1088 | case '\\': | |
1089 | log_event_str("\\\\"); | |
1090 | break; | |
1091 | case '"': | |
1092 | log_event_str("\\\""); | |
1093 | break; | |
1094 | default: | |
1095 | if (isprint(c)) log_char(c); | |
1096 | else log_event("\\%03o", c); | |
1097 | break; | |
1098 | } | |
1099 | } | |
1100 | ||
1101 | void TTCN_Logger::log_char_escaped(unsigned char c, char*& p_buffer) { | |
1102 | switch (c) { | |
1103 | case '\n': | |
1104 | p_buffer = mputstr(p_buffer, "\\n"); | |
1105 | break; | |
1106 | case '\t': | |
1107 | p_buffer = mputstr(p_buffer, "\\t"); | |
1108 | break; | |
1109 | case '\v': | |
1110 | p_buffer = mputstr(p_buffer, "\\v"); | |
1111 | break; | |
1112 | case '\b': | |
1113 | p_buffer = mputstr(p_buffer, "\\b"); | |
1114 | break; | |
1115 | case '\r': | |
1116 | p_buffer = mputstr(p_buffer, "\\r"); | |
1117 | break; | |
1118 | case '\f': | |
1119 | p_buffer = mputstr(p_buffer, "\\f"); | |
1120 | break; | |
1121 | case '\a': | |
1122 | p_buffer = mputstr(p_buffer, "\\a"); | |
1123 | break; | |
1124 | case '\\': | |
1125 | p_buffer = mputstr(p_buffer, "\\\\"); | |
1126 | break; | |
1127 | case '"': | |
1128 | p_buffer = mputstr(p_buffer, "\\\""); | |
1129 | break; | |
1130 | default: | |
1131 | if (isprint(c)) p_buffer = mputc(p_buffer, c); | |
1132 | else | |
1133 | p_buffer = mputprintf(p_buffer, "\\%03o", c); | |
1134 | break; | |
1135 | } | |
1136 | } | |
1137 | ||
1138 | static const char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', | |
1139 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; | |
1140 | ||
1141 | void TTCN_Logger::log_hex(unsigned char nibble) | |
1142 | { | |
1143 | if (nibble < 16) log_char(hex_digits[nibble]); | |
1144 | else log_event_str("<unknown>"); | |
1145 | } | |
1146 | ||
1147 | void TTCN_Logger::log_octet(unsigned char octet) | |
1148 | { | |
1149 | log_char(hex_digits[octet >> 4]); | |
1150 | log_char(hex_digits[octet & 0x0F]); | |
1151 | } | |
1152 | ||
1153 | void TTCN_Logger::OS_error() | |
1154 | { | |
1155 | if (errno != 0) { | |
1156 | const char *error_string = strerror(errno); | |
1157 | if (error_string != NULL) log_event(" (%s)", error_string); | |
1158 | else log_event(" (Unknown error: errno = %d)", errno); | |
1159 | errno = 0; | |
1160 | } | |
1161 | } | |
1162 | ||
1163 | void TTCN_Logger::log_timer_read(const char *timer_name, | |
1164 | double timeout_val) | |
1165 | { | |
1166 | get_logger_plugin_manager()->log_timer_read(timer_name, timeout_val); | |
1167 | } | |
1168 | ||
1169 | void TTCN_Logger::log_timer_start(const char *timer_name, double start_val) | |
1170 | { | |
1171 | get_logger_plugin_manager()->log_timer_start(timer_name, start_val); | |
1172 | } | |
1173 | ||
1174 | void TTCN_Logger::log_timer_guard(double start_val) | |
1175 | { | |
1176 | get_logger_plugin_manager()->log_timer_guard(start_val); | |
1177 | } | |
1178 | ||
1179 | void TTCN_Logger::log_timer_stop(const char *timer_name, double stop_val) | |
1180 | { | |
1181 | get_logger_plugin_manager()->log_timer_stop(timer_name, stop_val); | |
1182 | } | |
1183 | ||
1184 | void TTCN_Logger::log_timer_timeout(const char *timer_name, | |
1185 | double timeout_val) | |
1186 | { | |
1187 | get_logger_plugin_manager()->log_timer_timeout(timer_name, timeout_val); | |
1188 | } | |
1189 | ||
1190 | void TTCN_Logger::log_timer_any_timeout() | |
1191 | { | |
1192 | get_logger_plugin_manager()->log_timer_any_timeout(); | |
1193 | } | |
1194 | ||
1195 | void TTCN_Logger::log_timer_unqualified(const char *message) | |
1196 | { | |
1197 | get_logger_plugin_manager()->log_timer_unqualified(message); | |
1198 | } | |
1199 | ||
1200 | void TTCN_Logger::log_testcase_started(const qualified_name& testcase_name) | |
1201 | { | |
1202 | get_logger_plugin_manager()->log_testcase_started(testcase_name); | |
1203 | } | |
1204 | ||
1205 | void TTCN_Logger::log_testcase_finished(const qualified_name& testcase_name, | |
1206 | verdicttype verdict, | |
1207 | const char *reason) | |
1208 | { | |
1209 | get_logger_plugin_manager()->log_testcase_finished(testcase_name, verdict, reason); | |
1210 | } | |
1211 | ||
1212 | void TTCN_Logger::log_setverdict(verdicttype new_verdict, verdicttype old_verdict, | |
1213 | verdicttype local_verdict, const char *old_reason, const char *new_reason) | |
1214 | { | |
1215 | get_logger_plugin_manager()->log_setverdict(new_verdict, old_verdict, | |
1216 | local_verdict, old_reason, new_reason); | |
1217 | } | |
1218 | ||
1219 | void TTCN_Logger::log_getverdict(verdicttype verdict) | |
1220 | { | |
1221 | get_logger_plugin_manager()->log_getverdict(verdict); | |
1222 | } | |
1223 | ||
1224 | void TTCN_Logger::log_final_verdict(bool is_ptc, verdicttype ptc_verdict, | |
1225 | verdicttype local_verdict, verdicttype new_verdict, | |
1226 | const char *verdict_reason, int notification, int ptc_compref, | |
1227 | const char *ptc_name) | |
1228 | { | |
1229 | get_logger_plugin_manager()->log_final_verdict(is_ptc, ptc_verdict, | |
1230 | local_verdict, new_verdict, verdict_reason, notification, ptc_compref, ptc_name); | |
1231 | } | |
1232 | ||
1233 | void TTCN_Logger::log_controlpart_start_stop(const char *module_name, int finished) | |
1234 | { | |
1235 | get_logger_plugin_manager()->log_controlpart_start_stop(module_name, finished); | |
1236 | } | |
1237 | ||
1238 | void TTCN_Logger::log_controlpart_errors(unsigned int error_count) | |
1239 | { | |
1240 | get_logger_plugin_manager()->log_controlpart_errors(error_count); | |
1241 | } | |
1242 | ||
1243 | void TTCN_Logger::log_verdict_statistics(size_t none_count, double none_percent, | |
1244 | size_t pass_count, double pass_percent, | |
1245 | size_t inconc_count, double inconc_percent, | |
1246 | size_t fail_count, double fail_percent, | |
1247 | size_t error_count, double error_percent) | |
1248 | { | |
1249 | get_logger_plugin_manager()->log_verdict_statistics(none_count, none_percent, | |
1250 | pass_count, pass_percent, | |
1251 | inconc_count, inconc_percent, | |
1252 | fail_count, fail_percent, | |
1253 | error_count, error_percent); | |
1254 | } | |
1255 | ||
1256 | void TTCN_Logger::log_defaultop_activate(const char *name, int id) | |
1257 | { | |
1258 | get_logger_plugin_manager()->log_defaultop_activate(name, id); | |
1259 | } | |
1260 | ||
1261 | void TTCN_Logger::log_defaultop_deactivate(const char *name, int id) | |
1262 | { | |
1263 | get_logger_plugin_manager()->log_defaultop_deactivate(name, id); | |
1264 | } | |
1265 | ||
1266 | void TTCN_Logger::log_defaultop_exit(const char *name, int id, int x) | |
1267 | { | |
1268 | get_logger_plugin_manager()->log_defaultop_exit(name, id, x); | |
1269 | } | |
1270 | ||
1271 | void TTCN_Logger::log_executor_runtime(int reason) | |
1272 | { | |
1273 | get_logger_plugin_manager()->log_executor_runtime(reason); | |
1274 | } | |
1275 | ||
1276 | void TTCN_Logger::log_HC_start(const char *host) | |
1277 | { | |
1278 | get_logger_plugin_manager()->log_HC_start(host); | |
1279 | } | |
1280 | ||
1281 | void TTCN_Logger::log_fd_limits(int fd_limit, long fd_set_size) | |
1282 | { | |
1283 | get_logger_plugin_manager()->log_fd_limits(fd_limit, fd_set_size); | |
1284 | } | |
1285 | ||
1286 | void TTCN_Logger::log_testcase_exec(const char *module, const char *tc) | |
1287 | { | |
1288 | get_logger_plugin_manager()->log_testcase_exec(module, tc); | |
1289 | } | |
1290 | ||
1291 | void TTCN_Logger::log_module_init(const char *module, bool finish) | |
1292 | { | |
1293 | get_logger_plugin_manager()->log_module_init(module, finish); | |
1294 | } | |
1295 | ||
1296 | void TTCN_Logger::log_mtc_created(long pid) | |
1297 | { | |
1298 | get_logger_plugin_manager()->log_mtc_created(pid); | |
1299 | } | |
1300 | ||
1301 | void TTCN_Logger::log_configdata(int reason, const char *str) | |
1302 | { | |
1303 | get_logger_plugin_manager()->log_configdata(reason, str); | |
1304 | } | |
1305 | ||
1306 | void TTCN_Logger::log_executor_component(int reason) | |
1307 | { | |
1308 | get_logger_plugin_manager()->log_executor_component(reason); | |
1309 | } | |
1310 | ||
1311 | void TTCN_Logger::log_executor_misc(int reason, const char *name, | |
1312 | const char *address, int port) | |
1313 | { | |
1314 | get_logger_plugin_manager()->log_executor_misc(reason, name, address, port); | |
1315 | } | |
1316 | ||
1317 | void TTCN_Logger::log_extcommand(extcommand_t action, const char *cmd) | |
1318 | { | |
1319 | get_logger_plugin_manager()->log_extcommand(action, cmd); | |
1320 | } | |
1321 | ||
1322 | void TTCN_Logger::log_matching_done(const char *type, int ptc, | |
1323 | const char *return_type, int reason) | |
1324 | { | |
1325 | get_logger_plugin_manager()->log_matching_done(reason, type, ptc, return_type); | |
1326 | } | |
1327 | ||
1328 | void TTCN_Logger::log_matching_problem(int reason, int operation, boolean check, | |
1329 | boolean anyport, const char *port_name) | |
1330 | { | |
1331 | get_logger_plugin_manager()->log_matching_problem(reason, operation, | |
1332 | check, anyport, port_name); | |
1333 | } | |
1334 | ||
1335 | void TTCN_Logger::log_matching_success(int port_type, const char *port_name, | |
1336 | int compref, const CHARSTRING& info) | |
1337 | { | |
1338 | get_logger_plugin_manager()->log_matching_success(port_type, port_name, | |
1339 | compref, info); | |
1340 | } | |
1341 | ||
1342 | void TTCN_Logger::log_matching_failure(int port_type, const char *port_name, | |
1343 | int compref, int reason, const CHARSTRING& info) | |
1344 | { | |
1345 | get_logger_plugin_manager()->log_matching_failure(port_type, port_name, | |
1346 | compref, reason, info); | |
1347 | } | |
1348 | ||
1349 | void TTCN_Logger::log_matching_timeout(const char *timer_name) | |
1350 | { | |
1351 | get_logger_plugin_manager()->log_matching_timeout(timer_name); | |
1352 | } | |
1353 | ||
1354 | void TTCN_Logger::log_portconnmap(int operation, int src_compref, const char *src_port, | |
1355 | int dst_compref, const char *dst_port) | |
1356 | { | |
1357 | get_logger_plugin_manager()->log_portconnmap(operation, src_compref, src_port, | |
1358 | dst_compref, dst_port); | |
1359 | } | |
1360 | ||
1361 | void TTCN_Logger::log_par_ptc(int reason, const char *module, const char *name, | |
1362 | int compref, const char *compname, const char *tc_loc, int alive_pid, int status) | |
1363 | { | |
1364 | get_logger_plugin_manager()->log_par_ptc(reason, module, name, compref, | |
1365 | compname, tc_loc, alive_pid, status); | |
1366 | } | |
1367 | ||
1368 | void TTCN_Logger::log_port_queue(int operation, const char *port_name, int compref, | |
1369 | int id, const CHARSTRING& address, const CHARSTRING& param) | |
1370 | { | |
1371 | get_logger_plugin_manager()->log_port_queue(operation, port_name, compref, | |
1372 | id, address, param); | |
1373 | } | |
1374 | ||
1375 | void TTCN_Logger::log_port_state(int operation, const char *port_name) | |
1376 | { | |
1377 | get_logger_plugin_manager()->log_port_state(operation, port_name); | |
1378 | } | |
1379 | ||
1380 | void TTCN_Logger::log_procport_send(const char *portname, int operation, int compref, | |
1381 | const CHARSTRING& system, const CHARSTRING& param) | |
1382 | { | |
1383 | get_logger_plugin_manager()->log_procport_send(portname, operation, compref, | |
1384 | system, param); | |
1385 | } | |
1386 | ||
1387 | void TTCN_Logger::log_procport_recv(const char *portname, int operation, | |
1388 | int compref, boolean check, const CHARSTRING& param, int id) | |
1389 | { | |
1390 | get_logger_plugin_manager()->log_procport_recv(portname, operation, compref, | |
1391 | check, param, id); | |
1392 | } | |
1393 | ||
1394 | void TTCN_Logger::log_msgport_send(const char *portname, int compref, | |
1395 | const CHARSTRING& param) | |
1396 | { | |
1397 | get_logger_plugin_manager()->log_msgport_send(portname, compref, param); | |
1398 | } | |
1399 | ||
1400 | void TTCN_Logger::log_msgport_recv(const char *portname, int operation, int compref, | |
1401 | const CHARSTRING& system, const CHARSTRING& param, int id) | |
1402 | { | |
1403 | get_logger_plugin_manager()->log_msgport_recv(portname, operation, compref, | |
1404 | system, param, id); | |
1405 | } | |
1406 | ||
1407 | void TTCN_Logger::log_dualport_map(boolean incoming, const char *target_type, | |
1408 | const CHARSTRING& value, int id) | |
1409 | { | |
1410 | get_logger_plugin_manager()->log_dualport_map(incoming, target_type, value, id); | |
1411 | } | |
1412 | ||
1413 | void TTCN_Logger::log_dualport_discard(boolean incoming, const char *target_type, | |
1414 | const char *port_name, boolean unhandled) | |
1415 | { | |
1416 | get_logger_plugin_manager()->log_dualport_discard(incoming, target_type, port_name, | |
1417 | unhandled); | |
1418 | } | |
1419 | ||
1420 | void TTCN_Logger::log_port_misc(int reason, const char *port_name, | |
1421 | int remote_component, const char *remote_port, | |
1422 | const char *ip_address, int tcp_port, int new_size) | |
1423 | { | |
1424 | get_logger_plugin_manager()->log_port_misc(reason, port_name, | |
1425 | remote_component, remote_port, ip_address, tcp_port, new_size); | |
1426 | } | |
1427 | ||
1428 | void TTCN_Logger::log_random(int action, double v, unsigned long u) | |
1429 | { | |
1430 | get_logger_plugin_manager()->log_random(action, v, u); | |
1431 | } | |
1432 | ||
1433 | void TTCN_Logger::clear_parameters() { | |
1434 | get_logger_plugin_manager()->clear_param_list(); | |
1435 | get_logger_plugin_manager()->clear_plugin_list(); | |
1436 | } | |
1437 | ||
1438 | // The one instance (only for backward compatibility). | |
1439 | TTCN_Logger TTCN_logger; | |
1440 | ||
1441 | // Location related stuff. | |
1442 | TTCN_Location *TTCN_Location::innermost_location = NULL, | |
1443 | *TTCN_Location::outermost_location = NULL; | |
1444 | ||
1445 | TTCN_Location::TTCN_Location(const char *par_file_name, | |
1446 | unsigned int par_line_number, entity_type_t par_entity_type, | |
1447 | const char *par_entity_name) | |
1448 | : file_name(par_file_name), line_number(par_line_number), | |
1449 | entity_type(par_entity_type), entity_name(par_entity_name), | |
1450 | inner_location(NULL), outer_location(innermost_location) | |
1451 | { | |
1452 | if (par_file_name == NULL) file_name = "<unknown file>"; | |
1453 | if (par_entity_type == LOCATION_UNKNOWN) entity_name = NULL; | |
1454 | else if (par_entity_name == NULL) entity_name = "<unknown>"; | |
1455 | if (outer_location != NULL) outer_location->inner_location = this; | |
1456 | else outermost_location = this; | |
1457 | innermost_location = this; | |
1458 | } | |
1459 | ||
1460 | void TTCN_Location::update_lineno(unsigned int new_lineno) | |
1461 | { | |
1462 | line_number = new_lineno; | |
1463 | } | |
1464 | ||
1465 | TTCN_Location::~TTCN_Location() | |
1466 | { | |
1467 | if (inner_location == NULL) innermost_location = outer_location; | |
1468 | else inner_location->outer_location = outer_location; | |
1469 | if (outer_location == NULL) outermost_location = inner_location; | |
1470 | else outer_location->inner_location = inner_location; | |
1471 | } | |
1472 | ||
1473 | char *TTCN_Location::print_location(boolean print_outers, | |
1474 | boolean print_innermost, boolean print_entity_name) | |
1475 | { | |
1476 | char *ret_val = NULL; | |
1477 | if (innermost_location != NULL) { | |
1478 | if (print_outers) { | |
1479 | for (TTCN_Location *iter = outermost_location; | |
1480 | iter != NULL && iter != innermost_location; | |
1481 | iter = iter->inner_location) | |
1482 | ret_val = iter->append_contents(ret_val, print_entity_name); | |
1483 | } | |
1484 | if (print_innermost) | |
1485 | ret_val = innermost_location->append_contents(ret_val, | |
1486 | print_entity_name); | |
1487 | } | |
1488 | return ret_val; | |
1489 | } | |
1490 | ||
1491 | void TTCN_Location::strip_entity_name(char*& par_str) | |
1492 | { | |
1493 | if (!par_str) return; | |
1494 | char *new_str = NULL; | |
1495 | bool in_paren = false; | |
1496 | for (char *str_ptr = par_str; *str_ptr != '\0' ; str_ptr++) { | |
1497 | switch (*str_ptr) { | |
1498 | case '(': | |
1499 | in_paren = true; | |
1500 | break; | |
1501 | case ')': | |
1502 | in_paren = false; | |
1503 | break; | |
1504 | default: | |
1505 | if (!in_paren) new_str = mputc(new_str, *str_ptr); | |
1506 | break; | |
1507 | } | |
1508 | } | |
1509 | Free(par_str); | |
1510 | par_str = new_str; | |
1511 | } | |
1512 | ||
f08ff9ca BB |
1513 | unsigned int TTCN_Location::get_line_number() |
1514 | { | |
1515 | if (innermost_location != NULL) { | |
1516 | return innermost_location->line_number; | |
1517 | } | |
1518 | return 0; | |
1519 | } | |
1520 | ||
970ed795 EL |
1521 | char *TTCN_Location::append_contents(char *par_str, |
1522 | boolean print_entity_name) const | |
1523 | { | |
1524 | if (par_str != NULL) par_str = mputstr(par_str, "->"); | |
1525 | par_str = mputprintf(par_str, "%s:%u", file_name, line_number); | |
1526 | if (print_entity_name) { | |
1527 | switch (entity_type) { | |
1528 | case LOCATION_CONTROLPART: | |
1529 | par_str = mputprintf(par_str, "(controlpart:%s)", entity_name); | |
1530 | break; | |
1531 | case LOCATION_TESTCASE: | |
1532 | par_str = mputprintf(par_str, "(testcase:%s)", entity_name); | |
1533 | break; | |
1534 | case LOCATION_ALTSTEP: | |
1535 | par_str = mputprintf(par_str, "(altstep:%s)", entity_name); | |
1536 | break; | |
1537 | case LOCATION_FUNCTION: | |
1538 | par_str = mputprintf(par_str, "(function:%s)", entity_name); | |
1539 | break; | |
1540 | case LOCATION_EXTERNALFUNCTION: | |
1541 | par_str = mputprintf(par_str, "(externalfunction:%s)", entity_name); | |
1542 | break; | |
1543 | case LOCATION_TEMPLATE: | |
1544 | par_str = mputprintf(par_str, "(template:%s)", entity_name); | |
1545 | break; | |
1546 | default: | |
1547 | break; | |
1548 | } | |
1549 | } | |
1550 | return par_str; | |
1551 | } | |
1552 | ||
1553 | TTCN_Location_Statistics::TTCN_Location_Statistics(const char *par_file_name, | |
1554 | unsigned int par_line_number, entity_type_t par_entity_type, | |
1555 | const char *par_entity_name): TTCN_Location(par_file_name, par_line_number, | |
1556 | par_entity_type, par_entity_name) | |
1557 | { | |
1558 | TCov::hit(file_name, line_number, entity_name); | |
1559 | } | |
1560 | ||
1561 | void TTCN_Location_Statistics::update_lineno(unsigned int new_lineno) | |
1562 | { | |
1563 | TTCN_Location::update_lineno(new_lineno); | |
1564 | TCov::hit(file_name, line_number); | |
1565 | } | |
1566 | ||
1567 | void TTCN_Location_Statistics::init_file_lines(const char *file_name, const int line_nos[], size_t line_nos_len) | |
1568 | { | |
1569 | TCov::init_file_lines(file_name, line_nos, line_nos_len); | |
1570 | } | |
1571 | ||
1572 | void TTCN_Location_Statistics::init_file_functions(const char *file_name, const char *function_names[], size_t function_names_len) | |
1573 | { | |
1574 | TCov::init_file_functions(file_name, function_names, function_names_len); | |
1575 | } | |
1576 | ||
1577 | TTCN_Location_Statistics::~TTCN_Location_Statistics() { } | |
1578 | ||
1579 | expstring_t component_string(const component_id_t& comp_id) | |
1580 | { | |
1581 | expstring_t retval; | |
1582 | switch( comp_id.id_selector ) { | |
1583 | case COMPONENT_ID_NAME: | |
1584 | retval = mcopystr(comp_id.id_name); | |
1585 | break; | |
1586 | case COMPONENT_ID_COMPREF: | |
1587 | retval = mprintf("%d", comp_id.id_compref); | |
1588 | break; | |
1589 | case COMPONENT_ID_ALL: | |
1590 | retval = mcopystr("*"); | |
1591 | break; | |
1592 | case COMPONENT_ID_SYSTEM: | |
1593 | retval = mcopystr("<System>"); | |
1594 | break; | |
1595 | default: // Can't happen. | |
1596 | retval = mcopystr("Unknown component type !"); | |
1597 | break; | |
1598 | } | |
1599 | return retval; | |
1600 | } |