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