![]() |
Icinga-core 1.4.0
next gen monitoring
|
00001 /***************************************************************************** 00002 * 00003 * LOGGING.C - Log file functions for use with Icinga 00004 * 00005 * Copyright (c) 1999-2008 Ethan Galstad (egalstad@nagios.org) 00006 * Copyright (c) 2009-2011 Nagios Core Development Team and Community Contributors 00007 * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org) 00008 * 00009 * License: 00010 * 00011 * This program is free software; you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License version 2 as 00013 * published by the Free Software Foundation. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU General Public License 00021 * along with this program; if not, write to the Free Software 00022 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00023 * 00024 *****************************************************************************/ 00025 00026 #include "../include/config.h" 00027 #include "../include/common.h" 00028 #include "../include/statusdata.h" 00029 #include "../include/macros.h" 00030 #include "../include/icinga.h" 00031 #include "../include/broker.h" 00032 00033 00034 extern char *log_file; 00035 extern char *temp_file; 00036 extern char *log_archive_path; 00037 00038 extern host *host_list; 00039 extern service *service_list; 00040 00041 extern int use_daemon_log; 00042 extern int use_syslog; 00043 extern int use_syslog_local_facility; 00044 extern int syslog_local_facility; 00045 extern int log_service_retries; 00046 extern int log_initial_states; 00047 extern int log_current_states; 00048 extern int log_long_plugin_output; 00049 00050 extern unsigned long logging_options; 00051 extern unsigned long syslog_options; 00052 00053 extern int verify_config; 00054 extern int test_scheduling; 00055 00056 extern time_t last_log_rotation; 00057 extern int log_rotation_method; 00058 00059 extern int daemon_mode; 00060 00061 extern char *debug_file; 00062 extern int debug_level; 00063 extern int debug_verbosity; 00064 extern unsigned long max_debug_file_size; 00065 FILE *debug_file_fp=NULL; 00066 00067 int dummy; /* reduce compiler warnings */ 00068 00069 static pthread_mutex_t debug_fp_lock; 00070 00071 /* 00072 * since we don't want child processes to hang indefinitely 00073 * in case they inherit a locked lock, we use soft-locking 00074 * here, which basically tries to acquire the lock for a 00075 * short while and then gives up, returning -1 to signal 00076 * the error 00077 */ 00078 static inline int soft_lock(pthread_mutex_t *lock){ 00079 int i; 00080 00081 for (i = 0; i < 5; i++) { 00082 if (!pthread_mutex_trylock(lock)) { 00083 /* success */ 00084 return 0; 00085 } 00086 00087 if (errno == EDEADLK) { 00088 /* we already have the lock */ 00089 return 0; 00090 } 00091 00092 /* sleep briefly */ 00093 usleep(30); 00094 } 00095 00096 return -1; /* we failed to get the lock. Nothing to do */ 00097 } 00098 00099 00100 /******************************************************************/ 00101 /************************ LOGGING FUNCTIONS ***********************/ 00102 /******************************************************************/ 00103 00104 /* write something to the console */ 00105 static void write_to_console(char *buffer){ 00106 /* should we print to the console? */ 00107 if(daemon_mode==FALSE) 00108 printf("%s\n",buffer); 00109 } 00110 00111 00112 /* write something to the log file, syslog, and possibly the console */ 00113 static void write_to_logs_and_console(char *buffer, unsigned long data_type, int display){ 00114 register int len=0; 00115 register int x=0; 00116 00117 /* strip unnecessary newlines */ 00118 len=strlen(buffer); 00119 for(x=len-1;x>=0;x--){ 00120 if(buffer[x]=='\n') 00121 buffer[x]='\x0'; 00122 else 00123 break; 00124 } 00125 00126 /* write messages to the logs */ 00127 write_to_all_logs(buffer,data_type); 00128 00129 /* write message to the console */ 00130 if(display==TRUE){ 00131 00132 /* don't display warnings if we're just testing scheduling */ 00133 if(test_scheduling==TRUE && data_type==NSLOG_VERIFICATION_WARNING) 00134 return; 00135 00136 write_to_console(buffer); 00137 } 00138 } 00139 00140 00141 /* The main logging function */ 00142 void logit(int data_type, int display, const char *fmt, ...){ 00143 va_list ap; 00144 char *buffer=NULL; 00145 va_start(ap,fmt); 00146 if (vasprintf(&buffer, fmt, ap) > 0) { 00147 write_to_logs_and_console(buffer,data_type,display); 00148 free(buffer); 00149 } 00150 va_end(ap); 00151 } 00152 00153 00154 /* write something to the log file and syslog facility */ 00155 int write_to_all_logs(char *buffer, unsigned long data_type){ 00156 00157 /* write to syslog */ 00158 write_to_syslog(buffer,data_type); 00159 00160 /* write to main log */ 00161 write_to_log(buffer,data_type,NULL); 00162 00163 return OK; 00164 } 00165 00166 00167 /* write something to the log file and syslog facility */ 00168 static void write_to_all_logs_with_timestamp(char *buffer, unsigned long data_type, time_t *timestamp){ 00169 00170 /* write to syslog */ 00171 write_to_syslog(buffer,data_type); 00172 00173 /* write to main log */ 00174 write_to_log(buffer,data_type,timestamp); 00175 } 00176 00177 00178 /* write something to the icinga log file */ 00179 int write_to_log(char *buffer, unsigned long data_type, time_t *timestamp){ 00180 FILE *fp=NULL; 00181 time_t log_time=0L; 00182 00183 if(buffer==NULL) 00184 return ERROR; 00185 00186 /* don't log anything if we're not actually running... */ 00187 if(verify_config==TRUE || test_scheduling==TRUE) 00188 return OK; 00189 00190 /* bail out if we shouldn't write to daemon log */ 00191 if(use_daemon_log==FALSE) 00192 return OK; 00193 00194 /* make sure we can log this type of entry */ 00195 if(!(data_type & logging_options)) 00196 return OK; 00197 00198 fp=fopen(log_file,"a+"); 00199 if(fp==NULL){ 00200 if(daemon_mode==FALSE) 00201 printf("Warning: Cannot open log file '%s' for writing\n",log_file); 00202 return ERROR; 00203 } 00204 00205 /* what timestamp should we use? */ 00206 if(timestamp==NULL) 00207 time(&log_time); 00208 else 00209 log_time=*timestamp; 00210 00211 /* strip any newlines from the end of the buffer */ 00212 strip(buffer); 00213 00214 /* write the buffer to the log file */ 00215 fprintf(fp,"[%lu] %s\n",log_time,buffer); 00216 00217 fclose(fp); 00218 00219 #ifdef USE_EVENT_BROKER 00220 /* send data to the event broker */ 00221 broker_log_data(NEBTYPE_LOG_DATA,NEBFLAG_NONE,NEBATTR_NONE,buffer,data_type,log_time,NULL); 00222 #endif 00223 00224 return OK; 00225 } 00226 00227 00228 /* write something to the syslog facility */ 00229 int write_to_syslog(char *buffer, unsigned long data_type){ 00230 00231 if(buffer==NULL) 00232 return ERROR; 00233 00234 /* don't log anything if we're not actually running... */ 00235 if(verify_config==TRUE || test_scheduling==TRUE) 00236 return OK; 00237 00238 /* bail out if we shouldn't write to syslog */ 00239 if(use_syslog==FALSE) 00240 return OK; 00241 00242 /* make sure we should log this type of entry */ 00243 if(!(data_type & syslog_options)) 00244 return OK; 00245 00246 /* write the buffer to the syslog facility */ 00247 if (use_syslog_local_facility) { 00248 switch (syslog_local_facility) { 00249 case 0: 00250 syslog(LOG_LOCAL0|LOG_INFO,"%s",buffer); 00251 return OK; 00252 case 1: 00253 syslog(LOG_LOCAL1|LOG_INFO,"%s",buffer); 00254 return OK; 00255 case 2: 00256 syslog(LOG_LOCAL2|LOG_INFO,"%s",buffer); 00257 return OK; 00258 case 3: 00259 syslog(LOG_LOCAL3|LOG_INFO,"%s",buffer); 00260 return OK; 00261 case 4: 00262 syslog(LOG_LOCAL4|LOG_INFO,"%s",buffer); 00263 return OK; 00264 case 5: 00265 syslog(LOG_LOCAL5|LOG_INFO,"%s",buffer); 00266 return OK; 00267 case 6: 00268 syslog(LOG_LOCAL6|LOG_INFO,"%s",buffer); 00269 return OK; 00270 case 7: 00271 syslog(LOG_LOCAL7|LOG_INFO,"%s",buffer); 00272 return OK; 00273 default: 00274 break; 00275 } 00276 } 00277 00278 syslog(LOG_USER|LOG_INFO,"%s",buffer); 00279 00280 return OK; 00281 } 00282 00283 00284 /* write a service problem/recovery to the icinga log file */ 00285 int log_service_event(service *svc){ 00286 char *temp_buffer=NULL; 00287 char *processed_buffer=NULL; 00288 unsigned long log_options=0L; 00289 host *temp_host=NULL; 00290 icinga_macros mac; 00291 00292 /* don't log soft errors if the user doesn't want to */ 00293 if(svc->state_type==SOFT_STATE && !log_service_retries) 00294 return OK; 00295 00296 /* get the log options */ 00297 if(svc->current_state==STATE_UNKNOWN) 00298 log_options=NSLOG_SERVICE_UNKNOWN; 00299 else if(svc->current_state==STATE_WARNING) 00300 log_options=NSLOG_SERVICE_WARNING; 00301 else if(svc->current_state==STATE_CRITICAL) 00302 log_options=NSLOG_SERVICE_CRITICAL; 00303 else 00304 log_options=NSLOG_SERVICE_OK; 00305 00306 /* find the associated host */ 00307 if((temp_host=svc->host_ptr)==NULL) 00308 return ERROR; 00309 00310 /* grab service macros */ 00311 memset(&mac, 0, sizeof(mac)); 00312 grab_host_macros_r(&mac, temp_host); 00313 grab_service_macros_r(&mac, svc); 00314 00315 /* XXX: replace the macro madness with some simple helpers instead */ 00316 /* either log only the output, or if enabled, add long_output */ 00317 if(log_long_plugin_output==TRUE && svc->long_plugin_output!=NULL) { 00318 dummy=asprintf(&temp_buffer,"SERVICE ALERT: %s;%s;$SERVICESTATE$;$SERVICESTATETYPE$;$SERVICEATTEMPT$;%s\\n%s\n",svc->host_name,svc->description,(svc->plugin_output==NULL)?"":svc->plugin_output,svc->long_plugin_output); 00319 } else { 00320 dummy=asprintf(&temp_buffer,"SERVICE ALERT: %s;%s;$SERVICESTATE$;$SERVICESTATETYPE$;$SERVICEATTEMPT$;%s\n",svc->host_name,svc->description,(svc->plugin_output==NULL)?"":svc->plugin_output); 00321 } 00322 00323 process_macros_r(&mac, temp_buffer,&processed_buffer,0); 00324 clear_host_macros_r(&mac); 00325 clear_service_macros_r(&mac); 00326 00327 write_to_all_logs(processed_buffer,log_options); 00328 00329 my_free(temp_buffer); 00330 my_free(processed_buffer); 00331 00332 return OK; 00333 } 00334 00335 00336 /* write a host problem/recovery to the log file */ 00337 int log_host_event(host *hst){ 00338 char *temp_buffer=NULL; 00339 char *processed_buffer=NULL; 00340 unsigned long log_options=0L; 00341 icinga_macros mac; 00342 00343 /* grab the host macros */ 00344 memset(&mac, 0, sizeof(mac)); 00345 grab_host_macros_r(&mac, hst); 00346 00347 /* get the log options */ 00348 if(hst->current_state==HOST_DOWN) 00349 log_options=NSLOG_HOST_DOWN; 00350 else if(hst->current_state==HOST_UNREACHABLE) 00351 log_options=NSLOG_HOST_UNREACHABLE; 00352 else 00353 log_options=NSLOG_HOST_UP; 00354 00355 /* XXX: replace the macro madness with some simple helpers instead */ 00356 /* either log only the output, or if enabled, add long_output */ 00357 if(log_long_plugin_output==TRUE && hst->long_plugin_output!=NULL) { 00358 dummy=asprintf(&temp_buffer,"HOST ALERT: %s;$HOSTSTATE$;$HOSTSTATETYPE$;$HOSTATTEMPT$;%s\\n%s\n",hst->name,(hst->plugin_output==NULL)?"":hst->plugin_output,hst->long_plugin_output); 00359 } else { 00360 dummy=asprintf(&temp_buffer,"HOST ALERT: %s;$HOSTSTATE$;$HOSTSTATETYPE$;$HOSTATTEMPT$;%s\n",hst->name,(hst->plugin_output==NULL)?"":hst->plugin_output); 00361 } 00362 00363 process_macros_r(&mac, temp_buffer,&processed_buffer,0); 00364 00365 write_to_all_logs(processed_buffer,log_options); 00366 00367 clear_host_macros_r(&mac); 00368 my_free(temp_buffer); 00369 my_free(processed_buffer); 00370 00371 return OK; 00372 } 00373 00374 00375 /* logs host states */ 00376 int log_host_states(int type, time_t *timestamp){ 00377 char *temp_buffer=NULL; 00378 char *processed_buffer=NULL; 00379 host *temp_host=NULL; 00380 icinga_macros mac; 00381 00382 /* bail if we shouldn't be logging initial states */ 00383 if(type==INITIAL_STATES && log_initial_states==FALSE) 00384 return OK; 00385 00386 memset(&mac, 0, sizeof(mac)); 00387 00388 for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){ 00389 00390 /* grab the host macros */ 00391 grab_host_macros_r(&mac, temp_host); 00392 00393 dummy=asprintf(&temp_buffer,"%s HOST STATE: %s;$HOSTSTATE$;$HOSTSTATETYPE$;$HOSTATTEMPT$;%s\n",(type==INITIAL_STATES)?"INITIAL":"CURRENT",temp_host->name,(temp_host->plugin_output==NULL)?"":temp_host->plugin_output); 00394 process_macros_r(&mac, temp_buffer,&processed_buffer,0); 00395 00396 write_to_all_logs_with_timestamp(processed_buffer,NSLOG_INFO_MESSAGE,timestamp); 00397 00398 clear_host_macros_r(&mac); 00399 00400 my_free(temp_buffer); 00401 my_free(processed_buffer); 00402 } 00403 00404 return OK; 00405 } 00406 00407 00408 /* logs service states */ 00409 int log_service_states(int type, time_t *timestamp){ 00410 char *temp_buffer=NULL; 00411 char *processed_buffer=NULL; 00412 service *temp_service=NULL; 00413 host *temp_host=NULL; 00414 icinga_macros mac; 00415 00416 /* bail if we shouldn't be logging initial states */ 00417 if(type==INITIAL_STATES && log_initial_states==FALSE) 00418 return OK; 00419 00420 memset(&mac, 0, sizeof(mac)); 00421 00422 for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){ 00423 00424 /* find the associated host */ 00425 if((temp_host=temp_service->host_ptr)==NULL) 00426 continue; 00427 00428 /* grab service macros */ 00429 grab_host_macros_r(&mac, temp_host); 00430 grab_service_macros_r(&mac, temp_service); 00431 00432 /* XXX: macro madness */ 00433 dummy=asprintf(&temp_buffer,"%s SERVICE STATE: %s;%s;$SERVICESTATE$;$SERVICESTATETYPE$;$SERVICEATTEMPT$;%s\n",(type==INITIAL_STATES)?"INITIAL":"CURRENT",temp_service->host_name,temp_service->description,temp_service->plugin_output); 00434 process_macros_r(&mac, temp_buffer,&processed_buffer,0); 00435 00436 write_to_all_logs_with_timestamp(processed_buffer,NSLOG_INFO_MESSAGE,timestamp); 00437 00438 clear_host_macros_r(&mac); 00439 clear_service_macros_r(&mac); 00440 00441 my_free(temp_buffer); 00442 my_free(processed_buffer); 00443 } 00444 00445 return OK; 00446 } 00447 00448 00449 /* rotates the main log file */ 00450 int rotate_log_file(time_t rotation_time){ 00451 char *temp_buffer=NULL; 00452 char method_string[16]=""; 00453 char *log_archive=NULL; 00454 struct tm *t, tm_s; 00455 int rename_result=0; 00456 int stat_result=-1; 00457 struct stat log_file_stat; 00458 00459 if(log_rotation_method==LOG_ROTATION_NONE){ 00460 return OK; 00461 } 00462 else if(log_rotation_method==LOG_ROTATION_HOURLY) 00463 strcpy(method_string,"HOURLY"); 00464 else if(log_rotation_method==LOG_ROTATION_DAILY) 00465 strcpy(method_string,"DAILY"); 00466 else if(log_rotation_method==LOG_ROTATION_WEEKLY) 00467 strcpy(method_string,"WEEKLY"); 00468 else if(log_rotation_method==LOG_ROTATION_MONTHLY) 00469 strcpy(method_string,"MONTHLY"); 00470 else 00471 return ERROR; 00472 00473 /* update the last log rotation time and status log */ 00474 last_log_rotation=time(NULL); 00475 update_program_status(FALSE); 00476 00477 t = localtime_r(&rotation_time, &tm_s); 00478 00479 stat_result = stat(log_file, &log_file_stat); 00480 00481 /* get the archived filename to use */ 00482 dummy=asprintf(&log_archive,"%s%sicinga-%02d-%02d-%d-%02d.log", log_archive_path, (log_archive_path[strlen(log_archive_path)-1]=='/')?"":"/", t->tm_mon+1, t->tm_mday, t->tm_year+1900, t->tm_hour); 00483 00484 /* rotate the log file */ 00485 rename_result=my_rename(log_file,log_archive); 00486 00487 if(rename_result){ 00488 my_free(log_archive); 00489 return ERROR; 00490 } 00491 00492 /* record the log rotation after it has been done... */ 00493 dummy=asprintf(&temp_buffer,"LOG ROTATION: %s\n",method_string); 00494 write_to_all_logs_with_timestamp(temp_buffer,NSLOG_PROCESS_INFO,&rotation_time); 00495 my_free(temp_buffer); 00496 00497 /* record log file version format */ 00498 write_log_file_info(&rotation_time); 00499 00500 if(stat_result==0){ 00501 chmod(log_file, log_file_stat.st_mode); 00502 dummy=chown(log_file, log_file_stat.st_uid, log_file_stat.st_gid); 00503 } 00504 00505 /* log current host and service state if activated*/ 00506 if(log_current_states==TRUE) { 00507 log_host_states(CURRENT_STATES,&rotation_time); 00508 log_service_states(CURRENT_STATES,&rotation_time); 00509 } 00510 00511 /* free memory */ 00512 my_free(log_archive); 00513 00514 return OK; 00515 } 00516 00517 00518 /* record log file version/info */ 00519 int write_log_file_info(time_t *timestamp){ 00520 char *temp_buffer=NULL; 00521 00522 /* write log version */ 00523 dummy=asprintf(&temp_buffer,"LOG VERSION: %s\n",LOG_VERSION_2); 00524 write_to_all_logs_with_timestamp(temp_buffer,NSLOG_PROCESS_INFO,timestamp); 00525 my_free(temp_buffer); 00526 00527 return OK; 00528 } 00529 00530 00531 /* opens the debug log for writing */ 00532 int open_debug_log(void){ 00533 00534 /* don't do anything if we're not actually running... */ 00535 if(verify_config==TRUE || test_scheduling==TRUE) 00536 return OK; 00537 00538 /* don't do anything if we're not debugging */ 00539 if(debug_level==DEBUGL_NONE) 00540 return OK; 00541 00542 if((debug_file_fp=fopen(debug_file,"a+"))==NULL) 00543 return ERROR; 00544 00545 return OK; 00546 } 00547 00548 00549 /* closes the debug log */ 00550 int close_debug_log(void){ 00551 00552 if(debug_file_fp!=NULL) 00553 fclose(debug_file_fp); 00554 00555 debug_file_fp=NULL; 00556 00557 return OK; 00558 } 00559 00560 00561 /* write to the debug log */ 00562 int log_debug_info(int level, int verbosity, const char *fmt, ...){ 00563 va_list ap; 00564 char *temp_path=NULL; 00565 struct timeval current_time; 00566 00567 if(!(debug_level==DEBUGL_ALL || (level & debug_level))) 00568 return OK; 00569 00570 if(verbosity>debug_verbosity) 00571 return OK; 00572 00573 if(debug_file_fp==NULL) 00574 return ERROR; 00575 00576 /* 00577 * lock it so concurrent threads don't stomp on each other's 00578 * writings. We maintain the lock until we've (optionally) 00579 * renamed the file. 00580 * If soft_lock() fails we return early. 00581 */ 00582 if (soft_lock(&debug_fp_lock) < 0) 00583 return ERROR; 00584 00585 /* write the timestamp */ 00586 gettimeofday(¤t_time,NULL); 00587 fprintf(debug_file_fp,"[%lu.%06lu] [%03d.%d] [pid=%lu] ",current_time.tv_sec,current_time.tv_usec,level,verbosity,(unsigned long)getpid()); 00588 00589 /* write the data */ 00590 va_start(ap,fmt); 00591 vfprintf(debug_file_fp,fmt,ap); 00592 va_end(ap); 00593 00594 /* flush, so we don't have problems tailing or when fork()ing */ 00595 fflush(debug_file_fp); 00596 00597 /* if file has grown beyond max, rotate it */ 00598 if((unsigned long)ftell(debug_file_fp)>max_debug_file_size && max_debug_file_size>0L){ 00599 00600 /* close the file */ 00601 close_debug_log(); 00602 00603 /* rotate the log file */ 00604 dummy=asprintf(&temp_path,"%s.old",debug_file); 00605 if(temp_path){ 00606 00607 /* unlink the old debug file */ 00608 unlink(temp_path); 00609 00610 /* rotate the debug file */ 00611 my_rename(debug_file,temp_path); 00612 00613 /* free memory */ 00614 my_free(temp_path); 00615 } 00616 00617 /* open a new file */ 00618 open_debug_log(); 00619 } 00620 00621 pthread_mutex_unlock(&debug_fp_lock); 00622 00623 return OK; 00624 } 00625