1 #include "ace/Logging_Strategy.h"
2 #include "ace/Service_Config.h"
4 #include "ace/ACE_export.h"
5 #include "ace/Get_Opt.h"
7 // FUZZ: disable check_for_streams_include
8 #include "ace/streams.h"
10 #include "ace/Lib_Find.h"
11 #include "ace/Log_Category.h"
12 #include "ace/Reactor.h"
13 #include "ace/OS_NS_string.h"
14 #include "ace/OS_NS_stdio.h"
15 #include "ace/OS_NS_unistd.h"
17 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
19 // Parse the string containing (thread) priorities and set them
23 ACE_Logging_Strategy::priorities (ACE_TCHAR
*priority_string
,
24 ACE_Log_Msg::MASK_TYPE mask
)
26 u_long priority_mask
= 0;
28 // Choose priority mask to change.
30 if (mask
== ACE_Log_Msg::PROCESS
)
31 priority_mask
= process_priority_mask_
;
33 priority_mask
= thread_priority_mask_
;
35 ACE_TCHAR
*strtokp
= 0;
37 // Parse string and alternate priority mask.
39 for (ACE_TCHAR
*priority
= ACE_OS::strtok_r (priority_string
,
43 priority
= ACE_OS::strtok_r (0,
47 if (ACE_OS::strcmp (priority
, ACE_TEXT ("SHUTDOWN")) == 0)
48 ACE_SET_BITS (priority_mask
, LM_SHUTDOWN
);
49 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~SHUTDOWN")) == 0)
50 ACE_CLR_BITS (priority_mask
, LM_SHUTDOWN
);
51 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("TRACE")) == 0)
52 ACE_SET_BITS (priority_mask
, LM_TRACE
);
53 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~TRACE")) == 0)
54 ACE_CLR_BITS (priority_mask
, LM_TRACE
);
55 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("DEBUG")) == 0)
56 ACE_SET_BITS (priority_mask
, LM_DEBUG
);
57 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~DEBUG")) == 0)
58 ACE_CLR_BITS (priority_mask
, LM_DEBUG
);
59 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("INFO")) == 0)
60 ACE_SET_BITS (priority_mask
, LM_INFO
);
61 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~INFO")) == 0)
62 ACE_CLR_BITS (priority_mask
, LM_INFO
);
63 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("NOTICE")) == 0)
64 ACE_SET_BITS (priority_mask
, LM_NOTICE
);
65 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~NOTICE")) == 0)
66 ACE_CLR_BITS (priority_mask
, LM_NOTICE
);
67 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("WARNING")) == 0)
68 ACE_SET_BITS (priority_mask
, LM_WARNING
);
69 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~WARNING")) == 0)
70 ACE_CLR_BITS (priority_mask
, LM_WARNING
);
71 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("STARTUP")) == 0)
72 ACE_SET_BITS (priority_mask
, LM_STARTUP
);
73 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~STARTUP")) == 0)
74 ACE_CLR_BITS (priority_mask
, LM_STARTUP
);
75 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("ERROR")) == 0)
76 ACE_SET_BITS (priority_mask
, LM_ERROR
);
77 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~ERROR")) == 0)
78 ACE_CLR_BITS (priority_mask
, LM_ERROR
);
79 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("CRITICAL")) == 0)
80 ACE_SET_BITS (priority_mask
, LM_CRITICAL
);
81 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~CRITICAL")) == 0)
82 ACE_CLR_BITS (priority_mask
, LM_CRITICAL
);
83 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("ALERT")) == 0)
84 ACE_SET_BITS (priority_mask
, LM_ALERT
);
85 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~ALERT")) == 0)
86 ACE_CLR_BITS (priority_mask
, LM_ALERT
);
87 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("EMERGENCY")) == 0)
88 ACE_SET_BITS (priority_mask
, LM_EMERGENCY
);
89 else if (ACE_OS::strcmp (priority
, ACE_TEXT ("~EMERGENCY")) == 0)
90 ACE_CLR_BITS (priority_mask
, LM_EMERGENCY
);
93 // Affect right priority mask.
95 if (mask
== ACE_Log_Msg::PROCESS
)
96 process_priority_mask_
= priority_mask
;
98 thread_priority_mask_
= priority_mask
;
101 // Parse the string containing all the flags and set the flags
105 ACE_Logging_Strategy::tokenize (ACE_TCHAR
*flag_string
)
109 for (ACE_TCHAR
*flag
= ACE_OS::strtok_r (flag_string
,
113 flag
= ACE_OS::strtok_r (0, ACE_TEXT ("|"), &strtokp
))
115 if (ACE_OS::strcmp (flag
, ACE_TEXT ("STDERR")) == 0)
116 ACE_SET_BITS (this->flags_
, ACE_Log_Msg::STDERR
);
117 else if (ACE_OS::strcmp (flag
, ACE_TEXT ("LOGGER")) == 0)
118 ACE_SET_BITS (this->flags_
, ACE_Log_Msg::LOGGER
);
119 else if (ACE_OS::strcmp (flag
, ACE_TEXT ("OSTREAM")) == 0)
120 ACE_SET_BITS (this->flags_
, ACE_Log_Msg::OSTREAM
);
121 else if (ACE_OS::strcmp (flag
, ACE_TEXT ("VERBOSE")) == 0)
122 ACE_SET_BITS (this->flags_
, ACE_Log_Msg::VERBOSE
);
123 else if (ACE_OS::strcmp (flag
, ACE_TEXT ("VERBOSE_LITE")) == 0)
124 ACE_SET_BITS (this->flags_
, ACE_Log_Msg::VERBOSE_LITE
);
125 else if (ACE_OS::strcmp (flag
, ACE_TEXT ("SILENT")) == 0)
126 ACE_SET_BITS (this->flags_
, ACE_Log_Msg::SILENT
);
127 else if (ACE_OS::strcmp (flag
, ACE_TEXT ("SYSLOG")) == 0)
128 ACE_SET_BITS (this->flags_
, ACE_Log_Msg::SYSLOG
);
133 ACE_Logging_Strategy::parse_args (int argc
, ACE_TCHAR
*argv
[])
135 ACE_TRACE ("ACE_Logging_Strategy::parse_args");
138 // Perform data member initializations. BTW, do *not* initialize
139 // <thread_priority_mask_> or <process_priority_mask_> here to avoid
140 // unduing the behavior in <init>, where these are set by
141 // <ACE_Log_Msg::instance>.
143 this->wipeout_logfile_
= false;
145 this->fixed_number_
= false;
146 this->order_files_
= false;
147 this->max_file_number_
= 1;
148 this->interval_
= ACE_DEFAULT_LOGFILE_POLL_INTERVAL
;
151 ACE_Get_Opt
get_opt (argc
, argv
,
152 ACE_TEXT ("f:i:k:m:n:N:op:s:t:w"), 0);
154 for (int c
; (c
= get_opt ()) != -1; )
159 temp
= get_opt
.opt_arg ();
160 // Now tokenize the string to get all the flags
161 this->tokenize (temp
);
162 // If LOGGER was specified, set up the default logger key.
163 // The key can be changed by the -k option also, so if it's
164 // been set already, don't set it.
165 if (ACE_BIT_ENABLED (this->flags_
, ACE_Log_Msg::LOGGER
) &&
166 this->logger_key_
== 0)
167 this->logger_key_
= ACE::strnew (ACE_DEFAULT_LOGGER_KEY
);
170 // Interval (in secs) at which logfile size is sampled.
171 this->interval_
= ACE_OS::strtoul (get_opt
.opt_arg (), 0, 10);
174 // Ensure that the LOGGER flag is set
175 ACE_SET_BITS (this->flags_
, ACE_Log_Msg::LOGGER
);
176 #if defined (ACE_HAS_ALLOC_HOOKS)
177 ACE_Allocator::instance()->free(this->logger_key_
);
179 delete [] this->logger_key_
;
180 #endif /* ACE_HAS_ALLOC_HOOKS */
181 this->logger_key_
= ACE::strnew (get_opt
.opt_arg ());
184 // Maximum logfile size (in KB). Must be a non-zero value.
185 this->max_size_
= ACE_OS::strtoul (get_opt
.opt_arg (), 0, 10);
186 this->max_size_
<<= 10; // convert from KB to bytes.
189 #if defined (ACE_HAS_ALLOC_HOOKS)
190 ACE_Allocator::instance()->free(this->program_name_
);
192 delete [] this->program_name_
;
193 #endif /* ACE_HAS_ALLOC_HOOKS */
194 this->program_name_
= ACE::strnew (get_opt
.opt_arg ());
197 // The max number for the log_file being created
198 this->max_file_number_
= ACE_OS::atoi (get_opt
.opt_arg ()) - 1;
199 this->fixed_number_
= true;
202 // Log_files generation order
203 this->order_files_
= true;
206 temp
= get_opt
.opt_arg ();
207 // Now tokenize the string to setup process log priority
208 this->priorities (temp
, ACE_Log_Msg::PROCESS
);
211 // Ensure that the OSTREAM flag is set
212 ACE_SET_BITS (this->flags_
, ACE_Log_Msg::OSTREAM
);
213 #if defined (ACE_HAS_ALLOC_HOOKS)
214 ACE_Allocator::instance()->free(this->filename_
);
216 delete [] this->filename_
;
217 #endif /* ACE_HAS_ALLOC_HOOKS */
218 this->filename_
= ACE::strnew (get_opt
.opt_arg ());
221 temp
= get_opt
.opt_arg ();
222 // Now tokenize the string to setup thread log priority
223 this->priorities (temp
, ACE_Log_Msg::THREAD
);
226 // Cause the logfile to be wiped out, both on startup and on
228 this->wipeout_logfile_
= true;
237 ACE_Logging_Strategy::ACE_Logging_Strategy ()
238 : thread_priority_mask_ (0),
239 process_priority_mask_ (0),
244 wipeout_logfile_ (false),
245 fixed_number_ (false),
246 order_files_ (false),
248 max_file_number_ (1), // 2 files by default (max file number + 1)
249 interval_ (ACE_DEFAULT_LOGFILE_POLL_INTERVAL
),
251 log_msg_ (ACE_Log_Msg::instance ())
253 #if defined (ACE_DEFAULT_LOGFILE)
254 this->filename_
= ACE::strnew (ACE_DEFAULT_LOGFILE
);
255 #else /* ACE_DEFAULT_LOGFILE */
256 #if defined (ACE_HAS_ALLOC_HOOKS)
257 ACE_ALLOCATOR (this->filename_
,
258 static_cast<ACE_TCHAR
*>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
) * (MAXPATHLEN
+ 1))));
260 ACE_NEW (this->filename_
,
261 ACE_TCHAR
[MAXPATHLEN
+ 1]);
262 #endif /* ACE_HAS_ALLOC_HOOKS */
264 // Get the temporary directory
265 if (ACE::get_temp_dir
267 MAXPATHLEN
- 7) == -1) // 7 for "logfile"
269 ACELIB_ERROR ((LM_ERROR
,
270 ACE_TEXT ("Temporary path too long, ")
271 ACE_TEXT ("defaulting to current directory\n")));
272 this->filename_
[0] = 0;
275 // Add the filename to the end
276 ACE_OS::strcat (this->filename_
,
277 ACE_TEXT ("logfile"));
278 #endif /* ACE_DEFAULT_LOGFILE */
281 ACE_Logging_Strategy::~ACE_Logging_Strategy ()
283 // This is allocated in constructor, so it must be deallocated in
285 #if defined (ACE_HAS_ALLOC_HOOKS)
286 ACE_Allocator::instance()->free(this->filename_
);
288 delete [] this->filename_
;
289 #endif /* ACE_HAS_ALLOC_HOOKS */
293 ACE_Logging_Strategy::fini ()
295 #if defined (ACE_HAS_ALLOC_HOOKS)
296 ACE_Allocator::instance()->free(this->filename_
);
298 delete [] this->filename_
;
299 #endif /* ACE_HAS_ALLOC_HOOKS */
300 this->filename_
= 0; // Avoid double deletions.
302 #if defined (ACE_HAS_ALLOC_HOOKS)
303 ACE_Allocator::instance()->free(this->logger_key_
);
304 ACE_Allocator::instance()->free(this->program_name_
);
306 delete [] this->logger_key_
;
307 delete [] this->program_name_
;
308 #endif /* ACE_HAS_ALLOC_HOOKS */
311 && this->interval_
> 0 && this->max_size_
> 0)
312 this->reactor ()->cancel_timer (this);
318 ACE_Logging_Strategy::init (int argc
, ACE_TCHAR
*argv
[])
320 ACE_TRACE ("ACE_Logging_Strategy::init");
322 // Store current priority masks for changes in <parse_args>.
324 this->process_priority_mask_
=
325 this->log_msg_
->priority_mask (ACE_Log_Msg::PROCESS
);
327 this->thread_priority_mask_
=
328 this->log_msg_
->priority_mask (ACE_Log_Msg::THREAD
);
330 // Use the options hook to parse the command line arguments.
331 this->parse_args (argc
, argv
);
333 // Setup priorities (to original if not specified on command line)
335 this->log_msg_
->priority_mask (thread_priority_mask_
,
336 ACE_Log_Msg::THREAD
);
338 this->log_msg_
->priority_mask (process_priority_mask_
,
339 ACE_Log_Msg::PROCESS
);
341 // Check if any flags were specified. If none were specified, let
342 // the default behavior take effect.
343 if (this->flags_
!= 0)
346 this->log_msg_
->clr_flags (ACE_Log_Msg::STDERR
347 | ACE_Log_Msg::LOGGER
348 | ACE_Log_Msg::OSTREAM
349 | ACE_Log_Msg::VERBOSE
350 | ACE_Log_Msg::VERBOSE_LITE
351 | ACE_Log_Msg::SILENT
352 | ACE_Log_Msg::SYSLOG
);
353 // Check if OSTREAM bit is set
354 if (ACE_BIT_ENABLED (this->flags_
,
355 ACE_Log_Msg::OSTREAM
))
357 int delete_ostream
= 0;
358 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
359 FILE *output_file
= this->log_msg_
->msg_ostream ();
360 if (wipeout_logfile_
)
362 // close and re-open a stream if such exits
364 ACE_OS::fclose (output_file
) == -1)
366 output_file
= ACE_OS::fopen (this->filename_
, ACE_TEXT ("wt"));
368 // open a stream only if such doesn't exists
369 else if (output_file
== 0)
370 output_file
= ACE_OS::fopen (this->filename_
,
373 if (output_file
== 0)
376 ostream
*output_file
= this->log_msg_
->msg_ostream ();
377 // Create a new ofstream to direct output to the file.
378 if (wipeout_logfile_
)
382 ofstream (ACE_TEXT_ALWAYS_CHAR (this->filename_
)),
386 else if (output_file
== 0)
390 ofstream (ACE_TEXT_ALWAYS_CHAR (this->filename_
),
391 ios::app
| ios::out
),
396 if (output_file
->rdstate () != ios::goodbit
)
402 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
403 // Set the <output_file> that'll be used by the rest of the
405 this->log_msg_
->msg_ostream (output_file
, delete_ostream
);
407 // Setup a timeout handler to perform the maximum file size
408 // check (if required).
409 if (this->interval_
> 0 && this->max_size_
> 0)
411 if (this->reactor () == 0)
413 this->reactor (ACE_Reactor::instance ());
416 // Now set the flags for Log_Msg
417 this->log_msg_
->set_flags (this->flags_
);
420 return this->log_msg_
->open (this->program_name_
,
421 this->log_msg_
->flags (),
426 ACE_Logging_Strategy::handle_timeout (const ACE_Time_Value
&,
429 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
430 if ((size_t) ACE_OS::ftell (this->log_msg_
->msg_ostream ()) > this->max_size_
)
432 if ((size_t) this->log_msg_
->msg_ostream ()->tellp () > this->max_size_
)
433 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
435 // Lock out any other logging.
436 if (this->log_msg_
->acquire ())
437 ACELIB_ERROR_RETURN ((LM_ERROR
,
438 ACE_TEXT ("Cannot acquire lock!\n")),
441 // Close the current ostream.
442 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
443 FILE *output_file
= (FILE *) this->log_msg_
->msg_ostream ();
444 ACE_OS::fclose (output_file
);
445 // We'll call msg_ostream() modifier later.
447 ofstream
*output_file
=
448 (ofstream
*) this->log_msg_
->msg_ostream ();
449 output_file
->close ();
450 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
451 // Save current logfile to logfile.old analyze if it was set any
452 // fixed number for the log_files.
455 if (max_file_number_
< 1) //we only want one file
457 // Just unlink the file.
458 ACE_OS::unlink (this->filename_
);
460 // Open a new log file with the same name.
461 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
462 output_file
= ACE_OS::fopen (this->filename_
,
465 if (output_file
== 0)
468 this->log_msg_
->msg_ostream (output_file
);
470 output_file
->open (ACE_TEXT_ALWAYS_CHAR (this->filename_
),
472 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
474 // Release the lock previously acquired.
475 this->log_msg_
->release ();
481 // Set the number of digits of the log_files labels.
482 int digits
= 1, res
= count_
;
483 while((res
= (res
/ 10))>0)
486 if (ACE_OS::strlen (this->filename_
) + digits
<= MAXPATHLEN
)
488 ACE_TCHAR backup
[MAXPATHLEN
+1];
490 // analyse if it was chosen the mode which will order the
494 ACE_TCHAR to_backup
[MAXPATHLEN
+1];
496 // reorder the logs starting at the oldest (the biggest
497 // number) watch if we reached max_file_number_.
499 if (fixed_number_
&& count_
> max_file_number_
)
500 // count_ will always be bigger than max_file_number_,
501 // so do nothing so to always reorder files from
503 max_num
= max_file_number_
;
507 for (int i
= max_num
; i
> 1 ;i
--)
509 ACE_OS::snprintf (backup
, MAXPATHLEN
+ 1,
513 ACE_OS::snprintf (to_backup
, MAXPATHLEN
+ 1,
518 // Remove any existing old file; ignore error as
519 // file may not exist.
520 ACE_OS::unlink (backup
);
522 // Rename the current log file to the name of the
524 ACE_OS::rename (to_backup
, backup
);
526 ACE_OS::snprintf (backup
, MAXPATHLEN
+ 1,
532 if (fixed_number_
&& count_
>max_file_number_
)
533 count_
= 1; // start over from 1
535 ACE_OS::snprintf (backup
, MAXPATHLEN
+ 1,
541 // Remove any existing old file; ignore error as file may
543 ACE_OS::unlink (backup
);
545 // Rename the current log file to the name of the backup log
547 ACE_OS::rename (this->filename_
, backup
);
550 ACELIB_ERROR ((LM_ERROR
,
551 ACE_TEXT ("Backup file name too long; ")
552 ACE_TEXT ("backup logfile not saved.\n")));
554 // Open a new log file by the same name
555 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
556 output_file
= ACE_OS::fopen (this->filename_
, ACE_TEXT ("wt"));
558 if (output_file
== 0)
561 this->log_msg_
->msg_ostream (output_file
);
563 output_file
->open (ACE_TEXT_ALWAYS_CHAR (this->filename_
),
565 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
567 // Release the lock previously acquired.
568 this->log_msg_
->release ();
575 ACE_Logging_Strategy::handle_close (ACE_HANDLE
,
578 // This will reset reactor member and cancel timer events.
584 ACE_Logging_Strategy::reactor (ACE_Reactor
*r
)
586 if (this->reactor () != r
)
588 if (this->reactor () && this->interval_
> 0 && this->max_size_
> 0)
590 this->reactor ()->cancel_timer (this);
593 ACE_Service_Object::reactor (r
);
595 if (this->reactor ())
597 this->reactor ()->schedule_timer
599 ACE_Time_Value (this->interval_
),
600 ACE_Time_Value (this->interval_
));
606 ACE_Logging_Strategy::reactor () const
608 return ACE_Service_Object::reactor ();
612 ACE_Logging_Strategy::log_msg (ACE_Log_Msg
*log_msg
)
614 this->log_msg_
= log_msg
;
617 // The following is a "Factory" used by the ACE_Service_Config and
618 // svc.conf file to dynamically initialize the state of the
621 ACE_STATIC_SVC_DEFINE (ACE_Logging_Strategy
,
622 ACE_TEXT ("Logging_Strategy"),
623 ACE_Service_Type::SERVICE_OBJECT
,
624 &ACE_SVC_NAME (ACE_Logging_Strategy
),
625 ACE_Service_Type::DELETE_THIS
| ACE_Service_Type::DELETE_OBJ
,
628 ACE_FACTORY_DEFINE (ACE
, ACE_Logging_Strategy
)
630 ACE_END_VERSIONED_NAMESPACE_DECL
632 // _get_dll_unload_policy() prevents ACE from being unloaded and having its
633 // framework components run down if/when the Logging Strategy is unloaded.
634 extern "C" ACE_Export
int
635 _get_dll_unload_policy()
637 return ACE_DLL_UNLOAD_POLICY_LAZY
;