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 1081 of file midas.cxx.

1081 {
1082 int new_message_length = strlen(new_message);
1083 int new_allocated = 1024 + 2 * ((*allocated) + new_message_length);
1084 char buf[100];
1085 int buf_length;
1086
1087 //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);
1088
1089 if (*length + new_message_length + 100 > *allocated) {
1090 *messages = (char *) realloc(*messages, new_allocated);
1091 assert(*messages != NULL);
1092 *allocated = new_allocated;
1093 }
1094
1095 if (*length > 0)
1096 if ((*messages)[(*length) - 1] != '\n') {
1097 (*messages)[*length] = '\n'; // separator between messages
1098 (*length) += 1;
1099 }
1100
1101 sprintf(buf, "%ld ", tstamp);
1102 buf_length = strlen(buf);
1103 memcpy(&((*messages)[*length]), buf, buf_length);
1104 (*length) += buf_length;
1105
1106 memcpy(&((*messages)[*length]), new_message, new_message_length);
1107 (*length) += new_message_length;
1108 (*messages)[*length] = 0; // make sure string is NUL terminated
1109}
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 469 of file midas.cxx.

470{
471 for (int i = 0; _error_table[i].code; i++) {
472 if (_error_table[i].code == code) {
473 return _error_table[i].string;
474 }
475 }
476
477 return msprintf("unlisted status code %d", code);
478}
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 931 of file midas.cxx.

932{
933 DWORD ts = ss_time();
934
935 /* print argument list into message */
936 std::string message;
937 va_list argptr;
938 va_start(argptr, format);
939 message = cm_msg_format(message_type, filename, line, routine, format, &argptr);
940 va_end(argptr);
941
942 //printf("message [%s]\n", message.c_str());
943
944 /* call user function if set via cm_set_msg_print */
946 if (f != NULL && (message_type & _message_mask_user) != 0) {
947 if (message_type != MT_LOG) { // do not print MLOG messages
948 (*f)(message.c_str());
949 }
950 }
951
952 /* return if system mask is not set */
953 if ((message_type & _message_mask_system) == 0) {
954 return CM_SUCCESS;
955 }
956
957 gMsgBufMutex.lock();
958 gMsgBuf.push_back(msg_buffer_entry{ts, message_type, message});
959 gMsgBufMutex.unlock();
960
961 return CM_SUCCESS;
962}
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:3534
static std::mutex gMsgBufMutex
Definition midas.cxx:873
static std::deque< msg_buffer_entry > gMsgBuf
Definition midas.cxx:872
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:765
static std::atomic_int _message_mask_system
Definition midas.cxx:449
int(* MessagePrintCallback)(const char *)
Definition midas.cxx:445
static std::atomic< MessagePrintCallback > _message_print
Definition midas.cxx:447
static std::atomic_int _message_mask_user
Definition midas.cxx:450
Definition midas.cxx:866
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:989
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 989 of file midas.cxx.

990 {
991 va_list argptr;
992 std::string message;
993 static BOOL in_routine = FALSE;
994
995 /* avoid recursive calles */
996 if (in_routine)
997 return 0;
998
999 in_routine = TRUE;
1000
1001 /* print argument list into message */
1002 va_start(argptr, format);
1003 message = cm_msg_format(message_type, filename, line, routine, format, &argptr);
1004 va_end(argptr);
1005
1006 /* call user function if set via cm_set_msg_print */
1008 if (f != NULL && (message_type & _message_mask_user) != 0)
1009 (*f)(message.c_str());
1010
1011 /* return if system mask is not set */
1012 if ((message_type & _message_mask_system) == 0) {
1013 in_routine = FALSE;
1014 return CM_SUCCESS;
1015 }
1016
1017 /* send message to SYSMSG */
1018 cm_msg_send_event(0, message_type, message.c_str());
1019
1020 /* log message */
1021 cm_msg_log(message_type, facility, message.c_str());
1022
1023 in_routine = FALSE;
1024
1025 return CM_SUCCESS;
1026}
#define FALSE
Definition cfortran.h:309
INT cm_msg_log(INT message_type, const char *facility, const char *message)
Definition midas.cxx:678
static INT cm_msg_send_event(DWORD ts, INT message_type, const char *send_message)
Definition midas.cxx:840
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 501 of file midas.cxx.

501 {
502 //printf("cm_msg_close_buffer!\n");
503 if (_msg_buffer) {
505 _msg_buffer = 0;
506 }
507 return CM_SUCCESS;
508}
INT bm_close_buffer(INT buffer_handle)
Definition midas.cxx:7107
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 481 of file midas.cxx.

481 {
482
483 return CM_SUCCESS;
484}
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 518 of file midas.cxx.

518 {
519 std::string path;
520
521 cm_msg_get_logfile("midas", 0, &path, NULL, NULL);
522
523 /* extract directory name from full path name of midas.log */
524 size_t pos = path.rfind(DIR_SEPARATOR);
525 if (pos != std::string::npos) {
526 path.resize(pos);
527 } else {
528 path = "";
529 }
530
531 //printf("cm_msg_facilities: path [%s]\n", path.c_str());
532
533 STRING_LIST flist;
534
535 ss_file_find(path.c_str(), "*.log", &flist);
536
537 for (size_t i = 0; i < flist.size(); i++) {
538 const char *p = flist[i].c_str();
539 if (strchr(p, '_') == NULL && !(p[0] >= '0' && p[0] <= '9')) {
540 size_t pos = flist[i].rfind('.');
541 if (pos != std::string::npos) {
542 flist[i].resize(pos);
543 }
544 list->push_back(flist[i]);
545 }
546 }
547
548 return SUCCESS;
549}
#define SUCCESS
Definition mcstd.h:54
INT ss_file_find(const char *path, const char *pattern, char **plist)
Definition system.cxx:6791
void cm_msg_get_logfile(const char *fac, time_t t, std::string *filename, std::string *linkname, std::string *linktarget)
Definition midas.cxx:553
#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 881 of file midas.cxx.

881 {
882 int i;
883
884 //printf("cm_msg_flush_buffer!\n");
885
886 for (i = 0; i < 100; i++) {
888 {
889 std::lock_guard<std::mutex> lock(gMsgBufMutex);
890 if (gMsgBuf.empty())
891 break;
892 e = gMsgBuf.front();
893 gMsgBuf.pop_front();
894 // implicit unlock
895 }
896
897 /* log message */
898 cm_msg_log(e.message_type, "midas", e.message.c_str());
899
900 /* send message to SYSMSG */
901 int status = cm_msg_send_event(e.ts, e.message_type, e.message.c_str());
902 if (status != CM_SUCCESS)
903 return status;
904 }
905
906 return CM_SUCCESS;
907}
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 765 of file midas.cxx.

766{
767 /* strip path */
768 const char* pc = filename + strlen(filename);
769 while (*pc != '\\' && *pc != '/' && pc != filename)
770 pc--;
771 if (pc != filename)
772 pc++;
773
774 /* convert type to string */
775 std::string type_str;
776 if (message_type & MT_ERROR)
777 type_str += MT_ERROR_STR;
778 if (message_type & MT_INFO)
779 type_str += MT_INFO_STR;
780 if (message_type & MT_DEBUG)
781 type_str += MT_DEBUG_STR;
782 if (message_type & MT_USER)
783 type_str += MT_USER_STR;
784 if (message_type & MT_LOG)
785 type_str += MT_LOG_STR;
786 if (message_type & MT_TALK)
787 type_str += MT_TALK_STR;
788
789 std::string message;
790
791 /* print client name into string */
792 if (message_type == MT_USER)
793 message = msprintf("[%s] ", routine);
794 else {
795 std::string name = rpc_get_name();
796 if (name.length() > 0)
797 message = msprintf("[%s,%s] ", name.c_str(), type_str.c_str());
798 else
799 message = "";
800 }
801
802 /* preceed error messages with file and line info */
803 if (message_type == MT_ERROR) {
804 message += msprintf("[%s:%d:%s,%s] ", pc, line, routine, type_str.c_str());
805 } else if (message_type == MT_USER) {
806 message = msprintf("[%s,%s] ", routine, type_str.c_str());
807 }
808
809 int bufsize = 1024;
810 char* buf = (char*)malloc(bufsize);
811 assert(buf);
812
813 for (int i=0; i<10; i++) {
814 va_list ap;
815 va_copy(ap, *argptr);
816
817 /* print argument list into message */
818 int n = vsnprintf(buf, bufsize-1, format, ap);
819
820 //printf("vsnprintf [%s] %d %d\n", format, bufsize, n);
821
822 va_end(ap);
823
824 if (n < bufsize) {
825 break;
826 }
827
828 bufsize += 100;
829 bufsize *= 2;
830 buf = (char*)realloc(buf, bufsize);
831 assert(buf);
832 }
833
834 message += buf;
835 free(buf);
836
837 return message;
838}
#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:13215
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 553 of file midas.cxx.

553 {
554 HNDLE hDB;
555 int status;
556
558
559 // check for call to cm_msg() before MIDAS is fully initialized
560 // or after MIDAS is partially shutdown.
561 if (status != CM_SUCCESS) {
562 if (filename)
563 *filename = std::string(fac) + ".log";
564 if (linkname)
565 *linkname = "";
566 if (linktarget)
567 *linktarget = "";
568 return;
569 }
570
571 if (filename)
572 *filename = "";
573 if (linkname)
574 *linkname = "";
575 if (linktarget)
576 *linktarget = "";
577
578 std::string facility;
579 if (fac && fac[0])
580 facility = fac;
581 else
582 facility = "midas";
583
584 std::string message_format;
585 db_get_value_string(hDB, 0, "/Logger/Message file date format", 0, &message_format, TRUE);
586 if (message_format.find('%') != std::string::npos) {
587 /* replace stings such as %y%m%d with current date */
588 struct tm tms;
589
590 ss_tzset();
591 if (t == 0)
592 time(&t);
593 localtime_r(&t, &tms);
594
595 char de[256];
596 de[0] = '_';
597 strftime(de + 1, sizeof(de)-1, strchr(message_format.c_str(), '%'), &tms);
598 message_format = de;
599 }
600
601 std::string message_dir;
602 db_get_value_string(hDB, 0, "/Logger/Message dir", 0, &message_dir, TRUE);
603 if (message_dir.empty()) {
604 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &message_dir, FALSE);
605 if (message_dir.empty()) {
606 message_dir = cm_get_path();
607 if (message_dir.empty()) {
608 message_dir = ss_getcwd();
609 }
610 }
611 }
612
613 // prepend experiment directory
614 if (message_dir[0] != DIR_SEPARATOR)
615 message_dir = cm_get_path() + message_dir;
616
617 if (message_dir.back() != DIR_SEPARATOR)
618 message_dir.push_back(DIR_SEPARATOR);
619
620 if (filename)
621 *filename = message_dir + facility + message_format + ".log";
622 if (!message_format.empty()) {
623 if (linkname)
624 *linkname = message_dir + facility + ".log";
625 if (linktarget)
626 *linktarget = facility + message_format + ".log";
627 }
628}
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3027
std::string cm_get_path()
Definition midas.cxx:1553
std::string ss_getcwd()
Definition system.cxx:5848
void ss_tzset()
Definition system.cxx:3427
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:13967
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 678 of file midas.cxx.

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

488 {
489 //printf("cm_msg_open_buffer!\n");
490 if (_msg_buffer == 0) {
492 if (status != BM_SUCCESS && status != BM_CREATED) {
493 return status;
494 }
495 }
496 return CM_SUCCESS;
497}
INT bm_open_buffer(const char *buffer_name, INT buffer_size, INT *buffer_handle)
Definition midas.cxx:6728
#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 1067 of file midas.cxx.

1067 {
1068 INT status, id;
1069
1070 // we should only come here after the message buffer
1071 // was opened by cm_connect_experiment()
1072 assert(_msg_buffer);
1073
1074 _msg_dispatch = func;
1075
1077
1078 return status;
1079}
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:8476
#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 1350 of file midas.cxx.

1350 {
1351 int status;
1352 char *messages = NULL;
1353 int num_messages = 0;
1354
1355 if (rpc_is_remote())
1356 return rpc_call(RPC_CM_MSG_RETRIEVE, n_message, message, buf_size);
1357
1358 status = cm_msg_retrieve2("midas", 0, n_message, &messages, &num_messages);
1359
1360 if (messages) {
1361 mstrlcpy(message, messages, buf_size);
1362 int len = strlen(messages);
1363 if (len > buf_size)
1365 free(messages);
1366 }
1367
1368 return status;
1369}
#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:1280
#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 1112 of file midas.cxx.

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

1280 {
1281 std::string filename, linkname;
1282 INT n, i;
1283 time_t filedate;
1284 int length = 0;
1285 int allocated = 0;
1286
1287 time(&filedate);
1288 cm_msg_get_logfile(facility, filedate, &filename, &linkname, NULL);
1289
1290 //printf("facility %s, filename \"%s\" \"%s\"\n", facility, filename, linkname);
1291
1292 // see if file exists, use linkname if not
1293 if (!linkname.empty()) {
1294 if (!ss_file_exist(filename.c_str()))
1295 filename = linkname;
1296 }
1297
1298 if (ss_file_exist(filename.c_str())) {
1299 cm_msg_retrieve1(filename.c_str(), t, n_message, messages, &length, &allocated, &n);
1300 } else {
1301 n = 0;
1302 }
1303
1304 /* if there is no symlink, then there is no additional log files to read */
1305 if (linkname.empty()) {
1306 *num_messages = n;
1307 return CM_SUCCESS;
1308 }
1309
1310 //printf("read more messages %d %d!\n", n, n_message);
1311
1312 int missing = 0;
1313 while (n < n_message) {
1314 filedate -= 3600 * 24; // go one day back
1315
1316 cm_msg_get_logfile(facility, filedate, &filename, NULL, NULL);
1317
1318 //printf("read [%s] for time %d!\n", filename.c_str(), filedate);
1319
1320 if (ss_file_exist(filename.c_str())) {
1321 cm_msg_retrieve1(filename.c_str(), t, n_message - n, messages, &length, &allocated, &i);
1322 n += i;
1323 missing = 0;
1324 } else {
1325 missing++;
1326 }
1327
1328 // stop if ten consecutive files are not found
1329 if (missing > 10)
1330 break;
1331 }
1332
1333 *num_messages = n;
1334
1335 return CM_SUCCESS;
1336}
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:1112
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 840 of file midas.cxx.

840 {
841 //printf("cm_msg_send: ts %d, type %d, message [%s]\n", ts, message_type, send_message);
842
843 /* send event if not of type MLOG */
844 if (message_type != MT_LOG) {
845 if (_msg_buffer) {
846 /* copy message to event */
847 size_t len = strlen(send_message);
848 int event_length = sizeof(EVENT_HEADER) + len + 1;
849 char event[event_length];
850 EVENT_HEADER *pevent = (EVENT_HEADER *) event;
851
852 memcpy(event + sizeof(EVENT_HEADER), send_message, len + 1);
853
854 /* setup the event header and send the message */
855 bm_compose_event(pevent, EVENTID_MESSAGE, (WORD) message_type, len + 1, 0);
856 if (ts)
857 pevent->time_stamp = ts;
858 //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)));
859 bm_send_event(_msg_buffer, pevent, 0, BM_WAIT);
860 }
861 }
862
863 return CM_SUCCESS;
864}
INT bm_send_event(INT buffer_handle, const EVENT_HEADER *pevent, int unused, int timeout_msec)
Definition midas.cxx:9689
INT bm_compose_event(EVENT_HEADER *event_header, short int event_id, short int trigger_mask, DWORD data_size, DWORD serial)
Definition midas.cxx:8292
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:7460
INT cm_set_msg_print(INT system_mask, INT user_mask, int(*func)(const char *))
Definition midas.cxx:661
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 661 of file midas.cxx.

661 {
662 _message_mask_system = system_mask;
663 _message_mask_user = user_mask;
664 _message_print = func;
665
666 return BM_SUCCESS;
667}
Here is the caller graph for this function:

Variable Documentation

◆ gMsgBuf

std::deque<msg_buffer_entry> gMsgBuf
static

Definition at line 872 of file midas.cxx.

◆ gMsgBufMutex

std::mutex gMsgBufMutex
static

Definition at line 873 of file midas.cxx.