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

1067  {
1068  int new_message_length = strlen(new_message);
1069  int new_allocated = 1024 + 2 * ((*allocated) + new_message_length);
1070  char buf[100];
1071  int buf_length;
1072 
1073  //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);
1074 
1075  if (*length + new_message_length + 100 > *allocated) {
1076  *messages = (char *) realloc(*messages, new_allocated);
1077  assert(*messages != NULL);
1078  *allocated = new_allocated;
1079  }
1080 
1081  if (*length > 0)
1082  if ((*messages)[(*length) - 1] != '\n') {
1083  (*messages)[*length] = '\n'; // separator between messages
1084  (*length) += 1;
1085  }
1086 
1087  sprintf(buf, "%ld ", tstamp);
1088  buf_length = strlen(buf);
1089  memcpy(&((*messages)[*length]), buf, buf_length);
1090  (*length) += buf_length;
1091 
1092  memcpy(&((*messages)[*length]), new_message, new_message_length);
1093  (*length) += new_message_length;
1094  (*messages)[*length] = 0; // make sure string is NUL terminated
1095 }
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 457 of file midas.cxx.

458 {
459  for (int i = 0; _error_table[i].code; i++) {
460  if (_error_table[i].code == code) {
461  return _error_table[i].string;
462  }
463  }
464 
465  return msprintf("unlisted status code %d", code);
466 }
INT i
Definition: mdump.cxx:35
static const ERROR_TABLE _error_table[]
Definition: midas.cxx:272
std::string msprintf(const char *format,...)
Definition: midas.cxx:412
const char * string
Definition: midas.cxx:269
INT code
Definition: midas.cxx:268
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:566
MY my
Definition: mdsupport.cxx:95
#define message(type, str)
Definition: midas_macro.h:262
DWORD status
Definition: odbhist.cxx:39
double d
Definition: system.cxx:1317
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 917 of file midas.cxx.

918 {
919  DWORD ts = ss_time();
920 
921  /* print argument list into message */
922  std::string message;
923  va_list argptr;
924  va_start(argptr, format);
925  message = cm_msg_format(message_type, filename, line, routine, format, &argptr);
926  va_end(argptr);
927 
928  //printf("message [%s]\n", message);
929 
930  /* call user function if set via cm_set_msg_print */
932  if (f != NULL && (message_type & _message_mask_user) != 0) {
933  if (message_type != MT_LOG) { // do not print MLOG messages
934  (*f)(message.c_str());
935  }
936  }
937 
938  /* return if system mask is not set */
939  if ((message_type & _message_mask_system) == 0) {
940  return CM_SUCCESS;
941  }
942 
943  gMsgBufMutex.lock();
944  gMsgBuf.push_back(msg_buffer_entry{ts, message_type, message});
945  gMsgBufMutex.unlock();
946 
947  return CM_SUCCESS;
948 }
TRIGGER_SETTINGS ts
Definition: fevmemodules.c:102
#define CM_SUCCESS
Definition: midas.h:588
unsigned int DWORD
Definition: mcstd.h:51
#define MT_LOG
Definition: midas.h:552
DWORD ss_time()
Definition: system.cxx:3401
static std::mutex gMsgBufMutex
Definition: midas.cxx:859
static std::deque< msg_buffer_entry > gMsgBuf
Definition: midas.cxx:858
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:753
static std::atomic_int _message_mask_system
Definition: midas.cxx:437
int(* MessagePrintCallback)(const char *)
Definition: midas.cxx:433
static std::atomic< MessagePrintCallback > _message_print
Definition: midas.cxx:435
static std::atomic_int _message_mask_user
Definition: midas.cxx:438
Definition: midas.cxx:852
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:975
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 975 of file midas.cxx.

976  {
977  va_list argptr;
978  std::string message;
979  static BOOL in_routine = FALSE;
980 
981  /* avoid recursive calles */
982  if (in_routine)
983  return 0;
984 
985  in_routine = TRUE;
986 
987  /* print argument list into message */
988  va_start(argptr, format);
989  message = cm_msg_format(message_type, filename, line, routine, format, &argptr);
990  va_end(argptr);
991 
992  /* call user function if set via cm_set_msg_print */
994  if (f != NULL && (message_type & _message_mask_user) != 0)
995  (*f)(message.c_str());
996 
997  /* return if system mask is not set */
998  if ((message_type & _message_mask_system) == 0) {
999  in_routine = FALSE;
1000  return CM_SUCCESS;
1001  }
1002 
1003  /* send message to SYSMSG */
1004  cm_msg_send_event(0, message_type, message.c_str());
1005 
1006  /* log message */
1007  cm_msg_log(message_type, facility, message.c_str());
1008 
1009  in_routine = FALSE;
1010 
1011  return CM_SUCCESS;
1012 }
#define FALSE
Definition: cfortran.h:309
INT cm_msg_log(INT message_type, const char *facility, const char *message)
Definition: midas.cxx:666
static INT cm_msg_send_event(DWORD ts, INT message_type, const char *send_message)
Definition: midas.cxx:826
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 489 of file midas.cxx.

489  {
490  //printf("cm_msg_close_buffer!\n");
491  if (_msg_buffer) {
493  _msg_buffer = 0;
494  }
495  return CM_SUCCESS;
496 }
INT bm_close_buffer(INT buffer_handle)
Definition: midas.cxx:7060
static INT _msg_buffer
Definition: midas.cxx:200
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 469 of file midas.cxx.

469  {
470 
471  return CM_SUCCESS;
472 }
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 506 of file midas.cxx.

506  {
507  std::string path;
508 
509  cm_msg_get_logfile("midas", 0, &path, NULL, NULL);
510 
511  /* extract directory name from full path name of midas.log */
512  size_t pos = path.rfind(DIR_SEPARATOR);
513  if (pos != std::string::npos) {
514  path.resize(pos);
515  } else {
516  path = "";
517  }
518 
519  //printf("cm_msg_facilities: path [%s]\n", path.c_str());
520 
521  STRING_LIST flist;
522 
523  ss_file_find(path.c_str(), "*.log", &flist);
524 
525  for (size_t i = 0; i < flist.size(); i++) {
526  const char *p = flist[i].c_str();
527  if (strchr(p, '_') == NULL && !(p[0] >= '0' && p[0] <= '9')) {
528  size_t pos = flist[i].rfind('.');
529  if (pos != std::string::npos) {
530  flist[i].resize(pos);
531  }
532  list->push_back(flist[i]);
533  }
534  }
535 
536  return SUCCESS;
537 }
#define SUCCESS
Definition: mcstd.h:54
INT ss_file_find(const char *path, const char *pattern, char **plist)
Definition: system.cxx:6652
void cm_msg_get_logfile(const char *fac, time_t t, std::string *filename, std::string *linkname, std::string *linktarget)
Definition: midas.cxx:541
#define DIR_SEPARATOR
Definition: midas.h:193
std::vector< std::string > STRING_LIST
Definition: midas.h:253
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 867 of file midas.cxx.

867  {
868  int i;
869 
870  //printf("cm_msg_flush_buffer!\n");
871 
872  for (i = 0; i < 100; i++) {
874  {
875  std::lock_guard<std::mutex> lock(gMsgBufMutex);
876  if (gMsgBuf.empty())
877  break;
878  e = gMsgBuf.front();
879  gMsgBuf.pop_front();
880  // implicit unlock
881  }
882 
883  /* log message */
884  cm_msg_log(e.message_type, "midas", e.message.c_str());
885 
886  /* send message to SYSMSG */
887  int status = cm_msg_send_event(e.ts, e.message_type, e.message.c_str());
888  if (status != CM_SUCCESS)
889  return status;
890  }
891 
892  return CM_SUCCESS;
893 }
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 753 of file midas.cxx.

754 {
755  /* strip path */
756  const char* pc = filename + strlen(filename);
757  while (*pc != '\\' && *pc != '/' && pc != filename)
758  pc--;
759  if (pc != filename)
760  pc++;
761 
762  /* convert type to string */
763  std::string type_str;
764  if (message_type & MT_ERROR)
765  type_str += MT_ERROR_STR;
766  if (message_type & MT_INFO)
767  type_str += MT_INFO_STR;
768  if (message_type & MT_DEBUG)
769  type_str += MT_DEBUG_STR;
770  if (message_type & MT_USER)
771  type_str += MT_USER_STR;
772  if (message_type & MT_LOG)
773  type_str += MT_LOG_STR;
774  if (message_type & MT_TALK)
775  type_str += MT_TALK_STR;
776 
777  std::string message;
778 
779  /* print client name into string */
780  if (message_type == MT_USER)
781  message = msprintf("[%s] ", routine);
782  else {
783  std::string name = rpc_get_name();
784  if (name.length() > 0)
785  message = msprintf("[%s,%s] ", name.c_str(), type_str.c_str());
786  else
787  message = "";
788  }
789 
790  /* preceed error messages with file and line info */
791  if (message_type == MT_ERROR) {
792  message += msprintf("[%s:%d:%s,%s] ", pc, line, routine, type_str.c_str());
793  } else if (message_type == MT_USER) {
794  message = msprintf("[%s,%s] ", routine, type_str.c_str());
795  }
796 
797  int bufsize = 1024;
798  char* buf = (char*)malloc(bufsize);
799  assert(buf);
800 
801  for (int i=0; i<10; i++) {
802  va_list ap;
803  va_copy(ap, *argptr);
804 
805  /* print argument list into message */
806  int n = vsnprintf(buf, bufsize-1, format, ap);
807 
808  //printf("vsnprintf [%s] %d %d\n", format, bufsize, n);
809 
810  if (n < bufsize) {
811  break;
812  }
813 
814  bufsize += 100;
815  bufsize *= 2;
816  buf = (char*)realloc(buf, bufsize);
817  assert(buf);
818  }
819 
820  message += buf;
821  free(buf);
822 
823  return message;
824 }
#define MT_LOG_STR
Definition: midas.h:561
#define MT_INFO_STR
Definition: midas.h:558
#define MT_INFO
Definition: midas.h:549
#define MT_DEBUG_STR
Definition: midas.h:559
#define MT_TALK
Definition: midas.h:553
#define MT_USER
Definition: midas.h:551
#define MT_USER_STR
Definition: midas.h:560
#define MT_TALK_STR
Definition: midas.h:562
#define MT_DEBUG
Definition: midas.h:550
#define MT_ERROR
Definition: midas.h:548
#define MT_ERROR_STR
Definition: midas.h:557
std::string rpc_get_name()
Definition: midas.cxx:13051
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 541 of file midas.cxx.

541  {
542  HNDLE hDB;
543  int status;
544 
546 
547  // check for call to cm_msg() before MIDAS is fully initialized
548  // or after MIDAS is partially shutdown.
549  if (status != CM_SUCCESS) {
550  if (filename)
551  *filename = std::string(fac) + ".log";
552  if (linkname)
553  *linkname = "";
554  if (linktarget)
555  *linktarget = "";
556  return;
557  }
558 
559  if (filename)
560  *filename = "";
561  if (linkname)
562  *linkname = "";
563  if (linktarget)
564  *linktarget = "";
565 
566  std::string facility;
567  if (fac && fac[0])
568  facility = fac;
569  else
570  facility = "midas";
571 
572  std::string message_format;
573  db_get_value_string(hDB, 0, "/Logger/Message file date format", 0, &message_format, TRUE);
574  if (message_format.find('%') != std::string::npos) {
575  /* replace stings such as %y%m%d with current date */
576  struct tm tms;
577 
578  ss_tzset();
579  if (t == 0)
580  time(&t);
581  localtime_r(&t, &tms);
582 
583  char de[256];
584  de[0] = '_';
585  strftime(de + 1, sizeof(de)-1, strchr(message_format.c_str(), '%'), &tms);
586  message_format = de;
587  }
588 
589  std::string message_dir;
590  db_get_value_string(hDB, 0, "/Logger/Message dir", 0, &message_dir, TRUE);
591  if (message_dir.empty()) {
592  db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &message_dir, FALSE);
593  if (message_dir.empty()) {
594  message_dir = cm_get_path();
595  if (message_dir.empty()) {
596  message_dir = ss_getcwd();
597  }
598  }
599  }
600 
601  // prepend experiment directory
602  if (message_dir[0] != DIR_SEPARATOR)
603  message_dir = cm_get_path() + message_dir;
604 
605  if (message_dir.back() != DIR_SEPARATOR)
606  message_dir.push_back(DIR_SEPARATOR);
607 
608  if (filename)
609  *filename = message_dir + facility + message_format + ".log";
610  if (!message_format.empty()) {
611  if (linkname)
612  *linkname = message_dir + facility + ".log";
613  if (linktarget)
614  *linktarget = facility + message_format + ".log";
615  }
616 }
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition: midas.cxx:3005
INT cm_get_path(char *path, int path_size)
Definition: midas.cxx:1520
std::string ss_getcwd()
Definition: system.cxx:5709
void ss_tzset()
Definition: system.cxx:3294
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:13937
HNDLE hDB
main ODB handle
Definition: mana.cxx:207
INT HNDLE
Definition: midas.h:132
MUTEX_T * tm
Definition: odbedit.cxx:42
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 666 of file midas.cxx.

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

476  {
477  //printf("cm_msg_open_buffer!\n");
478  if (_msg_buffer == 0) {
480  if (status != BM_SUCCESS && status != BM_CREATED) {
481  return status;
482  }
483  }
484  return CM_SUCCESS;
485 }
INT bm_open_buffer(const char *buffer_name, INT buffer_size, INT *buffer_handle)
Definition: midas.cxx:6681
#define BM_SUCCESS
Definition: midas.h:611
#define BM_CREATED
Definition: midas.h:612
#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 1053 of file midas.cxx.

1053  {
1054  INT status, id;
1055 
1056  // we should only come here after the message buffer
1057  // was opened by cm_connect_experiment()
1058  assert(_msg_buffer);
1059 
1060  _msg_dispatch = func;
1061 
1063 
1064  return status;
1065 }
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:8431
#define GET_NONBLOCKING
Definition: midas.h:329
#define TRIGGER_ALL
Definition: midas.h:544
#define EVENTID_ALL
Definition: midas.h:543
static EVENT_HANDLER * _msg_dispatch
Definition: midas.cxx:201
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 1336 of file midas.cxx.

1336  {
1337  int status;
1338  char *messages = NULL;
1339  int num_messages = 0;
1340 
1341  if (rpc_is_remote())
1342  return rpc_call(RPC_CM_MSG_RETRIEVE, n_message, message, buf_size);
1343 
1344  status = cm_msg_retrieve2("midas", 0, n_message, &messages, &num_messages);
1345 
1346  if (messages) {
1347  strlcpy(message, messages, buf_size);
1348  int len = strlen(messages);
1349  if (len > buf_size)
1350  status = CM_TRUNCATED;
1351  free(messages);
1352  }
1353 
1354  return status;
1355 }
#define CM_TRUNCATED
Definition: midas.h:602
INT cm_msg_retrieve2(const char *facility, time_t t, INT n_message, char **messages, int *num_messages)
Definition: midas.cxx:1266
#define RPC_CM_MSG_RETRIEVE
Definition: mrpc.h:32
size_t EXPRT strlcpy(char *dst, const char *src, size_t size)
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 1098 of file midas.cxx.

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

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

826  {
827  //printf("cm_msg_send: ts %d, type %d, message [%s]\n", ts, message_type, send_message);
828 
829  /* send event if not of type MLOG */
830  if (message_type != MT_LOG) {
831  if (_msg_buffer) {
832  /* copy message to event */
833  size_t len = strlen(send_message);
834  int event_length = sizeof(EVENT_HEADER) + len + 1;
835  char event[event_length];
836  EVENT_HEADER *pevent = (EVENT_HEADER *) event;
837 
838  memcpy(event + sizeof(EVENT_HEADER), send_message, len + 1);
839 
840  /* setup the event header and send the message */
841  bm_compose_event(pevent, EVENTID_MESSAGE, (WORD) message_type, len + 1, 0);
842  if (ts)
843  pevent->time_stamp = ts;
844  //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)));
845  bm_send_event(_msg_buffer, pevent, 0, BM_WAIT);
846  }
847  }
848 
849  return CM_SUCCESS;
850 }
INT bm_send_event(INT buffer_handle, const EVENT_HEADER *pevent, int unused, int timeout_msec)
Definition: midas.cxx:9645
INT bm_compose_event(EVENT_HEADER *event_header, short int event_id, short int trigger_mask, DWORD data_size, DWORD serial)
Definition: midas.cxx:8246
unsigned short int WORD
Definition: mcstd.h:49
#define BM_WAIT
Definition: midas.h:372
#define EVENTID_MESSAGE
Definition: midas.h:908
DWORD time_stamp
Definition: midas.h:861
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:555
void ss_printf(INT x, INT y, const char *format,...)
Definition: system.cxx:7321
INT cm_set_msg_print(INT system_mask, INT user_mask, int(*func)(const char *))
Definition: midas.cxx:649
static int message_print(const char *msg)
Definition: mfe.cxx:1370
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 649 of file midas.cxx.

649  {
650  _message_mask_system = system_mask;
651  _message_mask_user = user_mask;
652  _message_print = func;
653 
654  return BM_SUCCESS;
655 }
Here is the caller graph for this function:

Variable Documentation

◆ gMsgBuf

std::deque<msg_buffer_entry> gMsgBuf
static

Definition at line 858 of file midas.cxx.

◆ gMsgBufMutex

std::mutex gMsgBufMutex
static

Definition at line 859 of file midas.cxx.