Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

msgLog.c

Go to the documentation of this file.
00001 /* msgLog.c - MINOS DAQ syslog functionality */
00002 
00003 /* 
00004  * Tim Nicholls, Real Time Systems Group
00005  * CLRC Rutherford Appleton Laboratory
00006  */
00007 
00008 /*
00009  * Current CVS Tag: 
00010  * $Header: /cvs/minoscvs/rep1/minossoft/OnlineUtil/msgLogLib/msgLog.c,v 1.3 2005/12/15 23:07:22 rhatcher Exp $ 
00011  */
00012 
00013 /*
00014  * Modification History : DO NOT EDIT - MAINTAINED BY CVS 
00015  * $Log: msgLog.c,v $
00016  * Revision 1.3  2005/12/15 23:07:22  rhatcher
00017  * synch to fix I suggested to Caius on 2005-10-15 (and then had to rediscover).
00018  * This FPE in the initial stage confuses gdb (version 6.1 and earilier)
00019  * to no end.  Of course, I forgot to make same commit at that time so
00020  * I had to rediscover (painfully hard) this fix.
00021  *
00022  * Revision 1.2  2005/09/06 19:06:49  rhatcher
00023  * Synch with online CVS repository as of 2005-08-25.  This includes fixes
00024  * for const correctness on char* format strings.  Alas, it now uses
00025  * clock_gettime() rather than gettimeofday() -- this exists on Linux,
00026  * but doesn't for MacOSX, but does require linkage to -lrt library.
00027  *
00028  * Revision 1.15  2005/08/25 17:37:24  howcroft
00029  * Added a function that allows a process to set its own max message repeat rate
00030  *
00031  * Revision 1.14  2005/08/25 17:20:43  howcroft
00032  * VxWorks and Linux now share code for time based message rate limiting. replaced the linux calls to gettimeofday with clock_getttime.
00033  *
00034  * Also, change char pointers to const pointers for format args.
00035  *
00036  * Revision 1.13  2005/08/15 20:22:26  howcroft
00037  * Wrap the repeated message timeouts in ifndef Vxworks statements, so it should still compile under vxworks
00038  *
00039  * Revision 1.12  2005/08/15 20:02:03  howcroft
00040  * use the macro MSG_USERPT to switch on and off the writing of the "last message sent N times".  If this macro is defined then this message is used, if not then the actual message is sent instead.
00041  *
00042  * Revision 1.11  2005/08/15 19:32:28  howcroft
00043  * Added new feature: timeouts on repeated message buffering.  A repeated messsage is now resent if:
00044  *
00045  * number of repeats>=MAX_RPTMSG_BUFFER (currently set to 1e6)
00046  *
00047  * OR
00048  *
00049  * time since last send > MAX_DTMSG_BUFFER (currently set to 0.5s)
00050  *
00051  * Revision 1.10  2005/05/03 10:12:38  tcn
00052  * Added function msgLogPidSet
00053  *
00054  * Revision 1.9  2003/11/06 11:17:09  howcroft
00055  * hacked so one can step back to syslog with USESYSLOG macro
00056  *
00057  * Revision 1.8  2003/10/24 13:34:53  howcroft
00058  * Bug fix, typo
00059  *
00060  * Revision 1.7  2003/10/24 13:30:22  howcroft
00061  *
00062  * MsgLogLib:
00063  * o Messages go via UDP to runControl directly rather than via syslog.
00064  * o Include a header with infomation about node Id, and message counter, we can now tell when messages are dropped.
00065  *
00066  * o msgLogger.c builds a little binary to act like the logger script.
00067  * o msgRead, a library to extract the messages from the UDP socket and fill a common struct defined in msgCommon.h
00068  *
00069  * Revision 1.6  2002/08/07 07:48:40  tcn
00070  * Added printf to Vxworks version of logMessage function, so messages also go to
00071  * console.
00072  *
00073  * Revision 1.5  2002/03/01 11:19:01  tcn
00074  * Implemented new debug message scheme with specifiable debug level and
00075  * and reporting threshold.
00076  *
00077  * Revision 1.4  2001/09/05 14:41:44  tcn
00078  * Forgot to include string.h
00079  *
00080  * Revision 1.3  2001/08/16 12:13:21  tcn
00081  * Added logNotice call, msgLogInit to (optionally) call openlog, message
00082  * priority code prepending for Linux and VxWorks
00083  *
00084  * Revision 1.2  2001/06/18 10:52:54  tcn
00085  * Implemented multi-level message logging. Now also works under VxWorks with the
00086  * -DVxWorks flag.
00087  *
00088  * Revision 1.1  2001/04/05 13:35:18  tcn
00089  * First commit of msgogLib
00090  *
00091  *
00092  */
00093 
00094  /*
00095 DESCRIPTION
00096 This module provides message logging functionality, routed either
00097 via syslog or (for VxWorks) via logMsg.
00098 
00099 The meaning of the levels for use in the MINOS DAQ is defined this:
00100 
00101    logCritical : Critical condition - system level problem (power, temp, etc.)
00102    logError    : Error condition - problem with DAQ, stopping readout
00103    logWarning  : Warning condition - problem with DAQ but can continue
00104    logNotice   : Normal condition, e.g. state transition by RC, LI sequence, 
00105                  executes complete
00106    logInfo     : Informational messages, e.g. component state changes
00107    logDebug    : Debug messages, e.g. TF xfer parameters
00108 
00109 logDebug has an additional argument, which specifies a debug level. A settable
00110 threshold, accessed by logDebugLevelSet, controls what debug levels are written
00111 as messages.
00112 
00113 INCLUDE FILES: msgLog.h, OsExtras.h
00114 */
00115 
00116 /* includes */
00117 #include <stdio.h>
00118 #include <stdarg.h>
00119 #include <string.h>
00120 #include <time.h>
00121 
00122 #ifdef VxWorks
00123 #include <bootLib.h>
00124 #include <logLib.h>
00125 #include <socket.h>
00126 #include <sockLib.h>
00127 #include <stdLib.h>
00128 #include <sysLib.h>
00129 #include <in.h>
00130 #include <ioLib.h>
00131 #include <msgQLib.h>
00132 #else
00133 #include <stdlib.h>
00134 #include <syslog.h>
00135 #include <sys/types.h>
00136 #include <sys/socket.h>
00137 #include <netinet/in.h>
00138 #include <arpa/inet.h>
00139 #include <sys/time.h>
00140 #include <errno.h>
00141 #include <unistd.h>
00142 #include <netdb.h>
00143 #endif
00144 
00145 #include "minosDaq.h"
00146 #include "msgLog.h"
00147 #include "msgCommon.h"
00148 
00149 #ifndef CLOCK_REALTIME
00150 #include "fake_clock_gettime.h"
00151 #endif
00152 
00153 /* defines */
00154 #ifdef VxWorks
00155 #define BOOT_LINE_SIZE 255
00156 #define TASK_SIZE_MSGLOGGER 2000
00157 #define TASK_PRIORITY_MSGLOGGER 1
00158 #define MSGQ_MAX_MSGS  100
00159 #define ENDIAN_SWAP_LONG(w) ( ((w&0xff)<<24) | ((w&0xff00)<<8) | ((w&0xff0000)>>8) | ((w&0xff000000)>>24) )
00160 #define ENDIAN_SWAP_SHORT(w) ( ((w&0xff)<<8) | ((w&0xff00)>>8) )
00161 #define NATIVE_MSG(args...) printf(## args)
00162 #else
00163 #define NATIVE_MSG(args...) syslog(DAQ_LOG_FACILITY|LOG_ERR, ## args)
00164 #endif
00165 
00166 /* typedefs */
00167 
00168 
00169 /* globals */
00170 
00171 
00172 /* locals */
00173 static unsigned int lDebugLevel = 0;
00174 static long  lMaxRptDt = MAX_DTMSG_BUFFER;
00175 
00176 #ifdef USESYSLOG
00177 static mdMsgLogBuffer lBuffer;
00178 #else
00179 #ifdef VxWorks
00180 static MSG_Q_ID lMsgLogQId = NULL;
00181 static int lMsgLogTaskId   = NULL;
00182 #endif
00183 static int lSocket = 0;
00184 static struct sockaddr_in lServerAddr;
00185 static mdMsgLogBuffer lBuffer;
00186 static int lMsgLocalEcho = 0;
00187 #endif
00188 static const char logTag[]= "EACEWNID";
00189 
00190 static struct timespec lastMessageTime; //time the last message was sent
00191 
00192 /* forward declarations */
00193 void logMessage(int priority, const char *fmt, va_list args);
00194 #ifdef USESYSLOG
00195 #else
00196 #ifdef VxWorks
00197 STATUS tMsgLogger(void);
00198 #endif
00199 static void msgSend(int priority);
00200 #endif
00201 
00202 
00203 
00204 /********************************************************************
00205 * =v=>
00206 * msgLogInit - initialise message logging
00207 *
00208 * This function can be called OPTIONALLY to initialise the message
00209 * logging. On VxWorks it does nothing, on systems with a syslog
00210 * implementation it calls openlog, which allows the program identity
00211 * and various syslog options to be set. Calling this function has the 
00212 * effect of printing syslog messages to STDERR in addition, and shows 
00213 * the PID in each message. 
00214 *
00215 * RETURNS: void
00216 * ===<
00217 * =i=> */
00218 void msgLogInit
00219 (
00220     const char *ident  /* process identifier (name) */
00221 )
00222 {
00223 
00224 #ifdef USESYSLOG
00225 #ifdef VxWorks    
00226     /* Do nothing */
00227 #else /* !VxWorks */
00228     openlog(ident, LOG_PERROR | LOG_PID, DAQ_LOG_FACILITY);
00229 #endif /* VxWorks */
00230 
00231 #else /* !USESYSLOG */
00232 
00233   const char* ip;
00234   const char* portenv;
00235   int port;
00236   int sockAddrSize;
00237   int pid;
00238 
00239   /*set last message time to 01/01/70
00240    * this way first message is always sent */
00241   lastMessageTime.tv_sec = 0; 
00242   lastMessageTime.tv_nsec = 0;
00243 
00244   sockAddrSize = sizeof(struct sockaddr_in);
00245 
00246   /* Clear socket address structure */
00247   bzero((char *)&lServerAddr, sockAddrSize);
00248 
00249   /* 
00250    * For VxWorks we pull the message server IP address directly from
00251    * the boot parameters. Otherwise, the server name/IP is resolved from
00252    * environment variables or falls back to the local host 
00253    */
00254 #ifdef VxWorks
00255   {
00256       char bootString[BOOT_LINE_SIZE];
00257       BOOT_PARAMS bootParams;
00258 
00259       /* 
00260        * Get the msgLogger IP adddress from the "other" field of the boot
00261        * parameters
00262        */
00263       sysNvRamGet(bootString, BOOT_LINE_SIZE, 0);
00264       bootStringToStruct(bootString, &bootParams);
00265       ip = (char *)&(bootParams.other);
00266       port = MSGLOG_PORT;
00267 
00268       if ((lServerAddr.sin_addr.s_addr = inet_addr(ip)) == ERROR) {
00269           NATIVE_MSG("msgLogInit: bad server name from boot params: %s", ip);
00270           return;
00271       }
00272       pid = taskIdSelf();
00273 
00274       /* Clean up any existing msgLogger task and message queue */
00275       if (lMsgLogTaskId != NULL) {
00276           NATIVE_MSG("msgLogInit: deleting existing message logger task (tid=0x%x)\n", lMsgLogTaskId);
00277           taskDelete(lMsgLogTaskId);
00278           lMsgLogTaskId = NULL;
00279       }
00280       if (lMsgLogQId != NULL) {
00281           NATIVE_MSG("msgLogInit: deleting existing message logger queue (id=0x%x)\n", lMsgLogQId);
00282           msgQDelete(lMsgLogQId);
00283           lMsgLogQId = NULL;
00284       }
00285 
00286       /* Create the message queue for the logging task */
00287       lMsgLogQId = msgQCreate(MSGQ_MAX_MSGS, sizeof(mdMsgLogBuffer), MSG_Q_FIFO);
00288       if (lMsgLogQId == NULL) {
00289           NATIVE_MSG("msgLogInit: msgQCreate failed: %s", strerror(errno));
00290           return;
00291       }
00292       /* Spawn the message logging task */
00293       lMsgLogTaskId = taskSpawn("tMsgLogger", TASK_PRIORITY_MSGLOGGER, 0, 
00294                                 TASK_SIZE_MSGLOGGER, (FUNCPTR)tMsgLogger,
00295                                 0,0,0,0,0,0,0,0,0,0);
00296       if (lMsgLogTaskId == ERROR) {
00297           NATIVE_MSG("msgLogInit: task creation failed: %s", strerror(errno));
00298           return;
00299       }
00300   }
00301 #else /* !Vxworks */
00302   {
00303       struct hostent     *host_ptr; /*the host add*/
00304 
00305       /* 
00306        * Pull the msg logger IP address and port from env vars, otherwise
00307        * take the default values
00308        */      
00309       ip = getenv(DAQ_MSG_IP);
00310       if (ip == NULL) {
00311           ip = MSGLOG_DEFAULT_IP;
00312       }
00313       portenv = getenv("DAQ_MSG_PORT");
00314       if ( portenv == NULL){
00315           port = MSGLOG_PORT;
00316       } else {
00317           sscanf(portenv, "%d", &port);
00318       }
00319   
00320       /* Resolve server hostname to address */
00321       host_ptr = gethostbyname(ip);
00322       if(!host_ptr ||host_ptr->h_addrtype != AF_INET ){
00323           NATIVE_MSG( "msgLogInit: bad server name/address: %s , %s",ip, strerror(errno));
00324           return;
00325       }
00326       memcpy(&lServerAddr.sin_addr.s_addr, host_ptr->h_addr, host_ptr->h_length);
00327       if(lServerAddr.sin_addr.s_addr == INADDR_NONE)
00328         {
00329           NATIVE_MSG( "msgLogInit: unresolved server address, unable to open msgLog socket\n");
00330           return;
00331         }
00332 
00333       /* Get current process ID */ 
00334       pid = getpid();
00335   
00336       /* Open syslog connection for fallback (native) messages */
00337       openlog(ident, LOG_PERROR | LOG_PID, DAQ_LOG_FACILITY);
00338   }
00339 #endif /* VxWorks */
00340 
00341   /* Fill in port and type in socket address structure */
00342   /* lServerAddr.sin_len    = (unsigned char)sockAddrSize; */
00343   lServerAddr.sin_family = AF_INET;
00344   lServerAddr.sin_port   = htons(port);
00345 
00346   /* Close the old socket if it exists */
00347   if (lSocket != 0) {
00348     NATIVE_MSG("msgLogInit: closing existing message logger socket (id=0x%x)\n", lSocket);
00349     close(lSocket);
00350     lSocket = 0;
00351   }
00352 
00353   /* Create the UDP datagram socket */
00354   lSocket = socket(AF_INET, SOCK_DGRAM, 0);
00355   if(lSocket == -1) {
00356       NATIVE_MSG("msgLogInit: socket() failed: %s", strerror(errno));
00357       return;
00358   }
00359     
00360   /* Initialise message header */
00361   lBuffer.hdr.pid = pid;
00362   lBuffer.hdr.count = 0;
00363   lBuffer.hdr.nodeFrom = MINOS_UNIDENTIFIED_CLIENT;
00364   strncpy(lBuffer.hdr.prcName, ident, MSGLOG_MAXNAME);
00365 
00366   /* Set local message echoing off by default */
00367   lMsgLocalEcho = 0;
00368 
00369 #endif /* USESYSLOG */
00370   
00371   /* Set default debug level to zero */
00372   lDebugLevel = 0;
00373 
00374   return;
00375 
00376 } /* msgLogInit */
00377 
00378 
00379 /********************************************************************
00380 *
00381 * msgLogCleanup - clean up the message logger
00382 *
00383 * This function cleans up the message logger, closing the socket and
00384 * deleting the (VxWorks) logging task and message queue as necessary.
00385 *
00386 * RETURNS: none
00387 *
00388 */
00389 void msgLogCleanup(void)
00390 {
00391 
00392 #ifdef VxWorks
00393     /* Clean up any existing msgLogger task and message queue */
00394     if (lMsgLogTaskId != NULL) {
00395         taskDelete(lMsgLogTaskId);
00396         lMsgLogTaskId = NULL;
00397     }
00398     if (lMsgLogQId != NULL) {
00399         msgQDelete(lMsgLogQId);
00400         lMsgLogQId = NULL;
00401     }
00402 #endif
00403 
00404 #ifndef USESYSLOG
00405     /* Close the UDP socket if it is open */
00406     if (lSocket != 0) {
00407       close(lSocket);
00408       lSocket = 0;
00409     }
00410 #endif
00411 
00412 } /* msgLogCleanup */
00413 
00414 /********************************************************************
00415 * =v=>
00416 * msgLogNodeIdSet - set node ID for message logging
00417 * 
00418 * Sets the node id use in the message header for UDP messaging to 
00419 * rcServer. This ID should be the appropriate entry from the
00420 * MinosEntity enumeration in minosDaq.h 
00421 * Only has meaning when conpiled without USESYSLOG.
00422 * 
00423 * RETURNS: None
00424 * ===<
00425 * =i=> */
00426 void msgLogNodeIdSet
00427 (
00428     long nodeId  /* node ID to be set */
00429 )
00430 {
00431 #ifdef USESYSLOG
00432   
00433 #else   
00434   lBuffer.hdr.nodeFrom = nodeId;
00435 #endif
00436   return;
00437 
00438 } /* msgLoNodeIdSet */
00439 
00440 /********************************************************************
00441 * =v=>
00442 * msgLogPidSet - set process ID for message logging
00443 * 
00444 * Sets the process ID to  use in the message header for UDP messaging to 
00445 * rcServer. 
00446 * 
00447 * RETURNS: None
00448 * ===<
00449 * =i=> */
00450 void msgLogPidSet
00451 (
00452     long pid  /* node ID to be set */
00453 )
00454 {
00455 #ifdef USESYSLOG
00456   
00457 #else   
00458   lBuffer.hdr.pid = pid;
00459 #endif
00460   return;
00461 
00462 } /* msgLogPidSet */
00463 
00464 /********************************************************************
00465 * =v=>
00466 * msgLogLocalEchoSet - set/clear local echoing of messages
00467 * 
00468 * This function will enable/disable the echoing of messages locally
00469 * (e.g. to stderr). Only has meaning when conpiled without USESYSLOG.
00470 * 
00471 * RETURNS: None
00472 * ===<
00473 * =i=> */
00474 void msgLogLocalEchoSet
00475 (
00476     int enable /* enable 1 = on, 0 = off */
00477 )
00478 {
00479 #ifdef USESYSLOG
00480   
00481 #else   
00482   lMsgLocalEcho = enable;
00483 #endif
00484   return;
00485 
00486 } /* msgLogLocalEchoSet */
00487 
00488 /********************************************************************
00489 * =v=>
00490 * logMaxRepRateSet - set max message repeat rate
00491 *
00492 * Sets the max time (in nano-secs) that identical messages are buffered. Setting to zero switches off bufferiing. 
00493 *
00494 * RETURNS: None
00495 * ===<
00496 * =i=> */
00497 void logMaxRepRateSet
00498 (
00499  long max_dt_ns
00500 )
00501 {
00502   lMaxRptDt = max_dt_ns;
00503 }
00504 
00505 /********************************************************************
00506 * =v=>
00507 * logDebugLevelSet - set debug log level
00508 *
00509 * This function sets the debug log level, which is used as a 
00510 * threshold for debugging. A value of zero turns off all debug level
00511 * messages. It is up to the user to determine how many levels of
00512 * debugging are available, but the number must always be positive.
00513 *
00514 * RETURNS: None
00515 * ===<
00516 * =i=> */
00517 void logDebugLevelSet
00518 (
00519    unsigned int level
00520 )
00521 {
00522 
00523    lDebugLevel = level;
00524 
00525 } /* logDebugLevelSet */
00526 
00527 
00528 /********************************************************************
00529 * =v=>
00530 *  msgLogResetMsgCount
00531 *
00532 * Resets the count of a message
00533 *
00534 * RETURNS: None
00535 * ===<
00536 * =i=> */
00537 void  msgLogResetMsgCount(long count)
00538 {
00539 #ifndef USESYSLOG
00540 #ifndef VxWorks
00541   lBuffer.hdr.count = count;
00542 #endif
00543 #endif
00544 } /*  msgLogResetMsgCount */
00545 
00546 long  msgLogGetMsgCount()
00547 {
00548 #ifndef USESYSLOG
00549 #ifndef VxWorks
00550   return (lBuffer.hdr.count);
00551 #endif
00552 #else
00553   return -1;
00554 #endif
00555 } /*  msgLogResetMsgCount */
00556 
00557 
00558 
00559 
00560 /********************************************************************
00561 * =v=>
00562 * logCritical - send an critical message to the message logger
00563 *
00564 * This function parses a variable argument list and sends an message
00565 * with LOG_CRIT level to the message logger
00566 *
00567 * RETURNS: void
00568 * ===<
00569 * =i=> */
00570 
00571 void logCritical(const char *fmt, ...) {
00572 
00573     va_list args;
00574     va_start(args, fmt);
00575     logMessage(LOG_CRIT, fmt, args);
00576     va_end(args);
00577 
00578 } /* logCritical */
00579 
00580 /********************************************************************
00581 * =v=>
00582 * logError - send an error message to the message logger
00583 *
00584 * This function parses a variable argument list and sends an message
00585 * with LOG_ERR level to the message logger
00586 *
00587 * RETURNS: void
00588 * ===<
00589 * =i=> */
00590 void logError(const char *fmt, ...) {
00591     
00592     va_list args;
00593     va_start(args, fmt);
00594     logMessage(LOG_ERR, fmt, args);    
00595     va_end(args);
00596 
00597 } /* logError */
00598 
00599 /********************************************************************
00600 * =v=>
00601 * logWarn - send an warning message to the message logger
00602 *
00603 * This function parses a variable argument list and sends an message
00604 * with LOG_WARNING level to the message logger
00605 *
00606 * RETURNS: void
00607 * ===<
00608 * =i=> */
00609 void logWarn(const char *fmt, ...) {
00610 
00611     va_list args;
00612     va_start(args, fmt);
00613     logMessage(LOG_WARNING, fmt, args);
00614     va_end(args);
00615 
00616 } /* logWarn */
00617 
00618 /********************************************************************
00619 * =v=>
00620 * logNotice - send a notice message to the message logger
00621 *
00622 * This function parses a variable argument list and sends an message
00623 * with LOG_NOTICE level to the message logger
00624 *
00625 * RETURNS: void
00626 * ===<
00627 * =i=> */
00628 void logNotice(const char *fmt, ...) {
00629 
00630     va_list args;
00631     va_start(args, fmt);
00632     logMessage(LOG_NOTICE, fmt, args);
00633     va_end(args);
00634 
00635 } /* logNotice */
00636 
00637 /********************************************************************
00638 * =v=>
00639 * logInfo - send an info message to the message logger
00640 *
00641 * This function parses a variable argument list and sends an message
00642 * with LOG_INFO level to the message logger
00643 *
00644 * RETURNS: void
00645 * ===<
00646 * =i=> */
00647 void logInfo(const char *fmt, ...) {
00648 
00649     va_list args;
00650     va_start(args, fmt);
00651     logMessage(LOG_INFO, fmt, args);
00652     va_end(args);
00653 
00654 } /* logInfo */
00655 
00656 
00657 /********************************************************************
00658 * =v=>
00659 * logDebug - send an debug message to the message logger
00660 *
00661 * This function parses a variable argument list and sends an message
00662 * with LOG_DEBUG level to the message logger
00663 *
00664 * RETURNS: void
00665 * ===<
00666 * =i=> */
00667 void logDebug(unsigned int level, const char *fmt, ...) {
00668 
00669     va_list args;
00670 
00671     /* 
00672      * Check requested level against threshold - values < 1 are
00673      * prohibited and reset to one to avoid situation where some
00674      * debug messages always get through.
00675      */
00676     if (level < 1) {
00677        level = 1;
00678     }
00679     if (level <= lDebugLevel) {
00680        va_start(args, fmt);
00681        logMessage(LOG_DEBUG, fmt, args);
00682        va_end(args);
00683     }
00684 
00685 } /* logDebug */
00686 
00687 /********************************************************************
00688 * =v=>
00689 * logMessage - format and send a message to the message logger
00690 *
00691 * This function parses an variable input argument list to format a
00692 * message. This is sent to the message logger with the specified
00693 * priority: logMsg under vxWorks with the priority tagged by a <x>
00694 * sequent, syslog otherwise
00695 *
00696 * RETURNS: void
00697 * ===<
00698 * =i=> */
00699 void logMessage(int priority, const char *fmt, va_list args) {
00700 
00701     int len = 0;
00702     static char lastMessage[MSGLOG_MAXMESSAGE]="";
00703     static int lastMessageCount=0;    
00704 
00705     static struct timespec thisMessageTime;
00706     clock_gettime(CLOCK_REALTIME,&thisMessageTime);
00707 
00708 
00709     /* Build message from argument list */
00710 #ifdef VxWorks
00711     vsprintf(lBuffer.message, fmt, args);
00712 #else
00713     vsnprintf(lBuffer.message, MSGLOG_MAXMESSAGE, fmt, args);
00714 #endif
00715 
00716     /* Discard any trailing new lines as we'll force one if necessary*/
00717     len = strlen(lBuffer.message);
00718     if (lBuffer.message[len-1] == '\n') lBuffer.message[len-1]=0;
00719 
00720 #ifdef USESYSLOG
00721 #ifdef VxWorks
00722     logMsg("<%c> %s\n", (int)logTag[priority], (int)lBuffer.message, 0, 0, 0, 0);
00723     printf("<%c> %s\n", logTag[priority], lBuffer.message);
00724 
00725 #else /* !VxWorks */
00726     syslog(DAQ_LOG_FACILITY | priority, "<%c> %s\n", logTag[priority], lBuffer.message);
00727 
00728 #endif /* VxWorks */
00729 #else  /* !USESYSLOG */
00730 
00731     /* Check if this is the same message as last time */
00732     len = strncmp(lastMessage, lBuffer.message, MSGLOG_MAXMESSAGE);
00733 
00734     /* Decide whether this is a repeated message and if it needs to be sent or not */
00735     long long deltat = (thisMessageTime.tv_sec-lastMessageTime.tv_sec)*1e9 +  (thisMessageTime.tv_nsec-lastMessageTime.tv_nsec);
00736 
00737     if(lastMessageCount!=0 && len==0 && lastMessageCount<MAX_RPTMSG_BUFFER && deltat<lMaxRptDt) {
00738       
00739         /* Same message - less than max counts nothing needs to be sent*/
00740         lastMessageCount++;
00741 
00742     } else{ 
00743       /* Either new message, or we've exceeded max count so send "repeated" message */
00744       if((len!=0 && lastMessageCount>1) || 
00745          (len==0 && (lastMessageCount>=MAX_RPTMSG_BUFFER || deltat>MAX_DTMSG_BUFFER) )) {
00746 #ifdef MSG_USERPT /*use the repeat message*/
00747           sprintf(lBuffer.message, "Last message repeated %d times", lastMessageCount);
00748           msgSend(LOG_INFO); 
00749 #ifdef VxWorks
00750           vsprintf(lBuffer.message, fmt, args);
00751 #else
00752           vsnprintf(lBuffer.message, MSGLOG_MAXMESSAGE, fmt, args);
00753 #endif
00754           lBuffer.hdr.priority = priority;        
00755 #else 
00756           strncpy(lastMessage, lBuffer.message, MSGLOG_MAXMESSAGE);
00757           msgSend(priority);
00758 #endif /*MSG_USERPT*/
00759       }
00760       /* New message, send it */
00761       if( len!=0 ) {
00762           strncpy(lastMessage, lBuffer.message, MSGLOG_MAXMESSAGE);
00763           msgSend(priority);      
00764       }
00765       /* Reset last message count */
00766       lastMessageTime.tv_sec = thisMessageTime.tv_sec;
00767       lastMessageTime.tv_nsec = thisMessageTime.tv_nsec;
00768       lastMessageCount=1;
00769     }
00770 
00771 #endif /* USESYSLOG */
00772 
00773     return;
00774 }
00775 
00776 #ifndef USESYSLOG
00777 /********************************************************************
00778 * =v=>
00779 * msgSend - send log message
00780 *
00781 * This function formats and sends the message to the appropriate 
00782 * location. Under VxWorks the message is passed (via a message queue)
00783 * to the message logging task. Otherwise it is sent directly via
00784 * the UDP socket which was opened by msgLogInit.
00785 *
00786 * RETURNS: none
00787 * ===<
00788 * =i=> */
00789 static void msgSend
00790 (
00791     int priority /* message priority */
00792 )
00793 {
00794 
00795   int len=0;
00796 
00797   /* Assemble the message header */
00798   lBuffer.hdr.priority = priority;
00799   lBuffer.hdr.length = strlen(lBuffer.message);
00800   lBuffer.hdr.count++;
00801   lBuffer.hdr.stime = 0;
00802 
00803   /* Complete the header OS-dependent fields then send the message */
00804 #ifdef VxWorks
00805   {
00806       struct timespec msgTime;
00807       STATUS rc;
00808       if (clock_gettime(CLOCK_REALTIME, &msgTime) == 0) {
00809           lBuffer.hdr.stime = msgTime.tv_sec;
00810       }
00811       /* VxWorks PID and name depend on current task context */
00812       lBuffer.hdr.pid   = taskIdSelf();
00813       strncpy(lBuffer.hdr.prcName, (char *)taskName(lBuffer.hdr.pid), MSGLOG_MAXNAME);
00814   
00815       /* Push message into message queue for logging task to handle */
00816       rc = msgQSend(lMsgLogQId, (char *)&lBuffer, sizeof(mdMsgLogBuffer), 
00817               NO_WAIT, MSG_PRI_NORMAL);
00818       if (rc == ERROR) {
00819           NATIVE_MSG("msgSend: msgQSend failed: %s", strerror(errno));
00820       }
00821 
00822   }
00823 #else /* !VxWorks */
00824   {
00825       struct timeval msgTime;
00826       if(gettimeofday(&msgTime, 0)==0) {
00827           lBuffer.hdr.stime = msgTime.tv_sec;
00828       }
00829       /* Send the message */  
00830       len = sendto(lSocket, (char *)&lBuffer, sizeof(mdMsgLogBuffer), MSG_DONTWAIT, 
00831                    (struct sockaddr *)&lServerAddr, sizeof(struct sockaddr_in)); 
00832       if(len < 0) {
00833           NATIVE_MSG( "msgSend: sendto() failed: %s", strerror(errno));
00834       }
00835 
00836   }
00837 #endif /* VxWorks */
00838   
00839   if (lMsgLocalEcho) {
00840       printf("%-.10s[%ld]: <%c> %-.100s\n", lBuffer.hdr.prcName, 
00841              lBuffer.hdr.pid, logTag[lBuffer.hdr.priority], lBuffer.message);  
00842   }
00843 
00844   return;
00845 }
00846 
00847 #ifdef VxWorks
00848 /********************************************************************
00849 *
00850 * tMsgLogger - message logging task
00851 *
00852 * This function implements the message logging task under VxWorks. It
00853 * simply receives messages on a message queue, byte swaps the 
00854 * numerical fields in the header and sends it to the UDP socket.
00855 *
00856 * RETURNS: OK, or ERROR if there was a problem
00857 *
00858 */
00859 STATUS tMsgLogger(void)
00860 {
00861 
00862     mdMsgLogBuffer message;
00863     int msgLen, sendLen;
00864 
00865     /* Loop forever ! */
00866     while (1) {
00867         msgLen = msgQReceive(lMsgLogQId, (char *)&message, sizeof(mdMsgLogBuffer), WAIT_FOREVER);
00868         if (msgLen == ERROR) {
00869             NATIVE_MSG("tMsgLogger: msgQReceive failed: %s", strerror(errno));
00870             return ERROR;
00871         } else if (msgLen != sizeof(mdMsgLogBuffer)) {
00872             NATIVE_MSG("tMsgLogger: bad message length: %d", msgLen);        
00873         } else {
00874             /* Need to byte swap the appropriate fields in the header */
00875             message.hdr.nodeFrom = ENDIAN_SWAP_LONG(message.hdr.nodeFrom);
00876             message.hdr.priority = ENDIAN_SWAP_SHORT(message.hdr.priority);
00877             message.hdr.pid      = ENDIAN_SWAP_LONG(message.hdr.pid);
00878             message.hdr.stime    = ENDIAN_SWAP_LONG(message.hdr.stime);
00879             message.hdr.count    = ENDIAN_SWAP_LONG(message.hdr.count);
00880             message.hdr.length   = ENDIAN_SWAP_LONG(message.hdr.length);
00881 
00882             /* Send the message to the socket (non-blocking) */
00883             sendLen = sendto(lSocket, (char *)&message, sizeof(mdMsgLogBuffer), MSG_DONTWAIT,
00884                              (struct sockaddr *)&lServerAddr, sizeof(struct sockaddr_in));
00885             if (sendLen < 0) {
00886                 NATIVE_MSG("tMsgLogger: sendto() failed: %s", strerror(errno));
00887             }
00888         }
00889     }
00890 
00891    return OK;
00892 
00893 } /* tMsgLogger */
00894 #endif /* Vxworks */
00895 #endif /* !USESYSLOG */

Generated on Mon Mar 16 22:58:47 2009 for loon by doxygen 1.3.5