MIDAS
Loading...
Searching...
No Matches
Message Functions (msg_xxx)

Classes

struct  msg_buffer_entry
 

Functions

std::string cm_get_error (INT code)
 
int cm_msg_early_init (void)
 
int cm_msg_open_buffer (void)
 
int cm_msg_close_buffer (void)
 
INT EXPRT cm_msg_facilities (STRING_LIST *list)
 
void cm_msg_get_logfile (const char *fac, time_t t, std::string *filename, std::string *linkname, std::string *linktarget)
 
INT cm_set_msg_print (INT system_mask, INT user_mask, int(*func)(const char *))
 
INT cm_msg_log (INT message_type, const char *facility, const char *message)
 
static std::string cm_msg_format (INT message_type, const char *filename, INT line, const char *routine, const char *format, va_list *argptr)
 
static INT cm_msg_send_event (DWORD ts, INT message_type, const char *send_message)
 
INT cm_msg_flush_buffer ()
 
INT cm_msg (INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
 
INT cm_msg1 (INT message_type, const char *filename, INT line, const char *facility, const char *routine, const char *format,...)
 
INT cm_msg_register (EVENT_HANDLER *func)
 
static void add_message (char **messages, int *length, int *allocated, time_t tstamp, const char *new_message)
 
static int cm_msg_retrieve1 (const char *filename, time_t t, INT n_messages, char **messages, int *length, int *allocated, int *num_messages)
 
INT cm_msg_retrieve2 (const char *facility, time_t t, INT n_message, char **messages, int *num_messages)
 
INT cm_msg_retrieve (INT n_message, char *message, INT buf_size)
 

Variables

static std::deque< msg_buffer_entrygMsgBuf
 
static std::mutex gMsgBufMutex
 

Detailed Description

dox dox


Function Documentation

◆ add_message()

static void add_message ( char **  messages,
int *  length,
int *  allocated,
time_t  tstamp,
const char *  new_message 
)
static

Definition at line 1089 of file midas.cxx.

1089 {
1090 int new_message_length = strlen(new_message);
1091 int new_allocated = 1024 + 2 * ((*allocated) + new_message_length);
1092 char buf[100];
1093 int buf_length;
1094
1095 //printf("add_message: new message %d, length %d, new end: %d, allocated: %d, maybe reallocate size %d\n", new_message_length, *length, *length + new_message_length, *allocated, new_allocated);
1096
1097 if (*length + new_message_length + 100 > *allocated) {
1098 *messages = (char *) realloc(*messages, new_allocated);
1099 assert(*messages != NULL);
1100 *allocated = new_allocated;
1101 }
1102
1103 if (*length > 0)
1104 if ((*messages)[(*length) - 1] != '\n') {
1105 (*messages)[*length] = '\n'; // separator between messages
1106 (*length) += 1;
1107 }
1108
1109 sprintf(buf, "%ld ", tstamp);
1110 buf_length = strlen(buf);
1111 memcpy(&((*messages)[*length]), buf, buf_length);
1112 (*length) += buf_length;
1113
1114 memcpy(&((*messages)[*length]), new_message, new_message_length);
1115 (*length) += new_message_length;
1116 (*messages)[*length] = 0; // make sure string is NUL terminated
1117}
Here is the caller graph for this function:

◆ cm_get_error()

std::string cm_get_error ( INT  code)

Convert error code to string. Used after cm_connect_experiment to print error string in command line programs or windows programs.

Parameters
codeError code as defined in midas.h
stringError string
Returns
CM_SUCCESS

Definition at line 473 of file midas.cxx.

474{
475 for (int i = 0; _error_table[i].code; i++) {
476 if (_error_table[i].code == code) {
477 return _error_table[i].string;
478 }
479 }
480
481 return msprintf("unlisted status code %d", code);
482}
INT i
Definition mdump.cxx:32
static const ERROR_TABLE _error_table[]
Definition midas.cxx:270
std::string msprintf(const char *format,...)
Definition midas.cxx:419
const char * string
Definition midas.cxx:267
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg()

INT cm_msg ( INT  message_type,
const char *  filename,
INT  line,
const char *  routine,
const char *  format,
  ... 
)

This routine can be called whenever an internal error occurs or an informative message is produced. Different message types can be enabled or disabled by setting the type bits via cm_set_msg_print().

Attention
Do not add the "\n" escape carriage control at the end of the formated line as it is already added by the client on the receiving side.
...
cm_msg(MINFO, "my program", "This is a information message only);
cm_msg(MERROR, "my program", "This is an error message with status:%d", my_status);
cm_msg(MTALK, "my_program", My program is Done!");
...
#define MINFO
Definition midas.h:560
MY my
Definition mdsupport.cxx:96
#define message(type, str)
DWORD status
Definition odbhist.cxx:39
double d
Definition system.cxx:1313
Parameters
message_type(See midas_macro).
filenameName of source file where error occured
lineLine number where error occured
routineRoutine name.
formatmessage to printout, ... Parameters like for printf()
Returns
CM_SUCCESS

Definition at line 939 of file midas.cxx.

940{
941 DWORD ts = ss_time();
942
943 /* print argument list into message */
944 std::string message;
945 va_list argptr;
946 va_start(argptr, format);
947 message = cm_msg_format(message_type, filename, line, routine, format, &argptr);
948 va_end(argptr);
949
950 //printf("message [%s]\n", message.c_str());
951
952 /* call user function if set via cm_set_msg_print */
954 if (f != NULL && (message_type & _message_mask_user) != 0) {
955 if (message_type != MT_LOG) { // do not print MLOG messages
956 (*f)(message.c_str());
957 }
958 }
959
960 /* return if system mask is not set */
961 if ((message_type & _message_mask_system) == 0) {
962 return CM_SUCCESS;
963 }
964
965 gMsgBufMutex.lock();
966 gMsgBuf.push_back(msg_buffer_entry{ts, message_type, message});
967 gMsgBufMutex.unlock();
968
969 return CM_SUCCESS;
970}
TRIGGER_SETTINGS ts
#define CM_SUCCESS
Definition midas.h:582
unsigned int DWORD
Definition mcstd.h:51
#define MT_LOG
Definition midas.h:546
DWORD ss_time()
Definition system.cxx:3541
static std::mutex gMsgBufMutex
Definition midas.cxx:881
static std::deque< msg_buffer_entry > gMsgBuf
Definition midas.cxx:880
static std::string cm_msg_format(INT message_type, const char *filename, INT line, const char *routine, const char *format, va_list *argptr)
Definition midas.cxx:769
static std::atomic_int _message_mask_system
Definition midas.cxx:453
int(* MessagePrintCallback)(const char *)
Definition midas.cxx:449
static std::atomic< MessagePrintCallback > _message_print
Definition midas.cxx:451
static std::atomic_int _message_mask_user
Definition midas.cxx:454
Definition midas.cxx:874
Here is the call graph for this function:

◆ cm_msg1()

INT cm_msg1 ( INT  message_type,
const char *  filename,
INT  line,
const char *  facility,
const char *  routine,
const char *  format,
  ... 
)

This routine is similar to cm_msg(). It differs from cm_msg() only by the logging destination being a file given through the argument list i.e:facility

Attention
Do not add the "\n" escape carriage control at the end of the formated line as it is already added by the client on the receiving side. The first arg in the following example uses the predefined macro MINFO which handles automatically the first 3 arguments of the function (see midas_macro).
...
cm_msg1(MINFO, "my_log_file", "my_program"," My message status:%d", status);
...
//----- File my_log_file.log
Thu Nov 8 17:59:28 2001 [my_program] My message status:1
INT cm_msg1(INT message_type, const char *filename, INT line, const char *facility, const char *routine, const char *format,...)
Definition midas.cxx:997
Parameters
message_typeSee midas_macro.
filenameName of source file where error occured
lineLine number where error occured
facilityLogging file name
routineRoutine name
formatmessage to printout, ... Parameters like for printf()
Returns
CM_SUCCESS

Definition at line 997 of file midas.cxx.

998 {
999 va_list argptr;
1000 std::string message;
1001 static BOOL in_routine = FALSE;
1002
1003 /* avoid recursive calles */
1004 if (in_routine)
1005 return 0;
1006
1007 in_routine = TRUE;
1008
1009 /* print argument list into message */
1010 va_start(argptr, format);
1011 message = cm_msg_format(message_type, filename, line, routine, format, &argptr);
1012 va_end(argptr);
1013
1014 /* call user function if set via cm_set_msg_print */
1016 if (f != NULL && (message_type & _message_mask_user) != 0)
1017 (*f)(message.c_str());
1018
1019 /* return if system mask is not set */
1020 if ((message_type & _message_mask_system) == 0) {
1021 in_routine = FALSE;
1022 return CM_SUCCESS;
1023 }
1024
1025 /* send message to SYSMSG */
1026 cm_msg_send_event(0, message_type, message.c_str());
1027
1028 /* log message */
1029 cm_msg_log(message_type, facility, message.c_str());
1030
1031 in_routine = FALSE;
1032
1033 return CM_SUCCESS;
1034}
#define FALSE
Definition cfortran.h:309
INT cm_msg_log(INT message_type, const char *facility, const char *message)
Definition midas.cxx:682
static INT cm_msg_send_event(DWORD ts, INT message_type, const char *send_message)
Definition midas.cxx:848
DWORD BOOL
Definition midas.h:105
#define TRUE
Definition midas.h:182
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_close_buffer()

int cm_msg_close_buffer ( void  )

Definition at line 505 of file midas.cxx.

505 {
506 //printf("cm_msg_close_buffer!\n");
507 if (_msg_buffer) {
509 _msg_buffer = 0;
510 }
511 return CM_SUCCESS;
512}
INT bm_close_buffer(INT buffer_handle)
Definition midas.cxx:7170
static INT _msg_buffer
Definition midas.cxx:198
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_early_init()

int cm_msg_early_init ( void  )

Definition at line 485 of file midas.cxx.

485 {
486
487 return CM_SUCCESS;
488}
Here is the caller graph for this function:

◆ cm_msg_facilities()

INT EXPRT cm_msg_facilities ( STRING_LIST list)

Retrieve list of message facilities by searching logfiles on disk

Parameters
listList of facilities
Returns
status SUCCESS

Definition at line 522 of file midas.cxx.

522 {
523 std::string path;
524
525 cm_msg_get_logfile("midas", 0, &path, NULL, NULL);
526
527 /* extract directory name from full path name of midas.log */
528 size_t pos = path.rfind(DIR_SEPARATOR);
529 if (pos != std::string::npos) {
530 path.resize(pos);
531 } else {
532 path = "";
533 }
534
535 //printf("cm_msg_facilities: path [%s]\n", path.c_str());
536
537 STRING_LIST flist;
538
539 ss_file_find(path.c_str(), "*.log", &flist);
540
541 for (size_t i = 0; i < flist.size(); i++) {
542 const char *p = flist[i].c_str();
543 if (strchr(p, '_') == NULL && !(p[0] >= '0' && p[0] <= '9')) {
544 size_t pos = flist[i].rfind('.');
545 if (pos != std::string::npos) {
546 flist[i].resize(pos);
547 }
548 list->push_back(flist[i]);
549 }
550 }
551
552 return SUCCESS;
553}
#define SUCCESS
Definition mcstd.h:54
INT ss_file_find(const char *path, const char *pattern, char **plist)
Definition system.cxx:6798
void cm_msg_get_logfile(const char *fac, time_t t, std::string *filename, std::string *linkname, std::string *linktarget)
Definition midas.cxx:557
#define DIR_SEPARATOR
Definition midas.h:193
std::vector< std::string > STRING_LIST
Definition midas.h:246
static te_expr * list(state *s)
Definition tinyexpr.c:567
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_flush_buffer()

INT cm_msg_flush_buffer ( void  )

This routine can be called to process messages buffered by cm_msg(). Normally it is called from cm_yield() and cm_disconnect_experiment() to make sure all accumulated messages are processed.

Definition at line 889 of file midas.cxx.

889 {
890 int i;
891
892 //printf("cm_msg_flush_buffer!\n");
893
894 for (i = 0; i < 100; i++) {
896 {
897 std::lock_guard<std::mutex> lock(gMsgBufMutex);
898 if (gMsgBuf.empty())
899 break;
900 e = gMsgBuf.front();
901 gMsgBuf.pop_front();
902 // implicit unlock
903 }
904
905 /* log message */
906 cm_msg_log(e.message_type, "midas", e.message.c_str());
907
908 /* send message to SYSMSG */
909 int status = cm_msg_send_event(e.ts, e.message_type, e.message.c_str());
910 if (status != CM_SUCCESS)
911 return status;
912 }
913
914 return CM_SUCCESS;
915}
static double e(void)
Definition tinyexpr.c:136
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_format()

static std::string cm_msg_format ( INT  message_type,
const char *  filename,
INT  line,
const char *  routine,
const char *  format,
va_list *  argptr 
)
static

Definition at line 769 of file midas.cxx.

770{
771 /* strip path */
772 const char* pc = filename + strlen(filename);
773 while (*pc != '\\' && *pc != '/' && pc != filename)
774 pc--;
775 if (pc != filename)
776 pc++;
777
778 /* convert type to string */
779 std::string type_str;
780 if (message_type & MT_ERROR)
781 type_str += MT_ERROR_STR;
782 if (message_type & MT_INFO)
783 type_str += MT_INFO_STR;
784 if (message_type & MT_DEBUG)
785 type_str += MT_DEBUG_STR;
786 if (message_type & MT_USER)
787 type_str += MT_USER_STR;
788 if (message_type & MT_LOG)
789 type_str += MT_LOG_STR;
790 if (message_type & MT_TALK)
791 type_str += MT_TALK_STR;
792
793 std::string message;
794
795 /* print client name into string */
796 if (message_type == MT_USER)
797 message = msprintf("[%s] ", routine);
798 else {
799 std::string name = rpc_get_name();
800 if (name.length() > 0)
801 message = msprintf("[%s,%s] ", name.c_str(), type_str.c_str());
802 else
803 message = "";
804 }
805
806 /* preceed error messages with file and line info */
807 if (message_type == MT_ERROR) {
808 message += msprintf("[%s:%d:%s,%s] ", pc, line, routine, type_str.c_str());
809 } else if (message_type == MT_USER) {
810 message = msprintf("[%s,%s] ", routine, type_str.c_str());
811 }
812
813 int bufsize = 1024;
814 char* buf = (char*)malloc(bufsize);
815 assert(buf);
816
817 for (int i=0; i<10; i++) {
818 va_list ap;
819 va_copy(ap, *argptr);
820
821 /* print argument list into message */
822 int n = vsnprintf(buf, bufsize, format, ap);
823
824 //printf("vsnprintf [%s] %d %d\n", format, bufsize, n);
825
826 va_end(ap);
827
828 if (n < 0) {
829 buf[0] = 0;
830 break;
831 }
832
833 if (n < bufsize) {
834 break;
835 }
836
837 bufsize = n + 1;
838 buf = (char*)realloc(buf, bufsize);
839 assert(buf);
840 }
841
842 message += buf;
843 free(buf);
844
845 return message;
846}
#define MT_LOG_STR
Definition midas.h:555
#define MT_INFO_STR
Definition midas.h:552
#define MT_INFO
Definition midas.h:543
#define MT_DEBUG_STR
Definition midas.h:553
#define MT_TALK
Definition midas.h:547
#define MT_USER
Definition midas.h:545
#define MT_USER_STR
Definition midas.h:554
#define MT_TALK_STR
Definition midas.h:556
#define MT_DEBUG
Definition midas.h:544
#define MT_ERROR
Definition midas.h:542
#define MT_ERROR_STR
Definition midas.h:551
std::string rpc_get_name()
Definition midas.cxx:13317
DWORD n[4]
Definition mana.cxx:247
#define name(x)
Definition midas_macro.h:24
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_get_logfile()

void cm_msg_get_logfile ( const char *  fac,
time_t  t,
std::string *  filename,
std::string *  linkname,
std::string *  linktarget 
)

Definition at line 557 of file midas.cxx.

557 {
558 HNDLE hDB;
559 int status;
560
562
563 // check for call to cm_msg() before MIDAS is fully initialized
564 // or after MIDAS is partially shutdown.
565 if (status != CM_SUCCESS) {
566 if (filename)
567 *filename = std::string(fac) + ".log";
568 if (linkname)
569 *linkname = "";
570 if (linktarget)
571 *linktarget = "";
572 return;
573 }
574
575 if (filename)
576 *filename = "";
577 if (linkname)
578 *linkname = "";
579 if (linktarget)
580 *linktarget = "";
581
582 std::string facility;
583 if (fac && fac[0])
584 facility = fac;
585 else
586 facility = "midas";
587
588 std::string message_format;
589 db_get_value_string(hDB, 0, "/Logger/Message file date format", 0, &message_format, TRUE);
590 if (message_format.find('%') != std::string::npos) {
591 /* replace stings such as %y%m%d with current date */
592 struct tm tms;
593
594 ss_tzset();
595 if (t == 0)
596 time(&t);
597 localtime_r(&t, &tms);
598
599 char de[256];
600 de[0] = '_';
601 strftime(de + 1, sizeof(de)-1, strchr(message_format.c_str(), '%'), &tms);
602 message_format = de;
603 }
604
605 std::string message_dir;
606 db_get_value_string(hDB, 0, "/Logger/Message dir", 0, &message_dir, TRUE);
607 if (message_dir.empty()) {
608 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &message_dir, FALSE);
609 if (message_dir.empty()) {
610 message_dir = cm_get_path();
611 if (message_dir.empty()) {
612 message_dir = ss_getcwd();
613 }
614 }
615 }
616
617 // prepend experiment directory
618 if (message_dir[0] != DIR_SEPARATOR)
619 message_dir = cm_get_path() + message_dir;
620
621 if (message_dir.back() != DIR_SEPARATOR)
622 message_dir.push_back(DIR_SEPARATOR);
623
624 if (filename)
625 *filename = message_dir + facility + message_format + ".log";
626 if (!message_format.empty()) {
627 if (linkname)
628 *linkname = message_dir + facility + ".log";
629 if (linktarget)
630 *linktarget = facility + message_format + ".log";
631 }
632}
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3083
std::string cm_get_path()
Definition midas.cxx:1587
std::string ss_getcwd()
Definition system.cxx:5855
void ss_tzset()
Definition system.cxx:3434
INT EXPRT db_get_value_string(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, int index, std::string *s, BOOL create, int create_string_length)
Definition odb.cxx:14528
HNDLE hDB
main ODB handle
Definition mana.cxx:207
INT HNDLE
Definition midas.h:132
MUTEX_T * tm
Definition odbedit.cxx:39
static double fac(double a)
Definition tinyexpr.c:137
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_log()

INT cm_msg_log ( INT  message_type,
const char *  facility,
const char *  message 
)

Write message to logging file. Called by cm_msg.

Attention
May burn your fingers
Parameters
message_typeMessage type
messageMessage string
facilityMessage facility, filename in which messages will be written
Returns
CM_SUCCESS

Definition at line 682 of file midas.cxx.

682 {
683 INT status;
684
685 if (rpc_is_remote()) {
686 if (rpc_is_connected()) {
687 status = rpc_call(RPC_CM_MSG_LOG, message_type, facility, message);
688 if (status != RPC_SUCCESS) {
689 fprintf(stderr, "cm_msg_log: Message \"%s\" not written to midas.log because rpc_call(RPC_CM_MSG_LOG) failed with status %d\n", message, status);
690 }
691 return status;
692 } else {
693 fprintf(stderr, "cm_msg_log: Message \"%s\" not written to midas.log, no connection to mserver\n", message);
694 return RPC_NET_ERROR;
695 }
696 }
697
698 if (message_type != MT_DEBUG) {
699 std::string filename, linkname, linktarget;
700
701 cm_msg_get_logfile(facility, 0, &filename, &linkname, &linktarget);
702
703#ifdef OS_LINUX
704 if (!linkname.empty()) {
705 //printf("cm_msg_log: filename [%s] linkname [%s] linktarget [%s]\n", filename.c_str(), linkname.c_str(), linktarget.c_str());
706 // If filename does not exist, user just switched from non-date format to date format.
707 // In that case we must copy linkname to filename, otherwise messages might get lost.
708 if (ss_file_exist(linkname.c_str()) && !ss_file_link_exist(linkname.c_str())) {
709 ss_file_copy(linkname.c_str(), filename.c_str(), true);
710 }
711
712 unlink(linkname.c_str());
713 status = symlink(linktarget.c_str(), linkname.c_str());
714 if (status != 0) {
715 fprintf(stderr,
716 "cm_msg_log: Error: Cannot symlink message log file \'%s' to \'%s\', symlink() errno: %d (%s)\n",
717 linktarget.c_str(), linkname.c_str(), errno, strerror(errno));
718 }
719 }
720#endif
721
722 int fh = open(filename.c_str(), O_WRONLY | O_CREAT | O_APPEND | O_LARGEFILE, 0644);
723 if (fh < 0) {
724 fprintf(stderr,
725 "cm_msg_log: Message \"%s\" not written to midas.log because open(%s) failed with errno %d (%s)\n",
726 message, filename.c_str(), errno, strerror(errno));
727 } else {
728
729 struct timeval tv;
730 struct tm tms;
731
732 ss_tzset();
733 gettimeofday(&tv, NULL);
734 localtime_r(&tv.tv_sec, &tms);
735
736 char str[256];
737 strftime(str, sizeof(str), "%H:%M:%S", &tms);
738 sprintf(str + strlen(str), ".%03d ", (int) (tv.tv_usec / 1000));
739 strftime(str + strlen(str), sizeof(str), "%Y/%m/%d", &tms);
740
741 std::string msg;
742 msg += str;
743 msg += " ";
744 msg += message;
745 msg += "\n";
746
747 /* avoid c++ complaint about comparison between
748 unsigned size_t returned by msg.length() and
749 signed ssize_t returned by write() */
750 ssize_t len = msg.length();
751
752 /* atomic write, no need to take a semaphore */
753 ssize_t wr = write(fh, msg.c_str(), len);
754
755 if (wr < 0) {
756 fprintf(stderr, "cm_msg_log: Message \"%s\" not written to \"%s\", write() error, errno %d (%s)\n", message, filename.c_str(), errno, strerror(errno));
757 } else if (wr != len) {
758 fprintf(stderr, "cm_msg_log: Message \"%s\" not written to \"%s\", short write() wrote %d instead of %d bytes\n", message, filename.c_str(), (int)wr, (int)len);
759 }
760
761 close(fh);
762 }
763 }
764
765 return CM_SUCCESS;
766}
#define RPC_SUCCESS
Definition midas.h:699
#define RPC_NET_ERROR
Definition midas.h:702
int ss_file_exist(const char *path)
Definition system.cxx:7203
int ss_file_link_exist(const char *path)
Definition system.cxx:7239
int ss_file_copy(const char *src, const char *dst, bool append)
Definition system.cxx:7304
bool rpc_is_remote(void)
Definition midas.cxx:12994
bool rpc_is_connected(void)
Definition midas.cxx:13016
INT rpc_call(DWORD routine_id,...)
Definition midas.cxx:14217
#define RPC_CM_MSG_LOG
Definition mrpc.h:25
#define O_LARGEFILE
Definition midas.h:210
int INT
Definition midas.h:129
#define write(n, a, f, d)
int gettimeofday(struct timeval *tp, void *tzp)
timeval tv
Definition msysmon.cxx:1095
char str[256]
Definition odbhist.cxx:33
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_open_buffer()

int cm_msg_open_buffer ( void  )

Definition at line 492 of file midas.cxx.

492 {
493 //printf("cm_msg_open_buffer!\n");
494 if (_msg_buffer == 0) {
496 if (status != BM_SUCCESS && status != BM_CREATED) {
497 return status;
498 }
499 }
500 return CM_SUCCESS;
501}
INT bm_open_buffer(const char *buffer_name, INT buffer_size, INT *buffer_handle)
Definition midas.cxx:6782
#define BM_SUCCESS
Definition midas.h:605
#define BM_CREATED
Definition midas.h:606
#define MESSAGE_BUFFER_NAME
Definition msystem.h:111
#define MESSAGE_BUFFER_SIZE
Definition msystem.h:110
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_register()

INT cm_msg_register ( EVENT_HANDLER func)

Register a dispatch function for receiving system messages.

Definition at line 1075 of file midas.cxx.

1075 {
1076 INT status, id;
1077
1078 // we should only come here after the message buffer
1079 // was opened by cm_connect_experiment()
1080 assert(_msg_buffer);
1081
1082 _msg_dispatch = func;
1083
1085
1086 return status;
1087}
INT bm_request_event(HNDLE buffer_handle, short int event_id, short int trigger_mask, INT sampling_type, HNDLE *request_id, EVENT_HANDLER *func)
Definition midas.cxx:8578
#define GET_NONBLOCKING
Definition midas.h:322
#define TRIGGER_ALL
Definition midas.h:538
#define EVENTID_ALL
Definition midas.h:537
static EVENT_HANDLER * _msg_dispatch
Definition midas.cxx:199
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_retrieve()

INT cm_msg_retrieve ( INT  n_message,
char *  message,
INT  buf_size 
)

Retrieve newest messages from "midas" facility log file

Parameters
n_messageNumber of messages to retrieve
messagebuf_size bytes of messages, separated by
characters. The returned number of bytes is normally smaller than the initial buf_size, since only full lines are returned.
*buf_sizeSize of message buffer to fill
Returns
CM_SUCCESS, CM_TRUNCATED

Definition at line 1381 of file midas.cxx.

1381 {
1382 int status;
1383 char *messages = NULL;
1384 int num_messages = 0;
1385
1386 if (rpc_is_remote())
1387 return rpc_call(RPC_CM_MSG_RETRIEVE, n_message, message, buf_size);
1388
1389 if (buf_size > 0)
1390 message[0] = 0;
1391
1392 status = cm_msg_retrieve2("midas", 0, n_message, &messages, &num_messages);
1393
1394 if (messages) {
1395 mstrlcpy(message, messages, buf_size);
1396 int len = strlen(messages);
1397 if (len >= buf_size)
1399 free(messages);
1400 }
1401
1402 return status;
1403}
#define CM_TRUNCATED
Definition midas.h:596
INT cm_msg_retrieve2(const char *facility, time_t t, INT n_message, char **messages, int *num_messages)
Definition midas.cxx:1311
#define RPC_CM_MSG_RETRIEVE
Definition mrpc.h:32
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_retrieve1()

static int cm_msg_retrieve1 ( const char *  filename,
time_t  t,
INT  n_messages,
char **  messages,
int *  length,
int *  allocated,
int *  num_messages 
)
static

Definition at line 1120 of file midas.cxx.

1121 {
1122 BOOL stop;
1123 int fh;
1124 char *p, str[1000];
1125 struct stat stat_buf;
1126 time_t tstamp, tstamp_valid, tstamp_last;
1127
1128 ss_tzset(); // required by localtime_r()
1129
1130 *num_messages = 0;
1131
1132 fh = open(filename, O_RDONLY | O_TEXT, 0644);
1133 if (fh < 0) {
1134 cm_msg(MERROR, "cm_msg_retrieve1", "Cannot open log file \"%s\", errno %d (%s)", filename, errno,
1135 strerror(errno));
1136 return SS_FILE_ERROR;
1137 }
1138
1139 /* read whole file into memory */
1140 if (fstat(fh, &stat_buf) != 0) {
1141 cm_msg(MERROR, "cm_msg_retrieve1", "Cannot stat log file \"%s\", errno %d (%s)", filename, errno,
1142 strerror(errno));
1143 close(fh);
1144 return SS_FILE_ERROR;
1145 }
1146 ssize_t size = stat_buf.st_size;
1147
1148 /* if file is too big, only read tail of file */
1149 ssize_t maxsize = 10 * 1024 * 1024;
1150 if (size > maxsize) {
1151 lseek(fh, -maxsize, SEEK_END);
1152 //printf("lseek status %d, errno %d (%s)\n", status, errno, strerror(errno));
1153 size = maxsize;
1154 }
1155
1156 char *buffer = (char *) malloc(size + 1);
1157
1158 if (buffer == NULL) {
1159 cm_msg(MERROR, "cm_msg_retrieve1", "Cannot malloc %d bytes to read log file \"%s\", errno %d (%s)", (int) size,
1160 filename, errno, strerror(errno));
1161 close(fh);
1162 return SS_FILE_ERROR;
1163 }
1164
1165 ssize_t rd = read(fh, buffer, size);
1166
1167 if (rd != size) {
1168 cm_msg(MERROR, "cm_msg_retrieve1", "Cannot read %d bytes from log file \"%s\", read() returned %d, errno %d (%s)",
1169 (int) size, filename, (int) rd, errno, strerror(errno));
1170 free(buffer);
1171 close(fh);
1172 return SS_FILE_ERROR;
1173 }
1174
1175 buffer[size] = 0;
1176 close(fh);
1177
1178 tstamp_last = tstamp_valid = 0;
1179 stop = FALSE;
1180
1181 if (size == 0) {
1182 free(buffer);
1183 return CM_SUCCESS;
1184 }
1185
1186 p = buffer + size - 1;
1187
1188 while (p > buffer && (*p == '\n' || *p == '\r'))
1189 p--;
1190
1191 if (p == buffer && (*p == '\n' || *p == '\r')) {
1192 free(buffer);
1193 return CM_SUCCESS;
1194 }
1195
1196 int n;
1197 for (n = 0; !stop;) {
1198
1199 /* go to beginning of line */
1200 int i;
1201 for (i = 0; p != buffer && (*p != '\n' && *p != '\r'); i++)
1202 p--;
1203
1204 /* limit line length to sizeof(str) */
1205 if (i >= (int) sizeof(str))
1206 i = sizeof(str) - 1;
1207
1208 if (p == buffer) {
1209 i++;
1210 memcpy(str, p, i);
1211 } else
1212 memcpy(str, p + 1, i);
1213 str[i] = 0;
1214 if (strchr(str, '\n'))
1215 *strchr(str, '\n') = 0;
1216 if (strchr(str, '\r'))
1217 *strchr(str, '\r') = 0;
1218 mstrlcat(str, "\n", sizeof(str));
1219
1220 // extract time tag
1221 time_t now;
1222 time(&now);
1223
1224 struct tm tms;
1225 localtime_r(&now, &tms); // must call tzset() beforehand!
1226
1227 if (str[0] >= '0' && str[0] <= '9') {
1228 // new format
1229 tms.tm_hour = atoi(str);
1230 tms.tm_min = atoi(str + 3);
1231 tms.tm_sec = atoi(str + 6);
1232 tms.tm_year = atoi(str + 13) - 1900;
1233 tms.tm_mon = atoi(str + 18) - 1;
1234 tms.tm_mday = atoi(str + 21);
1235 } else {
1236 // old format
1237 tms.tm_hour = atoi(str + 11);
1238 tms.tm_min = atoi(str + 14);
1239 tms.tm_sec = atoi(str + 17);
1240 tms.tm_year = atoi(str + 20) - 1900;
1241 for (i = 0; i < 12; i++)
1242 if (strncmp(str + 4, mname[i], 3) == 0)
1243 break;
1244 tms.tm_mon = i;
1245 tms.tm_mday = atoi(str + 8);
1246 }
1247 tstamp = ss_mktime(&tms);
1248 if (tstamp != -1)
1249 tstamp_valid = tstamp;
1250
1251 // for new messages (n=0!), stop when t reached
1252 if (n_messages == 0) {
1253 if (tstamp_valid < t)
1254 break;
1255 }
1256
1257 // for old messages, stop when all messages belonging to tstamp_last are sent
1258 if (n_messages != 0) {
1259 if (tstamp_last > 0 && tstamp_valid < tstamp_last)
1260 break;
1261 }
1262
1263 if (t == 0 || tstamp == -1 ||
1264 (n_messages > 0 && tstamp <= t) ||
1265 (n_messages == 0 && tstamp >= t)) {
1266
1267 n++;
1268
1269 add_message(messages, length, allocated, tstamp, str);
1270 }
1271
1272 if (p == buffer)
1273 break;
1274
1275 while (p > buffer && (*p == '\n' || *p == '\r'))
1276 p--;
1277
1278 if (p == buffer && (*p == '\n' || *p == '\r'))
1279 break;
1280
1281 if (n_messages == 1)
1282 stop = TRUE;
1283 else if (n_messages > 1) {
1284 // continue collecting messages until time stamp differs from current one
1285 if (n == n_messages)
1286 tstamp_last = tstamp_valid;
1287
1288 // if all messages without time tags, just return after n
1289 if (n == n_messages && tstamp_valid == 0)
1290 break;
1291 }
1292 }
1293
1294 free(buffer);
1295
1296 *num_messages = n;
1297
1298 return CM_SUCCESS;
1299}
#define SS_FILE_ERROR
Definition midas.h:670
#define MERROR
Definition midas.h:559
#define O_TEXT
Definition msystem.h:227
time_t ss_mktime(struct tm *tms)
Definition system.cxx:3444
static void add_message(char **messages, int *length, int *allocated, time_t tstamp, const char *new_message)
Definition midas.cxx:1089
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:939
const char * mname[]
Definition midas.cxx:144
#define read(n, a, f)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_retrieve2()

INT cm_msg_retrieve2 ( const char *  facility,
time_t  t,
INT  n_message,
char **  messages,
int *  num_messages 
)

Retrieve old messages from log file

Parameters
facilityLogging facility ("midas", "chat", "lazy", ...)
tReturn messages logged before and including time t, value 0 means start with newest messages
min_messagesMinimum number of messages to return
messagesmessages, newest first, separated by
characters. caller should free() this buffer at the end.
num_messagesNumber of messages returned
Returns
CM_SUCCESS

Definition at line 1311 of file midas.cxx.

1311 {
1312 std::string filename, linkname;
1313 INT n, i;
1314 time_t filedate;
1315 int length = 0;
1316 int allocated = 0;
1317
1318 time(&filedate);
1319 cm_msg_get_logfile(facility, filedate, &filename, &linkname, NULL);
1320
1321 //printf("facility %s, filename \"%s\" \"%s\"\n", facility, filename, linkname);
1322
1323 // see if file exists, use linkname if not
1324 if (!linkname.empty()) {
1325 if (!ss_file_exist(filename.c_str()))
1326 filename = linkname;
1327 }
1328
1329 if (ss_file_exist(filename.c_str())) {
1330 cm_msg_retrieve1(filename.c_str(), t, n_message, messages, &length, &allocated, &n);
1331 } else {
1332 n = 0;
1333 }
1334
1335 /* if there is no symlink, then there is no additional log files to read */
1336 if (linkname.empty()) {
1337 *num_messages = n;
1338 return CM_SUCCESS;
1339 }
1340
1341 //printf("read more messages %d %d!\n", n, n_message);
1342
1343 int missing = 0;
1344 while (n < n_message) {
1345 filedate -= 3600 * 24; // go one day back
1346
1347 cm_msg_get_logfile(facility, filedate, &filename, NULL, NULL);
1348
1349 //printf("read [%s] for time %d!\n", filename.c_str(), filedate);
1350
1351 if (ss_file_exist(filename.c_str())) {
1352 cm_msg_retrieve1(filename.c_str(), t, n_message - n, messages, &length, &allocated, &i);
1353 n += i;
1354 missing = 0;
1355 } else {
1356 missing++;
1357 }
1358
1359 // stop if ten consecutive files are not found
1360 if (missing > 10)
1361 break;
1362 }
1363
1364 *num_messages = n;
1365
1366 return CM_SUCCESS;
1367}
static int cm_msg_retrieve1(const char *filename, time_t t, INT n_messages, char **messages, int *length, int *allocated, int *num_messages)
Definition midas.cxx:1120
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_msg_send_event()

static INT cm_msg_send_event ( DWORD  ts,
INT  message_type,
const char *  send_message 
)
static

Definition at line 848 of file midas.cxx.

848 {
849 //printf("cm_msg_send: ts %d, type %d, message [%s]\n", ts, message_type, send_message);
850
851 /* send event if not of type MLOG */
852 if (message_type != MT_LOG) {
853 if (_msg_buffer) {
854 /* copy message to event */
855 size_t len = strlen(send_message);
856 int event_length = sizeof(EVENT_HEADER) + len + 1;
857 char event[event_length];
858 EVENT_HEADER *pevent = (EVENT_HEADER *) event;
859
860 memcpy(event + sizeof(EVENT_HEADER), send_message, len + 1);
861
862 /* setup the event header and send the message */
863 bm_compose_event(pevent, EVENTID_MESSAGE, (WORD) message_type, len + 1, 0);
864 if (ts)
865 pevent->time_stamp = ts;
866 //printf("cm_msg_send_event: len %d, header %d, allocated %d, data_size %d, bm_send_event %p+%d\n", (int)len, (int)sizeof(EVENT_HEADER), event_length, pevent->data_size, pevent, (int)(pevent->data_size + sizeof(EVENT_HEADER)));
867 bm_send_event(_msg_buffer, pevent, 0, BM_WAIT);
868 }
869 }
870
871 return CM_SUCCESS;
872}
INT bm_send_event(INT buffer_handle, const EVENT_HEADER *pevent, int unused, int timeout_msec)
Definition midas.cxx:9791
INT bm_compose_event(EVENT_HEADER *event_header, short int event_id, short int trigger_mask, DWORD data_size, DWORD serial)
Definition midas.cxx:8394
unsigned short int WORD
Definition mcstd.h:49
#define BM_WAIT
Definition midas.h:365
#define EVENTID_MESSAGE
Definition midas.h:903
DWORD time_stamp
Definition midas.h:856
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cm_set_msg_print()

INT cm_set_msg_print ( INT  system_mask,
INT  user_mask,
int(*)(const char *)  func 
)

Set message masks. When a message is generated by calling cm_msg(), it can got to two destinatinons. First a user defined callback routine and second to the "SYSMSG" buffer.

A user defined callback receives all messages which satisfy the user_mask.

int message_print(const char *msg)
{
char str[160];
memset(str, ' ', 159);
str[159] = 0;
if (msg[0] == '[')
msg = strchr(msg, ']')+2;
memcpy(str, msg, strlen(msg));
ss_printf(0, 20, str);
return 0;
}
...
...
#define MT_ALL
Definition midas.h:549
void ss_printf(INT x, INT y, const char *format,...)
Definition system.cxx:7467
INT cm_set_msg_print(INT system_mask, INT user_mask, int(*func)(const char *))
Definition midas.cxx:665
static int message_print(const char *msg)
Definition mfe.cxx:1348
Parameters
system_maskBit masks for MERROR, MINFO etc. to send system messages.
user_maskBit masks for MERROR, MINFO etc. to send messages to the user callback.
funcFunction which receives all printout. By setting "puts", messages are just printed to the screen.
Returns
CM_SUCCESS

Definition at line 665 of file midas.cxx.

665 {
666 _message_mask_system = system_mask;
667 _message_mask_user = user_mask;
668 _message_print = func;
669
670 return BM_SUCCESS;
671}
Here is the caller graph for this function:

Variable Documentation

◆ gMsgBuf

std::deque<msg_buffer_entry> gMsgBuf
static

Definition at line 880 of file midas.cxx.

◆ gMsgBufMutex

std::mutex gMsgBufMutex
static

Definition at line 881 of file midas.cxx.