MIDAS
Loading...
Searching...
No Matches
mlogger.cxx
Go to the documentation of this file.
1/********************************************************************\
2
3 Name: mlogger.cxx
4 Created by: Stefan Ritt
5
6 Contents: MIDAS logger program
7
8 $Id$
9
10\********************************************************************/
11
12#undef NDEBUG // midas required assert() to be always enabled
13
14#include "midas.h"
15#include "msystem.h"
16#include "hardware.h"
17#include "mstrlcpy.h"
18#include <errno.h> /* for mkdir() */
19#include <assert.h>
20#include <string>
21
22#define HAVE_LOGGING
23#include "mdsupport.h"
24
25#ifdef HAVE_ROOT
26#undef GetCurrentTime
27#include "TApplication.h"
28#include "TFile.h"
29#include "TNtuple.h"
30#include "TLeaf.h"
31//#warning HAVE_ROOT!
32//#else
33//#warning NO HAVE_ROOT!
34#endif
35
36#ifdef OS_WINNT
37#define ZLIB_WINAPI
38#endif
39#include <zlib.h>
40
41#ifdef HAVE_MYSQL
42#ifdef OS_UNIX
43#include <mysql.h>
44#include <mysqld_error.h>
45#endif
46#ifdef OS_WINNT
47#include <mysql.h>
48#include <mysqld_error.h>
49int errno; // under NT, "ignore libcd" is required, so errno has to be defined here
50#endif
52#endif
53
56
57static std::string IntToString(int value)
58{
59 char buf[256];
60 sprintf(buf, "%d", value);
61 return buf;
62}
63
64static std::string TimeToString(time_t t)
65{
66 const char* sign = "";
67
68 if (t == 0)
69 return "0";
70
71 time_t tt = t;
72
73 if (t < 0) {
74 sign = "-";
75 tt = -t;
76 }
77
78 assert(tt > 0);
79
80 std::string v;
81 while (tt) {
82 char c = '0' + tt%10;
83 tt /= 10;
84 v = c + v;
85 }
86
87 v = sign + v;
88
89 //printf("time %.0f -> %s\n", (double)t, v.c_str());
90
91 return v;
92}
93
94/*---- Logging channel information ---------------------------------*/
95
96// NOTE: [Settings] here MUST be exactly same as CHN_SETTINGS_STR below
97
98#define CHN_TREE_STR(_name) const char *_name[] = {\
99"[Settings]",\
100"Active = BOOL : 1",\
101"Type = STRING : [8] Disk",\
102"Filename = STRING : [256] run%05d.mid",\
103"Format = STRING : [8] MIDAS",\
104"Compression = INT32 : 0",\
105"ODB dump = BOOL : 1",\
106"ODB dump format = STRING : [32] json",\
107"Options ODB dump format = STRING[3] :",\
108"[32] odb",\
109"[32] xml",\
110"[32] json",\
111"Log messages = UINT32 : 0",\
112"Buffer = STRING : [32] SYSTEM",\
113"Event ID = INT32 : -1",\
114"Trigger mask = INT32 : -1",\
115"Event limit = DOUBLE : 0",\
116"Byte limit = DOUBLE : 0",\
117"Subrun Byte limit = DOUBLE : 0",\
118"Tape capacity = DOUBLE : 0",\
119"Subdir format = STRING : [32]",\
120"Current filename = STRING : [256]",\
121"Data checksum = STRING : [256] CRC32C",\
122"Options Data checksum = STRING[5] :",\
123"[32] NONE",\
124"[32] CRC32C",\
125"[32] SHA256",\
126"[32] SHA512",\
127"[32] ZLIB",\
128"File checksum = STRING : [256] CRC32C",\
129"Options File checksum = STRING[5] :",\
130"[32] NONE",\
131"[32] CRC32C",\
132"[32] SHA256",\
133"[32] SHA512",\
134"[32] ZLIB",\
135"Compress = STRING : [256] lz4",\
136"Options Compress = STRING[5] :",\
137"[32] none",\
138"[32] gzip",\
139"[32] lz4",\
140"[32] bzip2",\
141"[32] pbzip2",\
142"Output = STRING : [256] FILE",\
143"Options Output = STRING[5] :",\
144"[32] NULL",\
145"[32] FILE",\
146"[32] FTP",\
147"[32] ROOT",\
148"[32] PIPE",\
149"Gzip compression = UINT32 : 0",\
150"Bzip2 compression = UINT32 : 0",\
151"Pbzip2 num cpu = UINT32 : 0",\
152"Pbzip2 compression = UINT32 : 0",\
153"Pbzip2 options = STRING : [256]",\
154"",\
155"[Statistics]",\
156"Events written = DOUBLE : 0",\
157"Bytes written = DOUBLE : 0",\
158"Bytes written uncompressed = DOUBLE : 0",\
159"Bytes written total = DOUBLE : 0",\
160"Bytes written subrun = DOUBLE : 0",\
161"Files written = DOUBLE : 0",\
162"Disk level = DOUBLE : 0",\
163"",\
164NULL}
165
166typedef struct {
168 char obsolete_type[8];
169 char filename[256];
170 char obsolete_format[8];
173 char odb_dump_format[32];
174 char options_odb_dump_format[3][32];
176 char buffer[32];
183 char subdir_format[32];
184 char current_filename[256];
185 char data_checksum[256];
186 char options_data_checksum[5][32];
187 char file_checksum[256];
188 char options_file_checksum[5][32];
189 char compress[256];
190 char options_compress[5][32];
191 char output[256];
192 char options_output[5][32];
197 char pbzip2_options[256];
199
200// NOTE: CHN_SETTINGS here MUST be exactly same as [Settings] in CHN_TREE_STR above.
201
202#define CHN_SETTINGS_STR(_name) const char *_name[] = { \
203"Active = BOOL : 1",\
204"Type = STRING : [8] Disk",\
205"Filename = STRING : [256] run%05d.mid",\
206"Format = STRING : [8] MIDAS",\
207"Compression = INT32 : 0",\
208"ODB dump = BOOL : 1",\
209"ODB dump format = STRING : [32] json",\
210"Log messages = UINT32 : 0",\
211"Buffer = STRING : [32] SYSTEM",\
212"Event ID = INT32 : -1",\
213"Trigger mask = INT32 : -1",\
214"Event limit = DOUBLE : 0",\
215"Byte limit = DOUBLE : 0",\
216"Subrun Byte limit = DOUBLE : 0",\
217"Tape capacity = DOUBLE : 0",\
218"Subdir format = STRING : [32]",\
219"Current filename = STRING : [256]",\
220"Data checksum = STRING : [256]",\
221"File checksum = STRING : [256]",\
222"Compress = STRING : [256]",\
223"Output = STRING : [256]",\
224"Gzip compression = UINT32 : 0",\
225"Bzip2 compression = UINT32 : 0",\
226"Pbzip2 num cpu = UINT32 : 0",\
227"Pbzip2 compression = UINT32 : 0",\
228"Pbzip2 options = STRING : [256]",\
229"",\
230NULL}
231
233 double events_written = 0; /* count events, reset in tr_start() */
234 double bytes_written = 0; /* count bytes written out (compressed), reset in tr_start() */
235 double bytes_written_uncompressed = 0; /* count bytes before compression, reset in tr_start() */
236 double bytes_written_total = 0; /* count bytes written out (compressed), reset in log_callback(RPC_LOG_REWIND) */
237 double bytes_written_subrun = 0; /* count bytes written out (compressed), reset in tr_start() and on subrun increment */
238 double files_written = 0; /* incremented in log_close(), reset in log_callback(RPC_LOG_REWIND) */
239 double disk_level = 0;
240};
241
242#define CHN_STATISTICS_STR(_name) const char *_name[] = {\
243"Events written = DOUBLE : 0",\
244"Bytes written = DOUBLE : 0",\
245"Bytes written uncompressed = DOUBLE : 0",\
246"Bytes written total = DOUBLE : 0",\
247"Bytes written subrun = DOUBLE : 0",\
248"Files written = DOUBLE : 0",\
249"Disk level = DOUBLE : 0",\
250"",\
251NULL}
252
253/*---- logger channel definition---------------------------------------*/
254
255class WriterInterface;
256struct MIDAS_INFO;
257#ifdef HAVE_ROOT
258struct TREE_STRUCT;
259#endif
260
261struct LOG_CHN {
262 std::string name;
264 std::string path;
265 std::string pipe_command;
267#ifdef OBSOLETE
268 INT format = 0;
269 INT compression = 0;
270#endif
281#ifdef HAVE_ROOT
283#endif
284#ifdef OBSOLETE
286 void *gzfile = NULL;
287 FILE *pfile = NULL;
288#endif
289 void *ftp_con = NULL;
290 void *pfile = NULL;
294 int pre_checksum_module = 0; // CHECKSUM_xxx
295 int compression_module = 0; // COMPRESS_xxx
296 int post_checksum_module = 0; // CHECKSUM_xxx
297 int output_module = 0; // OUTPUT_xxx
298};
299
301{
302 LOG_CHN* chn = new LOG_CHN;
303 chn->name = name;
304 // chn->settings clear settings
305 return chn;
306};
307
308/*---- globals -----------------------------------------------------*/
309
310#define DISK_CHECK_INTERVAL_MILLISEC 10000
311
320double stop_try_later = 0;
321
322std::vector<LOG_CHN*> log_channels;
323
333
334static int hist_log_size = 0;
335static int hist_log_max = 0;
336static struct hist_log_s *hist_log = NULL;
337
338static HNDLE hDB;
339
340/*---- ODB records -------------------------------------------------*/
341
345
346/*---- data structures for MIDAS format ----------------------------*/
347
349 char *buffer;
351};
352
353/*---- forward declarations ----------------------------------------*/
354
355void receive_event(HNDLE hBuf, HNDLE request_id, EVENT_HEADER * pheader, void *pevent);
359extern void start_image_history();
360extern void stop_image_history();
362
363/*== common code FAL/MLOGGER start =================================*/
364
365#define MEMZERO(obj) memset(&(obj), 0, sizeof(obj))
366
367#define FREE(ptr) if (ptr) free(ptr); (ptr)=NULL;
368#define DELETE(ptr) if (ptr) delete (ptr); (ptr)=NULL;
369
370/*---- writer helper --------------------------------------------*/
371
372static std::string xpathname(const char* xpath, int level)
373{
374 std::string path = xpath;
375 while (level > 0) {
376 size_t p = path.rfind(".");
377 //printf("level %d, path [%s], pos %d\n", level, path.c_str(), (int)p);
378 if (p == std::string::npos)
379 break;
380 path = path.substr(0, p);
381 level--;
382 }
383 return path;
384}
385
386static FILE* fopen_wx(const char* filename)
387{
388 int fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IRGRP|S_IROTH);
389 if (fd == -1)
390 return NULL;
391 return fdopen(fd, "w");
392}
393
394static bool check_file_exists(const char* filename)
395{
396 struct stat st;
397 int status = stat(filename, &st);
398 if (status == -1) {
399 return false;
400 }
401 return true;
402}
403
404/*---- writer interface --------------------------------------------*/
405
407{
408public:
409 virtual int wr_open(LOG_CHN* log_chn, int run_number) = 0;
410 virtual int wr_write(LOG_CHN* log_chn, const void* data, const int size) = 0;
411 virtual int wr_close(LOG_CHN* log_chn, int run_number) = 0;
412 WriterInterface(); // base ctor
413 virtual ~WriterInterface() {}; // dtor
414 virtual std::string wr_get_file_ext() { return ""; }
415 virtual std::string wr_get_chain() = 0;
416public:
417 bool fTrace; // enable tracing printout
418 double fBytesIn; // count bytes in (before compression)
419 double fBytesOut; // count bytes out (after compression)
420};
421
423{
424 //fTrace = true; // <------ to enable (disable) tracing printout, set to "true" ("false")
425 fTrace = false; // <------ to enable (disable) tracing printout, set to "true" ("false")
426 fBytesIn = 0;
427 fBytesOut = 0;
428
429 if (fTrace)
430 printf("WriterInterface: default constructor!\n");
431}
432
433/*---- Null writer ------------------------------------------------*/
434
436{
437public:
439 {
440 if (fTrace)
441 printf("WriterNull: path [%s]\n", log_chn->path.c_str());
442 fSimulateCompression = false;
443 }
444
445 ~WriterNull() // dtor
446 {
447 if (fTrace)
448 printf("WriterNull: destructor\n");
449 }
450
452 {
453 if (fTrace)
454 printf("WriterNull: open path [%s]\n", log_chn->path.c_str());
455 fBytesIn = 0;
456 fBytesOut = 0;
457 log_chn->handle = 9999;
459 fBytesOut += 10; // simulate compression header
460 return SUCCESS;
461 }
462
463 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
464 {
465 if (fTrace)
466 printf("WriterNull: write path [%s], size %d\n", log_chn->path.c_str(), size);
467 fBytesIn += size;
469 fBytesOut += size/3; // simulate compression
470 else
471 fBytesOut += size;
472 return SUCCESS;
473 }
474
476 {
477 if (fTrace)
478 printf("WriterNull: close path [%s]\n", log_chn->path.c_str());
480 fBytesOut += 20; // simulate compression footer
481 log_chn->handle = 0;
482 return SUCCESS;
483 }
484
485 std::string wr_get_file_ext()
486 {
487 return ".null";
488 }
489
490 std::string wr_get_chain()
491 {
492 return "NULL";
493 }
494
495private:
497};
498
499/*---- file writer -------------------------------------------------*/
500
502{
503public:
505 {
506 if (fTrace)
507 printf("WriterFile: path [%s]\n", log_chn->path.c_str());
508 fFileno = -1;
509 }
510
511 ~WriterFile() // dtor
512 {
513 if (fTrace)
514 printf("WriterFile: destructor\n");
515 fFileno = -1;
516 }
517
519 {
520 fBytesIn = 0;
521 fBytesOut = 0;
522
523 if (fTrace)
524 printf("WriterFile: open path [%s]\n", log_chn->path.c_str());
525
526 assert(fFileno < 0);
527
528 if (check_file_exists(log_chn->path.c_str()))
529 return SS_FILE_EXISTS;
530
531#ifdef OS_WINNT
533#else
534 fFileno = open(log_chn->path.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_BINARY | O_LARGEFILE, 0444);
535#endif
536 if (fFileno < 0) {
537 cm_msg(MERROR, "WriterFile::wr_open", "Cannot write to file \'%s\', open() errno %d (%s)", log_chn->path.c_str(), errno, strerror(errno));
538 return SS_FILE_ERROR;
539 }
540
541 log_chn->handle = fFileno;
542
543 fFilename = log_chn->path;
544 return SUCCESS;
545 }
546
547 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
548 {
549 if (fTrace)
550 printf("WriterFile: write path [%s], size %d\n", log_chn->path.c_str(), size);
551
552 if (size == 0)
553 return SUCCESS;
554
555 assert(fFileno >= 0);
556
557 fBytesIn += size;
558
559 int wr = write(fFileno, data, size);
560
561 if (wr > 0)
562 fBytesOut += wr;
563
564 if (wr != size) {
565 cm_msg(MERROR, "WriterFile::wr_write", "Cannot write to file \'%s\', write(%d) returned %d, errno: %d (%s)", log_chn->path.c_str(), size, wr, errno, strerror(errno));
566 return SS_FILE_ERROR;
567 }
568
569 return SUCCESS;
570 }
571
573 {
574 int err;
575
576 if (fTrace)
577 printf("WriterFile: close path [%s]\n", log_chn->path.c_str());
578
579 assert(fFileno >= 0);
580
581 log_chn->handle = 0;
582
583 err = close(fFileno);
584 fFileno = -1;
585
586 if (err != 0) {
587 cm_msg(MERROR, "WriterFile::wr_close", "Cannot write to file \'%s\', close() errno %d (%s)", log_chn->path.c_str(), errno, strerror(errno));
588 return SS_FILE_ERROR;
589 }
590
591 return SUCCESS;
592 }
593
594 std::string wr_get_chain()
595 {
596 return ">" + fFilename;
597 }
598
599private:
600 std::string fFilename;
602};
603
604/*---- gzip writer -------------------------------------------------*/
605
606#include <zlib.h>
607
609{
610public:
612 {
613 if (fTrace)
614 printf("WriterGzip: path [%s]\n", log_chn->path.c_str());
615 fGzfp = 0;
616 if (log_chn->settings.gzip_compression) {
617 fCompress = log_chn->settings.gzip_compression;
618 } else {
620 }
621 fLastCheckTime = time(NULL);
622 }
623
624 ~WriterGzip() // dtor
625 {
626 if (fTrace)
627 printf("WriterGzip: destructor\n");
628 assert(fGzfp == 0);
629 }
630
632 {
633 int zerror;
634
635 fBytesIn = 0;
636 fBytesOut = 0;
637
638 if (fTrace)
639 printf("WriterGzip: open path [%s]\n", log_chn->path.c_str());
640
641 assert(fGzfp == 0);
642
643 if (check_file_exists(log_chn->path.c_str()))
644 return SS_FILE_EXISTS;
645
646 fGzfp = gzopen(log_chn->path.c_str(), "wb");
647 if (fGzfp == 0) {
648 cm_msg(MERROR, "WriterGzip::wr_open", "Cannot write to file \'%s\', gzopen() errno %d (%s)", log_chn->path.c_str(), errno, strerror(errno));
649 return SS_FILE_ERROR;
650 }
651
652 chmod(log_chn->path.c_str(), 0444);
653
654 //printf("WriterGzip::wr_open: compress %d\n", fCompress);
655
656 if (fCompress) {
658 if (zerror != Z_OK) {
659 cm_msg(MERROR, "WriterGzip::wr_open", "gzsetparams() zerror %d", zerror);
660 return SS_FILE_ERROR;
661 }
662 }
663
664#if ZLIB_VERNUM > 0x1235
665 // gzbuffer() added in zlib 1.2.3.5 (8 Jan 2010)
666 zerror = gzbuffer(fGzfp, 128*1024);
667 if (zerror != Z_OK) {
668 cm_msg(MERROR, "WriterGzip::wr_open", "gzbuffer() zerror %d", zerror);
669 return SS_FILE_ERROR;
670 }
671#else
672#warning Very old zlib, no gzbuffer()!
673#endif
674
675 log_chn->handle = 8888;
676
677 fFilename = log_chn->path;
678 return SUCCESS;
679 }
680
681 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
682 {
683 if (fTrace)
684 printf("WriterGzip: write path [%s], size %d\n", log_chn->path.c_str(), size);
685
686 if (size == 0)
687 return SUCCESS;
688
689 assert(fGzfp);
690
691 fBytesIn += size;
692
693 int wr = gzwrite(fGzfp, data, size);
694
695 if (wr != size) {
696 cm_msg(MERROR, "WriterGzip::wr_write", "Cannot write to file \'%s\', gzwrite(%d) returned %d, errno: %d (%s)", log_chn->path.c_str(), size, wr, errno, strerror(errno));
697 return SS_FILE_ERROR;
698 }
699
700#if ZLIB_VERNUM > 0x1235
701 // gzoffset() added in zlib 1.2.3.5 (8 Jan 2010)
703#else
704#warning Very old zlib, no gzoffset()!
705 time_t now = time(NULL);
706 if (now - fLastCheckTime > 2) {
708 fBytesOut = ss_file_size(log_chn->path.c_str());
709 }
710#endif
711
712 return SUCCESS;
713 }
714
716 {
717 int zerror;
718
719 if (fTrace)
720 printf("WriterGzip: close path [%s]\n", log_chn->path.c_str());
721
722 assert(fGzfp);
723
724 log_chn->handle = 0;
725
727
728 if (zerror != Z_OK) {
729 cm_msg(MERROR, "WriterGzip::wr_close", "Cannot write to file \'%s\', gzflush(Z_FINISH) zerror %d, errno: %d (%s)", log_chn->path.c_str(), zerror, errno, strerror(errno));
730 return SS_FILE_ERROR;
731 }
732
734 fGzfp = 0;
735
736 if (zerror != Z_OK) {
737 cm_msg(MERROR, "WriterGzip::wr_close", "Cannot write to file \'%s\', gzclose() zerror %d, errno: %d (%s)", log_chn->path.c_str(), zerror, errno, strerror(errno));
738 return SS_FILE_ERROR;
739 }
740
741 fBytesOut = ss_file_size(log_chn->path.c_str());
742
743 return SUCCESS;
744 }
745
746 std::string wr_get_file_ext()
747 {
748 return ".gz";
749 }
750
751 std::string wr_get_chain()
752 {
753 return "gzip > " + fFilename;
754 }
755
756private:
757 std::string fFilename;
761};
762
763/*---- pipe writer -------------------------------------------------*/
764
766{
767public:
768 WriterPopen(LOG_CHN* log_chn, const char* pipe_command, const char* file_ext) // ctor
769 {
770 if (fTrace)
771 printf("WriterPopen: path [%s]\n", log_chn->path.c_str());
772 fFp = NULL;
773 fPipeCommand = pipe_command;
775 fLastCheckTime = time(NULL);
776 }
777
778 ~WriterPopen() // dtor
779 {
780 if (fTrace)
781 printf("WriterPopen: destructor\n");
782 if (fFp)
783 pclose(fFp);
784 fFp = NULL;
785 }
786
788 {
789 fBytesIn = 0;
790 fBytesOut = 0;
791
792 if (fTrace)
793 printf("WriterPopen: open path [%s] pipe [%s] ext [%s]\n", log_chn->path.c_str(), fPipeCommand.c_str(), fFileExt.c_str());
794
795 assert(fFp == NULL);
796
797 if (check_file_exists(log_chn->path.c_str()))
798 return SS_FILE_EXISTS;
799
800#ifdef OS_WINNT
801 // sorry no popen?!?
802 return SS_FILE_ERROR;
803#else
804 fCommand = fPipeCommand + log_chn->path;
805
806 fFp = popen(fCommand.c_str(), "w");
807 if (fFp == NULL) {
808 cm_msg(MERROR, "WriterPopen::wr_open", "Cannot write to pipe \'%s\', popen() errno %d (%s)", fCommand.c_str(), errno, strerror(errno));
809 return SS_FILE_ERROR;
810 }
811
812 log_chn->handle = 9999;
813
814 return SUCCESS;
815#endif
816 }
817
818 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
819 {
820 if (fTrace)
821 printf("WriterPopen: write path [%s], size %d\n", log_chn->path.c_str(), size);
822
823 if (size == 0)
824 return SUCCESS;
825
826 if (fFp == NULL) {
827 return SS_FILE_ERROR;
828 }
829
830 fBytesIn += size;
831
832 int wr = fwrite(data, 1, size, fFp);
833
834 //if (wr > 0)
835 //fBytesOut += wr;
836
837 if (wr != size) {
838 cm_msg(MERROR, "WriterPopen::wr_write", "Cannot write to pipe \'%s\', fwrite(%d) returned %d, errno %d (%s)", fCommand.c_str(), size, wr, errno, strerror(errno));
839
840 if (errno == EPIPE) {
841 cm_msg(MERROR, "WriterPopen::wr_write", "Cannot write to pipe \'%s\': broken pipe, closing the pipe", fCommand.c_str());
842 wr_close(log_chn, 0);
843 }
844
845 return SS_FILE_ERROR;
846 }
847
848 time_t now = time(NULL);
849 if (now - fLastCheckTime > 2) {
851 fBytesOut = ss_file_size(log_chn->path.c_str());
852 }
853
854 return SUCCESS;
855 }
856
858 {
859 int err;
860
861 if (fTrace)
862 printf("WriterPopen: close path [%s]\n", log_chn->path.c_str());
863
864 assert(fFp != NULL);
865
866 log_chn->handle = 0;
867
868#ifdef OS_WINNT
869 // sorry no popen?!?
870 return SS_FILE_ERROR;
871#else
872 err = pclose(fFp);
873 fFp = NULL;
874
875 if (err != 0) {
876 cm_msg(MERROR, "WriterPopen::wr_close", "Cannot write to pipe \'%s\', pclose() returned %d, errno %d (%s)", fCommand.c_str(), err, errno, strerror(errno));
877 return SS_FILE_ERROR;
878 }
879
880 chmod(log_chn->path.c_str(), 0444);
881
882 fBytesOut = ss_file_size(log_chn->path.c_str());
883
884 return SUCCESS;
885#endif
886 }
887
888 std::string wr_get_file_ext()
889 {
890 return fFileExt;
891 }
892
893 std::string wr_get_chain()
894 {
895 return fPipeCommand;
896 }
897
898private:
900 std::string fPipeCommand;
901 std::string fCommand;
902 std::string fFileExt;
904};
905
906/*---- CRC32-ZLIB computation --------------------------------------*/
907
908#include <zlib.h>
909
911{
912public:
914 {
915 if (fTrace)
916 printf("WriterCRC32Zlib: path [%s], level %d\n", log_chn->path.c_str(), level);
917
918 assert(wr != NULL);
919
920 fLevel = level;
921 fWr = wr;
922 fCrc32 = 0;
923 }
924
926 {
927 if (fTrace)
928 printf("WriterCRC32Zlib: destructor\n");
929 DELETE(fWr);
930 }
931
933 {
934 int status;
935
936 if (fTrace)
937 printf("WriterCRC32Zlib: open path [%s], level %d\n", log_chn->path.c_str(), fLevel);
938
940
941 fBytesIn += 0;
943
944 if (status != SUCCESS) {
945 return status;
946 }
947
948 log_chn->handle = 9999;
949
950 fCrc32 = crc32(0, Z_NULL, 0);
951
952 return SUCCESS;
953 }
954
955 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
956 {
957 if (fTrace)
958 printf("WriterCRC32Zlib: write path [%s], size %d\n", log_chn->path.c_str(), size);
959
960 fCrc32 = crc32(fCrc32, (const Bytef*)data, size);
961
962 int status = fWr->wr_write(log_chn, data, size);
963
964 fBytesIn += size;
966
967 if (status != SUCCESS) {
968 return status;
969 }
970
971 return SUCCESS;
972 }
973
975 {
976 std::string x = xpathname(log_chn->path.c_str(), fLevel);
977 std::string f = x + ".crc32zlib";
978
979 if (fTrace)
980 printf("WriterCRC32Zlib: close path [%s], level %d, file [%s]\n", log_chn->path.c_str(), fLevel, f.c_str());
981
982 log_chn->handle = 0;
983
984 cm_msg(MLOG, "CRC32Zlib", "File \'%s\' CRC32-zlib checksum: 0x%08lx, %.0f bytes", x.c_str(), (unsigned long)fCrc32, fBytesIn);
985
986 FILE *fp = fopen_wx(f.c_str());
987 if (!fp) {
988 cm_msg(MERROR, "WriterCRC32Zlib::wr_close", "Cannot write CRC32Zlib to file \'%s\', fopen() errno %d (%s)", f.c_str(), errno, strerror(errno));
989 } else {
990 fprintf(fp, "%08lx %.0f %s\n", (unsigned long)fCrc32, fBytesIn, x.c_str());
991 fclose(fp);
992 }
993
994 /* close downstream writer */
995
997
998 fBytesIn += 0;
1000
1001 if (status != SUCCESS) {
1002 return status;
1003 }
1004
1005 return SUCCESS;
1006 }
1007
1008 std::string wr_get_file_ext() {
1009 return fWr->wr_get_file_ext();
1010 }
1011
1012 std::string wr_get_chain() {
1013 return "CRC32ZLIB | " + fWr->wr_get_chain();
1014 }
1015
1016private:
1020};
1021
1022/*---- CRC32C computation ------------------------------------------*/
1023
1024#include "crc32c.h"
1025
1027{
1028public:
1030 {
1031 if (fTrace)
1032 printf("WriterCRC32C: path [%s], level %d\n", log_chn->path.c_str(), level);
1033
1034 assert(wr != NULL);
1035
1036 fLevel = level;
1037 fWr = wr;
1038 fCrc32 = 0;
1039 }
1040
1042 {
1043 if (fTrace)
1044 printf("WriterCRC32C: destructor\n");
1045 DELETE(fWr);
1046 }
1047
1049 {
1050 int status;
1051
1052 if (fTrace)
1053 printf("WriterCRC32C: open path [%s], level %d\n", log_chn->path.c_str(), fLevel);
1054
1056
1057 fBytesIn += 0;
1059
1060 if (status != SUCCESS) {
1061 return status;
1062 }
1063
1064 log_chn->handle = 9999;
1065
1066 fCrc32 = 0;
1067
1068 return SUCCESS;
1069 }
1070
1071 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
1072 {
1073 if (fTrace)
1074 printf("WriterCRC32C: write path [%s], size %d\n", log_chn->path.c_str(), size);
1075
1076 fCrc32 = crc32c(fCrc32, data, size);
1077
1078 int status = fWr->wr_write(log_chn, data, size);
1079
1080 fBytesIn += size;
1082
1083 if (status != SUCCESS) {
1084 return status;
1085 }
1086
1087 return SUCCESS;
1088 }
1089
1091 {
1092 std::string x = xpathname(log_chn->path.c_str(), fLevel);
1093 std::string f = x + ".crc32c";
1094
1095 if (fTrace)
1096 printf("WriterCRC32C: close path [%s], level %d, file [%s]\n", log_chn->path.c_str(), fLevel, f.c_str());
1097
1098 log_chn->handle = 0;
1099
1100 cm_msg(MLOG, "CRC32C", "File \'%s\' CRC32C checksum: 0x%08lx, %.0f bytes", x.c_str(), (unsigned long)fCrc32, fBytesIn);
1101
1102 FILE *fp = fopen_wx(f.c_str());
1103 if (!fp) {
1104 cm_msg(MERROR, "WriterCRC32C::wr_close", "Cannot write CRC32C to file \'%s\', fopen() errno %d (%s)", f.c_str(), errno, strerror(errno));
1105 } else {
1106 fprintf(fp, "%08lx %.0f %s\n", (unsigned long)fCrc32, fBytesIn, x.c_str());
1107 fclose(fp);
1108 }
1109
1110 /* close downstream writer */
1111
1113
1114 fBytesIn += 0;
1116
1117 if (status != SUCCESS) {
1118 return status;
1119 }
1120
1121 return SUCCESS;
1122 }
1123
1124 std::string wr_get_file_ext() {
1125 return fWr->wr_get_file_ext();
1126 }
1127
1128 std::string wr_get_chain() {
1129 return "CRC32C | " + fWr->wr_get_chain();
1130 }
1131
1132private:
1136};
1137
1138/*---- SHA-256 computation -----------------------------------------*/
1139
1140#include "sha256.h"
1141
1143{
1144public:
1146 {
1147 if (fTrace)
1148 printf("WriterSHA256: path [%s], level %d\n", log_chn->path.c_str(), level);
1149
1150 assert(wr != NULL);
1151
1152 fLevel = level;
1153 fWr = wr;
1154
1156 }
1157
1159 {
1160 if (fTrace)
1161 printf("WriterSHA256: destructor\n");
1162 DELETE(fWr);
1163
1165 }
1166
1168 {
1169 int status;
1170
1171 if (fTrace)
1172 printf("WriterSHA256: open path [%s], level %d\n", log_chn->path.c_str(), fLevel);
1173
1175
1176 fBytesIn += 0;
1178
1179 if (status != SUCCESS) {
1180 return status;
1181 }
1182
1183 log_chn->handle = 9999;
1184
1185 mbedtls_sha256_starts(&fCtx, 0); // 2nd argument selects 0=SHA-256 vs 1=SHA-224
1186
1187 return SUCCESS;
1188 }
1189
1190 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
1191 {
1192 if (fTrace)
1193 printf("WriterSHA256: write path [%s], size %d\n", log_chn->path.c_str(), size);
1194
1195 mbedtls_sha256_update(&fCtx, (const unsigned char*)data, size);
1196
1197 int status = fWr->wr_write(log_chn, data, size);
1198
1199 fBytesIn += size;
1201
1202 if (status != SUCCESS) {
1203 return status;
1204 }
1205
1206 return SUCCESS;
1207 }
1208
1209 std::string toHex(unsigned char c)
1210 {
1211 char s[3];
1212 sprintf(s, "%02x", c);
1213 return s;
1214 }
1215
1216 std::string toString(const unsigned char sha256sum[32])
1217 {
1218 std::string s;
1219 for (int i=0; i<32; i++)
1220 s += toHex(sha256sum[i]);
1221 return s;
1222 }
1223
1225 {
1226 std::string x = xpathname(log_chn->path.c_str(), fLevel);
1227 std::string f = x + ".sha256";
1228
1229 if (fTrace)
1230 printf("WriterSHA256: close path [%s], level %d, file [%s]\n", log_chn->path.c_str(), fLevel, f.c_str());
1231
1232 log_chn->handle = 0;
1233
1234 unsigned char sha256sum[32];
1236
1237 //std::string s = toString(sha256sum);
1238 //printf("sha256 %s\n", s.c_str());
1239
1240 cm_msg(MLOG, "SHA256", "File \'%s\' SHA-256 checksum: %s, %.0f bytes", x.c_str(), toString(sha256sum).c_str(), fBytesIn);
1241
1242 FILE *fp = fopen_wx(f.c_str());
1243 if (!fp) {
1244 cm_msg(MERROR, "WriterSHA256::wr_close", "Cannot write SHA-256 checksum to file \'%s\', fopen() errno %d (%s)", f.c_str(), errno, strerror(errno));
1245 } else {
1246 fprintf(fp, "%s %.0f %s\n", toString(sha256sum).c_str(), fBytesIn, x.c_str());
1247 fclose(fp);
1248 }
1249
1250 /* close downstream writer */
1251
1253
1254 fBytesIn += 0;
1256
1257 if (status != SUCCESS) {
1258 return status;
1259 }
1260
1261 return SUCCESS;
1262 }
1263
1264 std::string wr_get_file_ext() {
1265 return fWr->wr_get_file_ext();
1266 }
1267
1268 std::string wr_get_chain() {
1269 return "SHA256 | " + fWr->wr_get_chain();
1270 }
1271
1272private:
1276};
1277
1278/*---- SHA-512 computation -----------------------------------------*/
1279
1280#include "sha512.h"
1281
1283{
1284public:
1286 {
1287 if (fTrace)
1288 printf("WriterSHA512: path [%s], level %d\n", log_chn->path.c_str(), level);
1289
1290 assert(wr != NULL);
1291
1292 fLevel = level;
1293 fWr = wr;
1294
1296 }
1297
1299 {
1300 if (fTrace)
1301 printf("WriterSHA512: destructor\n");
1302 DELETE(fWr);
1303
1305 }
1306
1308 {
1309 int status;
1310
1311 if (fTrace)
1312 printf("WriterSHA512: open path [%s], level %d\n", log_chn->path.c_str(), fLevel);
1313
1315
1316 fBytesIn += 0;
1318
1319 if (status != SUCCESS) {
1320 return status;
1321 }
1322
1323 log_chn->handle = 9999;
1324
1325 mbedtls_sha512_starts(&fCtx, 0); // 2nd argument selects 0=SHA-512 vs 1=SHA-384
1326
1327 return SUCCESS;
1328 }
1329
1330 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
1331 {
1332 if (fTrace)
1333 printf("WriterSHA512: write path [%s], size %d\n", log_chn->path.c_str(), size);
1334
1335 mbedtls_sha512_update(&fCtx, (const unsigned char*)data, size);
1336
1337 int status = fWr->wr_write(log_chn, data, size);
1338
1339 fBytesIn += size;
1341
1342 if (status != SUCCESS) {
1343 return status;
1344 }
1345
1346 return SUCCESS;
1347 }
1348
1349 std::string toHex(unsigned char c)
1350 {
1351 char s[3];
1352 sprintf(s, "%02x", c);
1353 return s;
1354 }
1355
1356 std::string toString(const unsigned char sha512sum[64])
1357 {
1358 std::string s;
1359 for (int i=0; i<64; i++)
1360 s += toHex(sha512sum[i]);
1361 return s;
1362 }
1363
1365 {
1366 std::string x = xpathname(log_chn->path.c_str(), fLevel);
1367 std::string f = x + ".sha512";
1368
1369 if (fTrace)
1370 printf("WriterSHA512: close path [%s], level %d, file [%s]\n", log_chn->path.c_str(), fLevel, f.c_str());
1371
1372 log_chn->handle = 0;
1373
1374 unsigned char sha512sum[64];
1376
1377 //std::string s = toString(sha512sum);
1378 //printf("sha512 %s\n", s.c_str());
1379
1380 cm_msg(MLOG, "SHA512", "File \'%s\' SHA-512 checksum: %s, %.0f bytes", x.c_str(), toString(sha512sum).c_str(), fBytesIn);
1381
1382 FILE *fp = fopen_wx(f.c_str());
1383 if (!fp) {
1384 cm_msg(MERROR, "WriterSHA512::wr_close", "Cannot write SHA-512 checksum to file \'%s\', fopen() errno %d (%s)", f.c_str(), errno, strerror(errno));
1385 } else {
1386 fprintf(fp, "%s %.0f %s\n", toString(sha512sum).c_str(), fBytesIn, x.c_str());
1387 fclose(fp);
1388 }
1389
1390 /* close downstream writer */
1391
1393
1394 fBytesIn += 0;
1396
1397 if (status != SUCCESS) {
1398 return status;
1399 }
1400
1401 return SUCCESS;
1402 }
1403
1404 std::string wr_get_file_ext() {
1405 return fWr->wr_get_file_ext();
1406 }
1407
1408 std::string wr_get_chain() {
1409 return "SHA512 | " + fWr->wr_get_chain();
1410 }
1411
1412private:
1416};
1417
1418/*---- LZ4 compressed writer --------------------------------------*/
1419
1420#include "mlz4frame.h"
1421
1423{
1424public:
1426 {
1427 if (fTrace)
1428 printf("WriterLZ4: path [%s]\n", log_chn->path.c_str());
1429
1430 assert(wr != NULL);
1431
1432 fBuffer = NULL;
1433 fWr = wr;
1434 fBufferSize = 0;
1435 fBlockSize = 0;
1436 }
1437
1438 ~WriterLZ4() // dtor
1439 {
1440 if (fTrace)
1441 printf("WriterLZ4: destructor\n");
1442
1443 FREE(fBuffer);
1444 DELETE(fWr);
1445 }
1446
1448 {
1449 int status;
1451
1452 if (fTrace)
1453 printf("WriterLZ4: open path [%s]\n", log_chn->path.c_str());
1454
1456 if (status != SUCCESS) {
1457 return status;
1458 }
1459
1461 if (MLZ4F_isError(errorCode)) {
1462 cm_msg(MERROR, "WriterLZ4::wr_open", "LZ4F_createCompressionContext() error %d (%s)", (int)errorCode, MLZ4F_getErrorName(errorCode));
1463 return SS_FILE_ERROR;
1464 }
1465
1467 fBlockSize = 4*1024*1024;
1469 fBufferSize *= 2; // kludge
1470 fBuffer = (char*)malloc(fBufferSize);
1471 if (fBuffer == NULL) {
1472 cm_msg(MERROR, "WriterLZ4::wr_open", "Cannot malloc() %d bytes for an LZ4 compression buffer, block size %d, errno %d (%s)", fBufferSize, fBlockSize, errno, strerror(errno));
1473 return SS_FILE_ERROR;
1474 }
1475
1476 MEMZERO(fPrefs);
1477
1478 fPrefs.compressionLevel = 0; // 0=fast, non-zero=???
1479 fPrefs.autoFlush = 0; // ???
1480 fPrefs.frameInfo.contentChecksumFlag = MLZ4F_contentChecksumEnabled;
1481 fPrefs.frameInfo.blockSizeID = blockSizeId;
1482
1484
1487 cm_msg(MERROR, "WriterLZ4::wr_open", "LZ4F_compressBegin() error %d (%s)", (int)errorCode, MLZ4F_getErrorName(errorCode));
1488 return SS_FILE_ERROR;
1489 }
1490
1492
1493 fBytesIn += 0;
1495
1496 if (status != SUCCESS) {
1497 return SS_FILE_ERROR;
1498 }
1499
1500 log_chn->handle = 9999;
1501
1502 return SUCCESS;
1503 }
1504
1505 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
1506 {
1507 const char* ptr = (const char*)data;
1508 int remaining = size;
1509
1510 if (fTrace)
1511 printf("WriterLZ4: write path [%s], size %d\n", log_chn->path.c_str(), size);
1512
1513 while (remaining > 0) {
1514 int wsize = remaining;
1515
1516 if (wsize > fBlockSize)
1517 wsize = fBlockSize;
1518
1520
1521 if (MLZ4F_isError(outSize)) {
1522 int errorCode = outSize;
1523 cm_msg(MERROR, "WriterLZ4::wr_write", "LZ4F_compressUpdate() with %d bytes, block size %d, buffer size %d, write size %d, remaining %d bytes, error %d (%s)", wsize, fBlockSize, fBufferSize, size, remaining, (int)errorCode, MLZ4F_getErrorName(errorCode));
1524 return SS_FILE_ERROR;
1525 }
1526
1527 if (outSize > 0) {
1529
1530 fBytesIn += wsize;
1532
1533 if (status != SUCCESS) {
1534 return SS_FILE_ERROR;
1535 }
1536 }
1537
1538 ptr += wsize;
1539 remaining -= wsize;
1540 }
1541
1542 return SUCCESS;
1543 }
1544
1546 {
1547 int xstatus = SUCCESS;
1549
1550 if (fTrace)
1551 printf("WriterLZ4: close path [%s]\n", log_chn->path.c_str());
1552
1553 log_chn->handle = 0;
1554
1555 /* write End of Stream mark */
1557
1560 cm_msg(MERROR, "WriterLZ4::wr_close", "LZ4F_compressEnd() error %d (%s)", (int)errorCode, MLZ4F_getErrorName(errorCode));
1561 return SS_FILE_ERROR;
1562 }
1563
1565
1566 fBytesIn += 0;
1568
1569 if (status != SUCCESS) {
1570 if (xstatus == SUCCESS)
1571 xstatus = status;
1572 }
1573
1574 /* close downstream writer */
1575
1577
1578 if (status != SUCCESS) {
1579 if (xstatus == SUCCESS)
1580 xstatus = status;
1581 }
1582
1583 /* free resources */
1584
1585 free(fBuffer);
1586 fBuffer = NULL;
1587 fBufferSize = 0;
1588
1590 if (MLZ4F_isError(errorCode)) {
1591 cm_msg(MERROR, "WriterLZ4::wr_close", "LZ4F_freeCompressionContext() error %d (%s)", (int)errorCode, MLZ4F_getErrorName(errorCode));
1592 if (xstatus == SUCCESS)
1594 }
1595
1596 return xstatus;
1597 }
1598
1599 std::string wr_get_file_ext() {
1600 return ".lz4" + fWr->wr_get_file_ext();
1601 }
1602
1603 std::string wr_get_chain() {
1604 return "lz4 | " + fWr->wr_get_chain();
1605 }
1606
1607private:
1611 char* fBuffer;
1614};
1615
1616/*---- Logging initialization --------------------------------------*/
1617
1619{
1620 INT size, status, delay;
1621 BOOL flag;
1623 KEY key;
1624 std::string str;
1625
1626 /*---- create /logger entries -----*/
1627
1628 str = cm_get_path();
1629 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &str, TRUE);
1630
1631 str = "";
1632 db_get_value_string(hDB, 0, "/Logger/Message dir", 0, &str, TRUE);
1633
1634 str = "";
1635 db_get_value_string(hDB, 0, "/Logger/History dir", 0, &str, TRUE);
1636
1637 str = "";
1638 db_get_value_string(hDB, 0, "/Logger/Message file date format", 0, &str, TRUE);
1639
1640 size = sizeof(BOOL);
1641 flag = TRUE;
1642 db_get_value(hDB, 0, "/Logger/Write data", &flag, &size, TID_BOOL, TRUE);
1643
1644 flag = FALSE;
1645 db_get_value(hDB, 0, "/Logger/ODB Dump", &flag, &size, TID_BOOL, TRUE);
1646
1647 str = "run%05d.json";
1648 db_get_value_string(hDB, 0, "/Logger/ODB Dump File", 0, &str, TRUE);
1649
1650 str = "last.json";
1651 db_get_value_string(hDB, 0, "/Logger/ODB Last Dump File", 0, &str, TRUE);
1652
1653 flag = FALSE;
1654 size = sizeof(BOOL);
1655 db_get_value(hDB, 0, "/Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
1656
1657 delay = 0;
1658 size = sizeof(INT);
1659 db_get_value(hDB, 0, "/Logger/Auto restart delay", &delay, &size, TID_INT32, TRUE);
1660
1661 flag = TRUE;
1662 db_get_value(hDB, 0, "/Logger/Tape message", &flag, &size, TID_BOOL, TRUE);
1663
1664 /* create at least one logging channel */
1665 status = db_find_key(hDB, 0, "/Logger/Channels/0", &hKey);
1666 if (status != DB_SUCCESS) {
1667 /* if no channels are defined, define at least one */
1668 status = db_create_record(hDB, 0, "/Logger/Channels/0", strcomb1(chn_tree_str).c_str());
1669 if (status != DB_SUCCESS)
1670 cm_msg(MERROR, "logger_init", "Cannot create channel entry in database");
1671 } else {
1672 /* check format of other channels */
1673 status = db_find_key(hDB, 0, "/Logger/Channels", &hKey);
1674 if (status == DB_SUCCESS) {
1675 for (int index = 0; ; index++) {
1678 break;
1679
1682 if (status != DB_SUCCESS && status != DB_OPEN_RECORD) {
1683 cm_msg(MERROR, "logger_init", "Cannot create/check channel record %s, db_check_record() status %d", key.name, status);
1684 break;
1685 }
1686 }
1687 }
1688 }
1689#ifdef HAVE_MYSQL
1691#endif
1694}
1695
1696/*---- ODB dump routine --------------------------------------------*/
1697
1699{
1700 /* write ODB dump */
1701
1702 static int buffer_size = 100000;
1703
1704 do {
1705 EVENT_HEADER* pevent = (EVENT_HEADER *) malloc(buffer_size);
1706 if (pevent == NULL) {
1707 cm_msg(MERROR, "log_odb_dump", "Cannot allocate ODB dump buffer");
1708 break;
1709 }
1710
1711 int size = buffer_size - sizeof(EVENT_HEADER);
1712 //int status = db_copy_xml(hDB, 0, (char *) (pevent + 1), &size);
1713 int status = db_copy(hDB, 0, (char *) (pevent + 1), &size, "");
1714 if (status != DB_TRUNCATED) {
1715 bm_compose_event(pevent, event_id, MIDAS_MAGIC, buffer_size - sizeof(EVENT_HEADER) - size + 1, run_number);
1716 log_write(log_chn, pevent);
1717 free(pevent);
1718 break;
1719 }
1720
1721 /* increase buffer size if truncated */
1722 free(pevent);
1723 buffer_size *= 10;
1724 } while (1);
1725}
1726
1728{
1729 /* write ODB dump */
1730
1731 static int buffer_size = 100000;
1732
1733 do {
1734 EVENT_HEADER* pevent = (EVENT_HEADER *) malloc(buffer_size);
1735 if (pevent == NULL) {
1736 cm_msg(MERROR, "log_odb_dump", "Cannot allocate ODB dump buffer");
1737 break;
1738 }
1739
1740 int size = buffer_size - sizeof(EVENT_HEADER);
1741 int status = db_copy_xml(hDB, 0, (char *) (pevent + 1), &size, true);
1742
1743 /* following line would dump ODB in old ASCII format instead of XML */
1744 //status = db_copy(hDB, 0, (char *) (pevent + 1), &size, "");
1745 if (status != DB_TRUNCATED) {
1747 log_write(log_chn, pevent);
1748 free(pevent);
1749 break;
1750 }
1751
1752 /* increase buffer size if truncated */
1753 free(pevent);
1754 buffer_size *= 10;
1755 } while (1);
1756}
1757
1759{
1760 /* write ODB dump */
1761
1762 char* buffer = NULL;
1763 int buffer_size = 0;
1764 int buffer_end = 0;
1765
1766 int status = db_copy_json_save(hDB, 0, &buffer, &buffer_size, &buffer_end);
1767
1768 //printf("db_copy_json_save: status %d, buffer_size %d, buffer_end %d\n", status, buffer_size, buffer_end);
1769
1770 if (status == DB_SUCCESS) {
1771 int event_size = sizeof(EVENT_HEADER) + buffer_end;
1773 if (pevent == NULL) {
1774 cm_msg(MERROR, "log_odb_dump", "Cannot allocate ODB dump buffer size %d", event_size);
1775 } else {
1777 memcpy(pevent+1, buffer, buffer_end);
1778 log_write(log_chn, pevent);
1779 free(pevent);
1780 }
1781 }
1782 free(buffer);
1783}
1784
1786{
1787 if (equal_ustring(log_chn->settings.odb_dump_format, "odb")) {
1789 } else if (equal_ustring(log_chn->settings.odb_dump_format, "xml")) {
1791 } else if (equal_ustring(log_chn->settings.odb_dump_format, "json")) {
1793 } else {
1794 cm_msg(MERROR, "log_odb_dump", "Invalid ODB dump format \"%s\" in ODB settings for channel \"%s\". Valid formats are: \"odb\", \"xml\", \"json\"", log_chn->settings.odb_dump_format, log_chn->name.c_str());
1795 }
1796}
1797
1798/*---- ODB save routine --------------------------------------------*/
1799
1800void odb_save(const char *filename, bool make_file_readonly)
1801{
1802 std::string path;
1803
1804 if (strchr(filename, DIR_SEPARATOR) == NULL) {
1805 db_get_value_string(hDB, 0, "/Logger/Data Dir", 0, &path, TRUE, 256);
1806 if (path.length() > 0) {
1807 if (!ends_with_char(path, DIR_SEPARATOR)) {
1808 path += DIR_SEPARATOR_STR;
1809 }
1810 }
1811 path += filename;
1812 } else {
1813 path = filename;
1814 }
1815
1816 //printf("filename [%s] path [%s]\n", filename, path.c_str());
1817
1818 DWORD t0 = ss_millitime();
1819
1820 if (ends_with_ustring(filename, ".xml"))
1821 db_save_xml(hDB, 0, path.c_str());
1822 else if (ends_with_ustring(filename, ".json"))
1823 db_save_json(hDB, 0, path.c_str());
1824 else
1825 db_save(hDB, 0, path.c_str(), FALSE);
1826
1828 chmod(path.c_str(), 0444);
1829
1830 DWORD te = ss_millitime();
1831
1832 if (verbose)
1833 printf("saved odb to \"%s\" in %d ms\n", path.c_str(), te-t0);
1834}
1835
1836
1837#ifdef HAVE_MYSQL
1838
1839static void xwrite(const char* filename, int fd, const void* data, int size)
1840{
1841 int wr = write(fd, data, size);
1842 if (wr != size) {
1843 cm_msg(MERROR, "xwrite", "cannot write to \'%s\', write(%d) returned %d, errno %d (%s)", filename, size, wr, errno, strerror(errno));
1844 }
1845}
1846
1847/*==== SQL routines ================================================*/
1848
1849/*---- Convert ctime() type date/time to SQL 'datetime' ------------*/
1850
1851typedef struct {
1852 char column_name[NAME_LENGTH];
1854 char data[256];
1855} SQL_LIST;
1856
1857static const char *mname[] = {
1858 "January",
1859 "February",
1860 "March",
1861 "April",
1862 "May",
1863 "June",
1864 "July",
1865 "August",
1866 "September",
1867 "October",
1868 "November",
1869 "December"
1870};
1871
1872void ctime_to_datetime(char *date)
1873{
1874 char ctime_date[30];
1875 struct tm tms;
1876 int i;
1877
1879 memset(&tms, 0, sizeof(struct tm));
1880
1881 for (i = 0; i < 12; i++)
1882 if (strncmp(ctime_date + 4, mname[i], 3) == 0)
1883 break;
1884 tms.tm_mon = i;
1885
1886 tms.tm_mday = atoi(ctime_date + 8);
1887 tms.tm_hour = atoi(ctime_date + 11);
1888 tms.tm_min = atoi(ctime_date + 14);
1889 tms.tm_sec = atoi(ctime_date + 17);
1890 tms.tm_year = atoi(ctime_date + 20) - 1900;
1891 tms.tm_isdst = -1;
1892
1893 if (tms.tm_year < 90)
1894 tms.tm_year += 100;
1895
1896 ss_mktime(&tms);
1897 sprintf(date, "%d-%02d-%02d %02d-%02d-%02d",
1898 tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday, tms.tm_hour, tms.tm_min, tms.tm_sec);
1899}
1900
1901/*---- mySQL debugging output --------------------------------------*/
1902
1903int mysql_query_debug(MYSQL * db, const char *query)
1904{
1905 int status, fh;
1906 std::string filename;
1907 std::string path;
1908 std::string dir;
1909 HNDLE hKey;
1910
1911 /* comment in this line if you need debugging output */
1912 //cm_msg(MINFO, "mysql_query_debug", "SQL query: %s", query);
1913
1914 /* write query into logfile if requested */
1915 filename = "";
1916 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Logfile", 0, &filename, TRUE);
1917 if (!filename.empty()) {
1918 status = db_find_key(hDB, 0, "/Logger/Data dir", &hKey);
1919 if (status == DB_SUCCESS) {
1920 dir = "";
1921 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &dir, TRUE);
1922 if (!dir.empty())
1923 if (dir.back() != DIR_SEPARATOR)
1924 dir += DIR_SEPARATOR_STR;
1925
1926 path = dir + filename;
1927 } else {
1928 std::string dir = cm_get_path();
1929 if (!dir.empty())
1930 if (dir.back() != DIR_SEPARATOR)
1931 dir += DIR_SEPARATOR_STR;
1932
1933 path = dir + filename;
1934 }
1935
1936 fh = open(path.c_str(), O_WRONLY | O_CREAT | O_APPEND | O_LARGEFILE, 0644);
1937 if (fh < 0) {
1938 printf("Cannot open message log file \'%s\', open() returned %d, errno %d (%s)\n", path.c_str(),
1939 fh, errno, strerror(errno));
1940 } else {
1941 xwrite(path.c_str(), fh, query, strlen(query));
1942 xwrite(path.c_str(), fh, ";\n", 2);
1943 close(fh);
1944 }
1945 }
1946
1947 /* execut sql query */
1948 status = mysql_query(db, query);
1949
1950 if (status)
1951 cm_msg(MERROR, "mysql_query_debug", "SQL error: %s", mysql_error(db));
1952
1953 return status;
1954}
1955
1956/*---- Retrieve list of columns from ODB tree ----------------------*/
1957
1959{
1960 HNDLE hKey;
1961 int n, i, status;
1962 KEY key;
1963
1964 for (i = 0;; i++) {
1967 break;
1968 }
1969
1970 if (i == 0)
1971 return 0;
1972
1973 n = i;
1974
1975 *sql_list = (SQL_LIST *) malloc(sizeof(SQL_LIST) * n);
1976
1977 for (i = 0; i < n; i++) {
1978
1979 /* get name of link, NOT of link target */
1981 db_get_link(hDB, hKey, &key);
1982 mstrlcpy((*sql_list)[i].column_name, key.name, NAME_LENGTH);
1983
1984 /* get key */
1986 db_get_key(hDB, hKey, &key);
1987
1988 /* get key data */
1989 int size = key.total_size;
1990 char* data = (char*)malloc(size);
1991 assert(data);
1992 db_get_data(hDB, hKey, data, &size, key.type);
1993 char str[1000];
1994 std::string s = db_sprintf(data, size, 0, key.type);
1995 mstrlcpy(str, s.c_str(), sizeof(str));
1996 //printf("AAA key %s size %d %d [%s]\n", key.name, key.total_size, (int)strlen(str), str);
1997 assert(strlen(str) < sizeof(str));
1998 free(data);
1999 if (key.type == TID_BOOL)
2000 strcpy((*sql_list)[i].data, str[0] == 'y' || str[0] == 'Y' ? "1" : "0");
2001 else
2002 strcpy((*sql_list)[i].data, str);
2003
2004 if (key.type == TID_STRING) {
2005 /* check if string is date/time */
2006 if (strlen(str) == 24 && str[10] == ' ' && str[13] == ':') {
2007 strcpy(str, "DATETIME");
2009 } else if (key.item_size < 256)
2010 sprintf(str, "VARCHAR (%d)", key.item_size);
2011 else
2012 sprintf(str, " TEXT");
2013
2014 } else {
2015 switch (key.type) {
2016 case TID_UINT8:
2017 strcpy(str, "TINYINT UNSIGNED ");
2018 break;
2019 case TID_INT8:
2020 strcpy(str, "TINYINT ");
2021 break;
2022 case TID_CHAR:
2023 strcpy(str, "CHAR ");
2024 break;
2025 case TID_UINT16:
2026 strcpy(str, "SMALLINT UNSIGNED ");
2027 break;
2028 case TID_INT16:
2029 strcpy(str, "SMALLINT ");
2030 break;
2031 case TID_UINT32:
2032 strcpy(str, "INT UNSIGNED ");
2033 break;
2034 case TID_INT32:
2035 strcpy(str, "INT ");
2036 break;
2037 case TID_BOOL:
2038 strcpy(str, "BOOLEAN ");
2039 break;
2040 case TID_FLOAT:
2041 strcpy(str, "FLOAT ");
2042 break;
2043 case TID_DOUBLE:
2044 strcpy(str, "DOUBLE ");
2045 break;
2046 default:
2047 cm_msg(MERROR, "sql_create_database",
2048 "No SQL type mapping for key \"%s\" of type %s", key.name, rpc_tid_name(key.type));
2049 }
2050 }
2051
2052 strcpy((*sql_list)[i].column_type, str);
2053 }
2054
2055 return n;
2056}
2057
2058/*---- Create mySQL table from ODB tree ----------------------------*/
2059
2060BOOL sql_create_table(MYSQL * db, char *database, char *table, HNDLE hKeyRoot)
2061{
2063
2064 std::string query = msprintf("CREATE TABLE `%s`.`%s` (", database, table);
2065
2067 if (n_col == 0) {
2068 std::string path = db_get_path(hDB, hKeyRoot);
2069 cm_msg(MERROR, "sql_create_database", "ODB tree \"%s\" contains no variables", path.c_str());
2070 return FALSE;
2071 }
2072
2073 for (int i = 0; i < n_col; i++) {
2074 query += msprintf("`%s` %s NOT NULL, ", sql_list[i].column_name, sql_list[i].column_type);
2075 }
2076
2077 query += msprintf("PRIMARY KEY (`%s`))", sql_list[0].column_name);
2078 free(sql_list);
2079
2080 if (mysql_query_debug(db, query.c_str())) {
2081 cm_msg(MERROR, "sql_create_table", "Failed to create table: Error: %s", mysql_error(db));
2082 return FALSE;
2083 }
2084
2085 return TRUE;
2086}
2087
2088/*---- Create mySQL table from ODB tree ----------------------------*/
2089
2090BOOL sql_modify_table(MYSQL * db, char *database, char *table, HNDLE hKeyRoot)
2091{
2093
2095 if (n_col == 0) {
2096 std::string path = db_get_path(hDB, hKeyRoot);
2097 cm_msg(MERROR, "sql_modify_table", "ODB tree \"%s\" contains no variables", path.c_str());
2098 return FALSE;
2099 }
2100
2101 for (int i = 0; i < n_col; i++) {
2102 std::string query;
2103
2104 /* try to add column */
2105 if (i == 0) {
2106 query = msprintf("ALTER TABLE `%s`.`%s` ADD `%s` %s", database, table, sql_list[i].column_name, sql_list[i].column_type);
2107 } else {
2108 query = msprintf("ALTER TABLE `%s`.`%s` ADD `%s` %s AFTER `%s`",
2109 database, table,
2110 sql_list[i].column_name,
2112 sql_list[i - 1].column_name);
2113 }
2114
2115 if (mysql_query_debug(db, query.c_str())) {
2117
2118 /* try to modify column */
2119 query = msprintf("ALTER TABLE `%s`.`%s` MODIFY `%s` %s", database, table, sql_list[i].column_name, sql_list[i].column_type);
2120
2121 if (mysql_query_debug(db, query.c_str())) {
2122 free(sql_list);
2123 cm_msg(MERROR, "sql_modify_table", "Failed to modify column: Error: %s", mysql_error(db));
2124 return FALSE;
2125 }
2126
2127 } else {
2128 free(sql_list);
2129 cm_msg(MERROR, "sql_modify_table", "Failed to add column: Error: %s", mysql_error(db));
2130 return FALSE;
2131 }
2132 }
2133 }
2134
2135 cm_msg(MINFO, "sql_insert", "SQL table '%s.%s' modified successfully", database, table);
2136
2137 return TRUE;
2138}
2139
2140/*---- Create mySQL database ---------------------------------------*/
2141
2143{
2144 std::string query = msprintf("CREATE DATABASE `%s`", database);
2145 if (mysql_query_debug(db, query.c_str())) {
2146 cm_msg(MERROR, "sql_create_database", "Failed to create database: Error: %s", mysql_error(db));
2147 return FALSE;
2148 }
2149
2150 /* select database */
2151 query = msprintf("USE `%s`", database);
2152 if (mysql_query_debug(db, query.c_str())) {
2153 cm_msg(MERROR, "sql_create_database", "Failed to select database: Error: %s", mysql_error(db));
2154 return FALSE;
2155 }
2156
2157 return TRUE;
2158}
2159
2160/*---- Insert table row from ODB tree ------------------------------*/
2161
2162int sql_insert(MYSQL * db, char *database, char *table, HNDLE hKeyRoot, BOOL create_flag)
2163{
2165
2166 /*
2167 build SQL query in the form
2168 "INSERT INTO `<table>` (`<name>`, <name`,..) VALUES (`<value>`, `value`, ...)
2169 */
2170 std::string query = msprintf("INSERT INTO `%s`.`%s` (", database, table);
2172 if (n_col == 0)
2173 return DB_SUCCESS;
2174
2175 for (int i = 0; i < n_col; i++) {
2176 query += msprintf("`%s`", sql_list[i].column_name);
2177 if (i < n_col - 1) {
2178 query += ", ";
2179 }
2180 }
2181
2182 query += ") VALUES (";
2183
2184 for (int i = 0; i < n_col; i++) {
2185 query += "'";
2186
2187 size_t len = strlen(sql_list[i].data);
2188 char str[len*2+1];
2190 query += str;
2191 query += "'";
2192
2193 if (i < n_col - 1) {
2194 query += ", ";
2195 }
2196 }
2197
2198 free(sql_list);
2199 sql_list = NULL;
2200 query += ")";
2201 if (mysql_query_debug(db, query.c_str())) {
2202
2203 /* if entry for this run exists alreay return */
2204 if (mysql_errno(db) == ER_DUP_ENTRY) {
2205
2206 return ER_DUP_ENTRY;
2207
2208 } else if (mysql_errno(db) == ER_NO_SUCH_TABLE && create_flag) {
2209
2210 /* if table does not exist, creat it and try again */
2212 if (mysql_query_debug(db, query.c_str())) {
2213 cm_msg(MERROR, "sql_insert", "Failed to update database: Error: %s", mysql_error(db));
2214 return mysql_errno(db);
2215 }
2216 cm_msg(MINFO, "sql_insert", "SQL table '%s.%s' created successfully", database, table);
2217
2218 } else if (mysql_errno(db) == ER_BAD_FIELD_ERROR && create_flag) {
2219
2220 /* if table structure is different, adjust it and try again */
2222 if (mysql_query_debug(db, query.c_str())) {
2223 cm_msg(MERROR, "sql_insert", "Failed to update database: Error: %s", mysql_error(db));
2224 return mysql_errno(db);
2225 }
2226
2227 } else {
2228 int status = mysql_errno(db);
2229 cm_msg(MERROR, "sql_insert", "Failed to update database: Errno: %d, Error: %s", status, mysql_error(db));
2230 return mysql_errno(db);
2231 }
2232 }
2233
2234 return DB_SUCCESS;
2235}
2236
2237/*---- Update table row from ODB tree ------------------------------*/
2238
2239int sql_update(MYSQL * db, char *database, char *table, HNDLE hKeyRoot, BOOL create_flag, char *where)
2240{
2242
2243 /*
2244 build SQL query in the form
2245 "UPDATE `<database`.`<table>` SET `<name>`='<value', ... WHERE `<name>`='value'
2246 */
2247
2248 std::string query = msprintf("UPDATE `%s`.`%s` SET ", database, table);
2250 if (n_col == 0)
2251 return DB_SUCCESS;
2252
2253 for (int i = 0; i < n_col; i++) {
2254 size_t len = strlen(sql_list[i].data);
2255 char str[2*len+1]; // see https://dev.mysql.com/doc/c-api/8.0/en/mysql-real-escape-string.html
2257 query += msprintf("`%s`='%s'", sql_list[i].column_name, str);
2258 if (i < n_col - 1) {
2259 query += ", ";
2260 }
2261 }
2262 free(sql_list);
2263 sql_list = NULL;
2264
2265 query += msprintf(" %s", where);
2266 if (mysql_query_debug(db, query.c_str())) {
2268
2269 /* if table does not exist, creat it and try again */
2271 return sql_insert(db, database, table, hKeyRoot, create_flag);
2272
2273 } else if (mysql_errno(db) == ER_BAD_FIELD_ERROR && create_flag) {
2274
2275 /* if table structure is different, adjust it and try again */
2277 if (mysql_query_debug(db, query.c_str())) {
2278 cm_msg(MERROR, "sql_update", "Failed to update database: Error: %s", mysql_error(db));
2279 return mysql_errno(db);
2280 }
2281
2282 } else {
2283 cm_msg(MERROR, "sql_update", "Failed to update database: Error: %s", mysql_error(db));
2284 return mysql_errno(db);
2285 }
2286 }
2287
2288 return DB_SUCCESS;
2289}
2290
2291/*---- Create /Logger/Runlog/SQL tree ------------------------------*/
2292
2294{
2295 char hostname[80], username[80], password[80], table[80], filename[80];
2296 int size, write_flag, create_flag;
2298
2299 size = sizeof(create_flag);
2300 create_flag = 0;
2301 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Create database", &create_flag, &size, TID_BOOL, TRUE);
2302
2303 size = sizeof(write_flag);
2304 write_flag = 0;
2305 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Write data", &write_flag, &size, TID_BOOL, TRUE);
2306
2307 size = sizeof(hostname);
2308 strcpy(hostname, "localhost");
2309 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Hostname", hostname, &size, TID_STRING, TRUE);
2310
2311 size = sizeof(username);
2312 strcpy(username, "root");
2313 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Username", username, &size, TID_STRING, TRUE);
2314
2315 size = sizeof(password);
2316 password[0] = 0;
2317 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Password", password, &size, TID_STRING, TRUE);
2318
2319 /* use experiment name as default database name */
2320 std::string database;
2321 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &database, TRUE);
2322 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Database", 0, &database, TRUE);
2323
2324 size = sizeof(table);
2325 strcpy(table, "Runlog");
2326 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Table", table, &size, TID_STRING, TRUE);
2327
2328 size = sizeof(filename);
2329 strcpy(filename, "sql.log");
2330 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Logfile", filename, &size, TID_STRING, TRUE);
2331
2332 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links BOR", &hKeyRoot);
2333 if (!hKeyRoot) {
2334 /* create some default links */
2335 db_create_key(hDB, 0, "/Logger/Runlog/SQL/Links BOR", TID_KEY);
2336
2337 if (db_find_key(hDB, 0, "/Runinfo/Run number", &hKey) == DB_SUCCESS)
2338 db_create_link(hDB, 0, "/Logger/Runlog/SQL/Links BOR/Run number", "/Runinfo/Run number");
2339
2340 if (db_find_key(hDB, 0, "/Experiment/Run parameters/Comment", &hKey) == DB_SUCCESS)
2341 db_create_link(hDB, 0, "/Logger/Runlog/SQL/Links BOR/Comment", "/Experiment/Run parameters/Comment");
2342
2343 if (db_find_key(hDB, 0, "/Runinfo/Start time", &hKey) == DB_SUCCESS)
2344 db_create_link(hDB, 0, "/Logger/Runlog/SQL/Links BOR/Start time", "/Runinfo/Start time");
2345 }
2346
2347 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links EOR", &hKeyRoot);
2348 if (!hKeyRoot) {
2349 /* create some default links */
2350 db_create_key(hDB, 0, "/Logger/Runlog/SQL/Links EOR", TID_KEY);
2351
2352 if (db_find_key(hDB, 0, "/Runinfo/Stop time", &hKey) == DB_SUCCESS)
2353 db_create_link(hDB, 0, "/Logger/Runlog/SQL/Links EOR/Stop time", "/Runinfo/Stop time");
2354
2355 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/Events sent", &hKey) == DB_SUCCESS)
2356 db_create_link(hDB, 0, "/Logger/Runlog/SQL/Links EOR/Number of events",
2357 "/Equipment/Trigger/Statistics/Events sent");
2358
2359 }
2360}
2361
2362/*---- Write ODB tree to SQL table ---------------------------------*/
2363
2365{
2366 MYSQL db;
2367 char hostname[80], username[80], password[80], database[80], table[80], query[5000], where[500];
2368 int status, size, write_flag, create_flag;
2369 BOOL insert;
2372
2373 /* do not update SQL if logger does not write data */
2374 size = sizeof(BOOL);
2375 write_flag = FALSE;
2376 db_get_value(hDB, 0, "/Logger/Write data", &write_flag, &size, TID_BOOL, TRUE);
2377 if (!write_flag)
2378 return;
2379
2380 /* insert SQL on bor, else update */
2381 insert = bor;
2382
2383 /* determine primary key */
2384 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links BOR", &hKeyRoot);
2386
2387 /* if BOR list empty, take first one from EOR list */
2388 if (status == DB_NO_MORE_SUBKEYS) {
2389 insert = TRUE;
2390 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links EOR", &hKeyRoot);
2393 return;
2394 }
2395
2397 sprintf(where, "WHERE `%s`='%s'", sql_list[0].column_name, sql_list[0].data);
2398 free(sql_list);
2399 sql_list = NULL;
2400
2401 /* get BOR or EOR list */
2402 if (bor) {
2403 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links BOR", &hKeyRoot);
2404 if (!hKeyRoot) {
2405 cm_msg(MERROR, "write_runlog_sql", "Cannot find \"/Logger/Runlog/SQL/Links BOR");
2406 return;
2407 }
2408 } else {
2409 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links EOR", &hKeyRoot);
2410 if (!hKeyRoot) {
2411 cm_msg(MERROR, "write_runlog_sql", "Cannot find \"/Logger/Runlog/SQL/Links EOR");
2412 return;
2413 }
2414 }
2415
2416 size = sizeof(create_flag);
2417 create_flag = 0;
2418 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Create database", &create_flag, &size, TID_BOOL, TRUE);
2419
2420 size = sizeof(write_flag);
2421 write_flag = 0;
2422 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Write data", &write_flag, &size, TID_BOOL, TRUE);
2423
2424 size = sizeof(hostname);
2425 strcpy(hostname, "localhost");
2426 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Hostname", hostname, &size, TID_STRING, TRUE);
2427
2428 size = sizeof(username);
2429 strcpy(username, "root");
2430 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Username", username, &size, TID_STRING, TRUE);
2431
2432 size = sizeof(password);
2433 password[0] = 0;
2434 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Password", password, &size, TID_STRING, TRUE);
2435
2436 /* use experiment name as default database name */
2437 size = sizeof(database);
2438 db_get_value(hDB, 0, "/Experiment/Name", database, &size, TID_STRING, TRUE);
2439 size = sizeof(database);
2440 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Database", database, &size, TID_STRING, TRUE);
2441
2442 size = sizeof(table);
2443 strcpy(table, "Runlog");
2444 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Table", table, &size, TID_STRING, TRUE);
2445
2446 /* continue only if data should be written */
2447 if (!write_flag)
2448 return;
2449
2450 /* connect to MySQL database */
2451 mysql_init(&db);
2452
2453 if (!mysql_real_connect(&db, hostname, username, password, NULL, 0, NULL, 0)) {
2454 cm_msg(MERROR, "write_runlog_sql", "Failed to connect to database: Error: %s", mysql_error(&db));
2455 mysql_close(&db);
2456 return;
2457 }
2458
2459 /* select database */
2460 sprintf(query, "USE `%s`", database);
2461 if (mysql_query_debug(&db, query)) {
2462
2463 /* create database if selected */
2464 if (create_flag) {
2466 mysql_close(&db);
2467 return;
2468 }
2469 cm_msg(MINFO, "write_runlog_sql", "Database \"%s\" created successfully", database);
2470
2471 } else {
2472 cm_msg(MERROR, "write_runlog_sql", "Failed to select database: Error: %s", mysql_error(&db));
2473 mysql_close(&db);
2474 return;
2475 }
2476 }
2477
2478 if (insert) {
2480 if (status == ER_DUP_ENTRY)
2482 } else
2484
2485 mysql_close(&db);
2486}
2487
2488#endif // HAVE_MYSQL
2489
2490/*---- Create /Logger/Runlog/ASCII tree ----------------------------*/
2491
2493{
2494 std::string filename;
2495 int size, write_flag;
2497
2498 size = sizeof(write_flag);
2499 write_flag = 0;
2500 db_get_value(hDB, 0, "/Logger/Runlog/ASCII/Write data", &write_flag, &size, TID_BOOL, TRUE);
2501
2502 filename = "runlog.log";
2503 db_get_value_string(hDB, 0, "/Logger/Runlog/ASCII/Filename", 0, &filename, TRUE);
2504
2505 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", &hKeyRoot);
2506 if (!hKeyRoot) {
2507 /* create some default links */
2508 db_create_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", TID_KEY);
2509
2510 if (db_find_key(hDB, 0, "/Runinfo/Run number", &hKey) == DB_SUCCESS)
2511 db_create_link(hDB, 0, "/Logger/Runlog/ASCII/Links BOR/Run number", "/Runinfo/Run number");
2512
2513 if (db_find_key(hDB, 0, "/Experiment/Run parameters/Comment", &hKey) == DB_SUCCESS)
2514 db_create_link(hDB, 0, "/Logger/Runlog/ASCII/Links BOR/Comment", "/Experiment/Run parameters/Comment");
2515
2516 if (db_find_key(hDB, 0, "/Runinfo/Start time", &hKey) == DB_SUCCESS)
2517 db_create_link(hDB, 0, "/Logger/Runlog/ASCII/Links BOR/Start time", "/Runinfo/Start time");
2518 }
2519
2520 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", &hKeyRoot);
2521 if (!hKeyRoot) {
2522 /* create some default links */
2523 db_create_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", TID_KEY);
2524
2525 if (db_find_key(hDB, 0, "/Runinfo/Stop time", &hKey) == DB_SUCCESS)
2526 db_create_link(hDB, 0, "/Logger/Runlog/ASCII/Links EOR/Stop time", "/Runinfo/Stop time");
2527
2528 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/Events sent", &hKey) == DB_SUCCESS)
2529 db_create_link(hDB, 0, "/Logger/Runlog/ASCII/Links EOR/Number of events",
2530 "/Equipment/Trigger/Statistics/Events sent");
2531
2532 }
2533}
2534
2535/*---- Write ODB tree to ASCII log file ----------------------------*/
2536
2538{
2539 char filename[256], dir[256], path[256];
2540 int status, size, write_flag;
2542
2543 /* do not update runlog if logger does not write data */
2544 size = sizeof(BOOL);
2545 write_flag = FALSE;
2546 db_get_value(hDB, 0, "/Logger/Write data", &write_flag, &size, TID_BOOL, TRUE);
2547 if (!write_flag)
2548 return;
2549
2550 /* get BOR or EOR list */
2551 if (bor) {
2552 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", &hKeyRoot);
2553 if (!hKeyRoot) {
2554 cm_msg(MERROR, "write_runlog_ascii", "Cannot find \"/Logger/Runlog/ASCII/Links BOR");
2555 return;
2556 }
2557 } else {
2558 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", &hKeyRoot);
2559 if (!hKeyRoot) {
2560 cm_msg(MERROR, "write_runlog_ascii", "Cannot find \"/Logger/Runlog/ASCII/Links EOR");
2561 return;
2562 }
2563 }
2564
2565 size = sizeof(write_flag);
2566 write_flag = 0;
2567 db_get_value(hDB, 0, "/Logger/Runlog/ASCII/Write data", &write_flag, &size, TID_BOOL, TRUE);
2568
2569 size = sizeof(filename);
2570 strcpy(filename, "runlog.log");
2571 db_get_value(hDB, 0, "/Logger/Runlog/ASCII/Filename", filename, &size, TID_STRING, TRUE);
2572
2573 if (strchr(filename, DIR_SEPARATOR) == NULL) {
2574 size = sizeof(dir);
2575 dir[0] = 0;
2576 db_get_value(hDB, 0, "/Logger/Message Dir", dir, &size, TID_STRING, TRUE);
2577 if (dir[0] != 0)
2578 if (dir[strlen(dir) - 1] != DIR_SEPARATOR)
2580 strcpy(path, dir);
2581 strcat(path, filename);
2582 } else
2583 strcpy(path, filename);
2584
2585 /* continue only if data should be written */
2586 if (!write_flag)
2587 return;
2588
2589 FILE *f = fopen(path, "r");
2590 if (f == NULL) {
2591 // create new file
2592 f = fopen(path, "wt");
2593
2594 // write column header line with variable names
2595 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", &hKeyRoot);
2596 for (int i = 0;; i++) {
2599 break;
2600 KEY key;
2601 db_get_key(hDB, hKey, &key);
2602 fprintf(f, "%s\t", key.name);
2603 }
2604 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", &hKeyRoot);
2605 for (int i = 0;; i++) {
2608 break;
2609 KEY key;
2610 db_get_key(hDB, hKey, &key);
2611 fprintf(f, "%s\t", key.name);
2612 }
2613 fprintf(f, "\n");
2614 fclose(f);
2615 }
2616
2617 // append data to logfile
2618 f = fopen(path, "at");
2619
2620 if (bor)
2621 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", &hKeyRoot);
2622 else
2623 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", &hKeyRoot);
2624
2625 for (int i = 0;; i++) {
2628 break;
2629 KEY key;
2630 db_get_key(hDB, hKey, &key);
2631 int size = key.total_size;
2632 char* data = (char*)malloc(size);
2633 assert(data);
2634 db_get_data(hDB, hKey, data, &size, key.type);
2635 std::string str = db_sprintf(data, size, 0, key.type);
2636 //printf("BBB key %s size %d %d [%s]\n", key.name, size, (int)strlen(str), str);
2637 free(data);
2638 fprintf(f, "%s\t", str.c_str());
2639 }
2640 if (!bor)
2641 fprintf(f, "\n");
2642 fclose(f);
2643}
2644
2645/*---- Create /Logger/Runlog/JSON tree ----------------------------*/
2646
2648{
2649 char dirname[80];
2650 int size, write_flag;
2652
2653 size = sizeof(write_flag);
2654 write_flag = 0;
2655 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Write data", &write_flag, &size, TID_BOOL, TRUE);
2656
2657 size = sizeof(dirname);
2658 strcpy(dirname, "runlogs");
2659 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Subdir", dirname, &size, TID_STRING, TRUE);
2660
2661 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", &hKeyRoot);
2662 if (!hKeyRoot) {
2663 /* create some default links */
2664 db_create_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", TID_KEY);
2665
2666 if (db_find_key(hDB, 0, "/Runinfo/Run number", &hKey) == DB_SUCCESS)
2667 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links BOR/Run number", "/Runinfo/Run number");
2668
2669 if (db_find_key(hDB, 0, "/Experiment/Run parameters/Comment", &hKey) == DB_SUCCESS)
2670 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links BOR/Comment", "/Experiment/Run parameters/Comment");
2671
2672 if (db_find_key(hDB, 0, "/Runinfo/Start time", &hKey) == DB_SUCCESS)
2673 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links BOR/Start time", "/Runinfo/Start time");
2674 }
2675
2676 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", &hKeyRoot);
2677 if (!hKeyRoot) {
2678 /* create some default links */
2679 db_create_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", TID_KEY);
2680
2681 if (db_find_key(hDB, 0, "/Runinfo/Stop time", &hKey) == DB_SUCCESS)
2682 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links EOR/Stop time", "/Runinfo/Stop time");
2683
2684 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/Events sent", &hKey) == DB_SUCCESS)
2685 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links EOR/Number of events",
2686 "/Equipment/Trigger/Statistics/Events sent");
2687
2688 }
2689}
2690
2691
2692/*---- Write ODB tree to JSON log file (one per run) -----------------*/
2693
2695 char filename[256], messagedir[256], datadir[256], dirname[256], path[256];
2696 int status, size, write_flag;
2697 int runnumber;
2698 HNDLE hKey;
2699
2700 /* do not update runlog if logger does not write data */
2701 size = sizeof(BOOL);
2702 write_flag = FALSE;
2703 db_get_value(hDB, 0, "/Logger/Write data", &write_flag, &size, TID_BOOL, TRUE);
2704 if (!write_flag)
2705 return;
2706
2707 /* get BOR or EOR list */
2708 if (bor) {
2709 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", &hKey);
2710 if (!hKey) {
2711 cm_msg(MERROR, "write_runlog_json", "Cannot find \"/Logger/Runlog/JSON/Links BOR");
2712 return;
2713 }
2714 } else {
2715 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", &hKey);
2716 if (!hKey) {
2717 cm_msg(MERROR, "write_runlog_json", "Cannot find \"/Logger/Runlog/JSON/Links EOR");
2718 return;
2719 }
2720 }
2721
2722 size = sizeof(write_flag);
2723 write_flag = 0;
2724 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Write data", &write_flag, &size, TID_BOOL, TRUE);
2725
2726 size = sizeof(datadir);
2727 strcpy(datadir, "");
2728 db_get_value(hDB, 0, "/Logger/Data Dir", datadir, &size, TID_STRING, TRUE);
2729
2730 size = sizeof(messagedir);
2731 strcpy(messagedir, "");
2732 db_get_value(hDB, 0, "/Logger/Message Dir", messagedir, &size, TID_STRING, TRUE);
2733
2734 size = sizeof(dirname);
2735 strcpy(dirname, "runlogs");
2736 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Subdir", dirname, &size, TID_STRING, TRUE);
2737
2738 size = sizeof(runnumber);
2739 db_get_value(hDB, 0, "/Runinfo/Run number", &runnumber, &size, TID_INT32, FALSE);
2740
2741 snprintf(filename, 256, "runlog_%06i.json", runnumber);
2742
2743 // use /Logger/Message dir, and if empty use /Logger/Data dir
2744 mstrlcpy(path, messagedir, sizeof(path));
2745 if (path[0] == 0)
2746 mstrlcpy(path, datadir, sizeof(path));
2747 if (path[strlen(path) - 1] != DIR_SEPARATOR)
2748 mstrlcat(path, DIR_SEPARATOR_STR, sizeof(path));
2749 mstrlcat(path, dirname, sizeof(path));
2750 if (path[strlen(path) - 1] != DIR_SEPARATOR)
2751 mstrlcat(path, DIR_SEPARATOR_STR, sizeof(path));
2752
2753 /* create directory if needed */
2754#ifdef OS_WINNT
2755 status = mkdir(path);
2756#else
2757 status = mkdir(path, 0755);
2758#endif
2759
2760 mstrlcat(path, filename, sizeof(path));
2761
2762 /* continue only if data should be written */
2763 if (!write_flag)
2764 return;
2765
2766 char fileflag[2] = "a";
2767 if (bor)
2768 strcpy(fileflag, "a");
2769
2770 FILE *file = fopen(path, fileflag);
2771 if (file == NULL) {
2772 cm_msg(MERROR, "write_runlog_json", "Cannot open file \"%s\"", path);
2773 return;
2774 }
2775
2776 if (bor)
2777 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", &hKey);
2778 else
2779 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", &hKey);
2780
2781 int buffer_size = 100000;
2782 char *buffer = (char *)malloc(buffer_size);
2783 int buffer_end = 0;
2784
2785 if (bor)
2786 json_write(&buffer, &buffer_size, &buffer_end, 0, "{\n \"BOR\": ", 0);
2787 else
2788 json_write(&buffer, &buffer_size, &buffer_end, 0, " \"EOR\": ", 0);
2789
2790 if (!rpc_is_remote())
2793 status = json_write_anything(hDB, hKey, &buffer, &buffer_size, &buffer_end, JS_LEVEL_1, 0, flags, 0);
2794 if (!rpc_is_remote())
2796
2797 if (bor)
2798 json_write(&buffer, &buffer_size, &buffer_end, 0, ",\n", 0);
2799 else
2800 json_write(&buffer, &buffer_size, &buffer_end, 0, " \n}\n", 0);
2801
2802 if (status == DB_SUCCESS) {
2803 if (buffer) {
2804 size_t wr = fwrite(buffer, 1, buffer_end, file);
2805 if (wr != (size_t) buffer_end) {
2806 cm_msg(MERROR, "write_runlog_json", "Cannot write to file \"%s\", fwrite() errno %d (%s)", filename, errno, strerror(errno));
2807 free(buffer);
2808 fclose(file);
2809 return;
2810 }
2811 }
2812 }
2813
2814 if (buffer)
2815 free(buffer);
2816
2817 fclose(file);
2818}
2819
2820/*---- open FTP channel --------------------------------------------*/
2821
2823{
2824 cm_msg(MERROR, "ftp_error", "%s", message);
2825 return 1;
2826}
2827
2829{
2830 INT status;
2831 short port = 0;
2832 char *token;
2834 char user[32], pass[32];
2835 char directory[256], file_name[256], file_mode[256];
2836 char bdestination[256]; // have to make a copy of destination because strtok() modifies it's string
2838 char* destination = bdestination;
2839
2840 // skip leading slash
2841 if (destination[0] == '/')
2842 destination += 1;
2843
2844 /*
2845 destination should have the form:
2846 host, port, user, password, directory, run%05d.mid
2847 */
2848
2849 /* break destination in components */
2850 token = strtok(destination, ",");
2851 if (token)
2852 mstrlcpy(host_name, token, sizeof(host_name));
2853
2854 token = strtok(NULL, ", ");
2855 if (token)
2856 port = atoi(token);
2857
2858 token = strtok(NULL, ", ");
2859 if (token)
2860 mstrlcpy(user, token, sizeof(user));
2861
2862 token = strtok(NULL, ", ");
2863 if (token)
2864 mstrlcpy(pass, token, sizeof(pass));
2865
2866 token = strtok(NULL, ", ");
2867 if (token)
2868 mstrlcpy(directory, token, sizeof(directory));
2869
2870 token = strtok(NULL, ", ");
2871 if (token)
2872 mstrlcpy(file_name, token, sizeof(file_name));
2873
2874 token = strtok(NULL, ", ");
2875 file_mode[0] = 0;
2876 if (token)
2877 mstrlcpy(file_mode, token, sizeof(file_mode));
2878
2879#ifdef FAL_MAIN
2881#else
2882 ftp_debug((int (*)(const char *)) puts, ftp_error);
2883#endif
2884
2885 status = ftp_login(con, host_name, port, user, pass, "");
2886 if (status >= 0)
2887 return status;
2888
2889 status = ftp_chdir(*con, directory);
2890 if (status >= 0)
2891 return status;
2892
2893 status = ftp_binary(*con);
2894 if (status >= 0)
2895 return status;
2896
2897 if (file_mode[0]) {
2898 status = ftp_command(*con, "umask %s", file_mode, 200, 250, EOF);
2899 if (status >= 0)
2900 return status;
2901 }
2902
2903 if (ftp_open_write(*con, file_name) >= 0)
2904 return (*con)->err_no;
2905
2906 return SS_SUCCESS;
2907}
2908
2909/*---- FTP writer --------------------------------------------------*/
2910
2912{
2913public:
2915 {
2916 if (fTrace)
2917 printf("WriterFtp: path [%s]\n", log_chn->path.c_str());
2918
2919 fFtp = NULL;
2920 }
2921
2922 ~WriterFtp() // dtor
2923 {
2924 if (fTrace)
2925 printf("WriterFtp: destructor\n");
2926
2927 if (fFtp) {
2928 ftp_bye(fFtp);
2929 fFtp = NULL;
2930 }
2931 }
2932
2934 {
2935 fBytesIn = 0;
2936 fBytesOut = 0;
2937
2938 if (fTrace)
2939 printf("WriterFtp: open path [%s]\n", log_chn->path.c_str());
2940
2941 assert(fFtp == NULL);
2942
2943 int status = ftp_open(log_chn->path.c_str(), &fFtp);
2944 if (status != SS_SUCCESS || fFtp == NULL) {
2945 cm_msg(MERROR, "WriterFtp::wr_open", "Cannot open FTP connection \'%s\', ftp_open() status %d, errno %d (%s)", log_chn->path.c_str(), status, errno, strerror(errno));
2946 return SS_FILE_ERROR;
2947 }
2948
2949 log_chn->handle = 9999;
2950
2951 return SUCCESS;
2952 }
2953
2954 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
2955 {
2956 if (fTrace)
2957 printf("WriterFtp: write path [%s], size %d\n", log_chn->path.c_str(), size);
2958
2959 if (size == 0)
2960 return SUCCESS;
2961
2962 if (fFtp == NULL) {
2963 return SS_FILE_ERROR;
2964 }
2965
2966 fBytesIn += size;
2967
2968 int wr = ftp_send(fFtp->data, (const char*)data, size);
2969
2970 if (wr > 0)
2971 fBytesOut += wr;
2972
2973 if (wr != size) {
2974 cm_msg(MERROR, "WriterFtp::wr_write", "Cannot write to FTP connection \'%s\', ftp_send(%d) returned %d, errno %d (%s)", log_chn->path.c_str(), size, wr, errno, strerror(errno));
2975 return SS_FILE_ERROR;
2976 }
2977
2978 return SUCCESS;
2979 }
2980
2982 {
2983 if (fTrace)
2984 printf("WriterFtp: close path [%s]\n", log_chn->path.c_str());
2985
2986 assert(fFtp != NULL);
2987
2988 ftp_close(fFtp);
2989 ftp_bye(fFtp);
2990 fFtp = NULL;
2991
2992 log_chn->handle = 0;
2993
2994 return SUCCESS;
2995 }
2996
2997 std::string wr_get_file_ext()
2998 {
2999 return "";
3000 }
3001
3002 std::string wr_get_chain()
3003 {
3004 return "FTP";
3005 }
3006
3007private:
3009};
3010
3011/*---- MIDAS format routines ---------------------------------------*/
3012
3013#ifdef OBSOLETE
3015{
3016 INT size, written = 0;
3017 off_t n;
3018
3019 MIDAS_INFO* info = log_chn->midas_info;
3020 size = (POINTER_T) info->write_pointer - (POINTER_T) info->buffer;
3021
3022 if (size == 0)
3023 return 0;
3024
3025 /* write record to device */
3026 if (log_chn->type == LOG_TYPE_FTP)
3027 written =
3028 ftp_send(((FTP_CON *) log_chn->ftp_con)->data, info->buffer,
3029 size) == size ? SS_SUCCESS : SS_FILE_ERROR;
3030 else if (log_chn->gzfile) {
3031 n = lseek(log_chn->handle, 0, SEEK_CUR);
3032 if (gzwrite((gzFile) log_chn->gzfile, info->buffer, size) != size)
3033 return -1;
3034 written = lseek(log_chn->handle, 0, SEEK_CUR) - n;
3035 } else if (log_chn->pfile) {
3036 written = fwrite(info->buffer, size, 1,log_chn->pfile);
3037 if (errno == EPIPE){
3038 cm_msg(MERROR, "midas_flush_buffer",
3039 "pipe was broken for redirection of data stream, please check the command usage:\"%s\"\nYou can try to run mlogger in console in interactive mode(just \"mlogger\") to obtaine more detail error message",
3040 log_chn->pipe_command.c_str());
3041 log_chn->handle=0;
3042 }
3043 if (written !=1 )
3044 return -1;
3045 written = size;
3046 } else if (log_chn->handle) {
3047#ifdef OS_WINNT
3048 WriteFile((HANDLE) log_chn->handle, info->buffer, size, (unsigned long *) &written, NULL);
3049#else
3050 written = write(log_chn->handle, info->buffer, size);
3051#endif
3052 } else {
3053 /* we are writing into the void!?! */
3054 written = 0;
3055 }
3056
3057 info->write_pointer = info->buffer;
3058
3059 return written;
3060}
3061#endif
3062
3063/*------------------------------------------------------------------*/
3064
3065#ifdef OBSOLETE
3067{
3069
3070 MIDAS_INFO* info = log_chn->midas_info;
3071 written = 0;
3072
3073 /* check if event fits into buffer */
3074 size_left = TAPE_BUFFER_SIZE - ((POINTER_T) info->write_pointer - (POINTER_T) info->buffer);
3075
3076 if (size_left < evt_size) {
3077 /* copy first part of event */
3078 memcpy(info->write_pointer, pevent, size_left);
3079 info->write_pointer += size_left;
3080
3081 /* flush buffer */
3083 if (written < 0)
3084 return -1;
3085
3086 /* several writes for large events */
3087 while (evt_size - size_left >= TAPE_BUFFER_SIZE) {
3088 memcpy(info->buffer, (char *) pevent + size_left, TAPE_BUFFER_SIZE);
3089 info->write_pointer += TAPE_BUFFER_SIZE;
3091
3093 if (i < 0)
3094 return -1;
3095
3096 written += i;
3097 }
3098
3099 /* copy remaining part of event */
3100 memcpy(info->buffer, (char *) pevent + size_left, evt_size - size_left);
3101 info->write_pointer = info->buffer + (evt_size - size_left);
3102 } else {
3103 /* copy event to buffer */
3104 memcpy(info->write_pointer, pevent, evt_size);
3105 info->write_pointer += evt_size;
3106 }
3107
3108 /* update statistics */
3109 return written;
3110}
3111#endif
3112
3113/*------------------------------------------------------------------*/
3114
3115#ifdef OBSOLETE
3117{
3118 INT status;
3119
3120 /* allocate MIDAS buffer info */
3121 log_chn->midas_info = (MIDAS_INFO*) malloc(sizeof(MIDAS_INFO));
3122
3123 MIDAS_INFO* info = log_chn->midas_info;
3124 if (info == NULL) {
3125 log_chn->handle = 0;
3126 return SS_NO_MEMORY;
3127 }
3128
3129 /* allocate full ring buffer for that channel */
3130 if ((info->buffer = (char *) malloc(TAPE_BUFFER_SIZE)) == NULL) {
3131 free(info);
3132 log_chn->handle = 0;
3133 return SS_NO_MEMORY;
3134 }
3135
3136 info->write_pointer = info->buffer;
3137
3138 /* Create device channel */
3139 if (log_chn->type == LOG_TYPE_FTP) {
3140 status = ftp_open(log_chn->path.c_str(), &log_chn->ftp_con);
3141 if (status != SS_SUCCESS) {
3142 free(info->buffer);
3143 free(info);
3144 log_chn->handle = 0;
3145 return status;
3146 } else {
3147 log_chn->handle = 1;
3148 log_chn->do_disk_level = FALSE;
3149 log_chn->statistics.disk_level = -1;
3150 }
3151 } else {
3152 /* check if file exists */
3153 if (strstr(log_chn->path.c_str(), "null") == NULL) {
3154 log_chn->handle = open(log_chn->path.c_str(), O_RDONLY);
3155 if (log_chn->handle > 0) {
3156 /* check if file length is nonzero */
3157 if (lseek(log_chn->handle, 0, SEEK_END) > 0) {
3158 close(log_chn->handle);
3159 free(info->buffer);
3160 free(info);
3161 log_chn->handle = 0;
3162 return SS_FILE_EXISTS;
3163 }
3164 }
3165 }
3166
3167 log_chn->gzfile = NULL;
3168 log_chn->pfile = NULL;
3169 log_chn->handle = 0;
3170
3171 /* check that compression level and file name match each other */
3172 if (1) {
3173 const char *sufp = strstr(log_chn->path.c_str(), ".gz");
3174 int isgz = sufp && sufp[3]==0;
3175
3176 if (log_chn->compression>0 && !isgz) {
3177 cm_msg(MERROR, "midas_log_open", "Compression level %d enabled, but output file name \'%s\' does not end with '.gz'", log_chn->compression, log_chn->path.c_str());
3178 free(info->buffer);
3179 free(info);
3180 return SS_FILE_ERROR;
3181 }
3182
3183 if (log_chn->compression==0 && isgz && log_chn->pipe_command[0] == 0) {
3184 cm_msg(MERROR, "midas_log_open",
3185 "Output file name ends with '.gz', but compression level is zero");
3186 free(info->buffer);
3187 free(info);
3188 return SS_FILE_ERROR;
3189 }
3190 }
3191
3192 if (log_chn->pipe_command[0] != 0){
3193#ifdef OS_WINNT
3194 cm_msg(MERROR, "midas_log_open", "Error: Pipe command not supported under Widnows");
3195 return SS_FILE_ERROR;
3196#else
3197 log_chn->pfile = popen(log_chn->pipe_command.c_str(), "w");
3198 log_chn->handle = 1;
3199 if (log_chn->pfile == NULL) {
3200 cm_msg(MERROR, "midas_log_open", "Error: popen() failed, cannot open pipe stream");
3201 free(info->buffer);
3202 free(info);
3203 log_chn->handle = 0;
3204 return SS_FILE_ERROR;
3205 }
3206#endif
3207 } else {
3208#ifdef OS_WINNT
3209 log_chn->handle = (int) CreateFile(log_chn->path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL,
3212#else
3213 log_chn->handle = open(log_chn->path.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_BINARY | O_LARGEFILE, 0444);
3214#endif
3215 if (log_chn->handle < 0) {
3216 free(info->buffer);
3217 free(info);
3218 log_chn->handle = 0;
3219 return SS_FILE_ERROR;
3220 }
3221
3222 log_chn->do_disk_level = TRUE;
3223
3224 if (log_chn->compression > 0) {
3225 log_chn->gzfile = gzdopen(log_chn->handle, "wb");
3226 if (log_chn->gzfile == NULL) {
3227 cm_msg(MERROR, "midas_log_open", "Error: gzdopen() failed, cannot open compression stream");
3228 free(info->buffer);
3229 free(info);
3230 log_chn->handle = 0;
3231 return SS_FILE_ERROR;
3232 }
3233
3234 gzsetparams((gzFile)log_chn->gzfile, log_chn->compression, Z_DEFAULT_STRATEGY);
3235 }
3236 }
3237 }
3238
3239 /* write ODB dump */
3240 if (log_chn->settings.odb_dump)
3242
3243 return SS_SUCCESS;
3244}
3245#endif
3246
3247/*------------------------------------------------------------------*/
3248
3249#ifdef OBSOLETE
3251{
3252 int written;
3253 off_t n;
3254
3255 /* write ODB dump */
3256 if (log_chn->settings.odb_dump)
3258
3260
3261 /* update statistics */
3262 log_chn->statistics.bytes_written += written;
3263 log_chn->statistics.bytes_written_total += written;
3264
3265 if (log_chn->type == LOG_TYPE_FTP) {
3266 ftp_close(log_chn->ftp_con);
3267 ftp_bye(log_chn->ftp_con);
3268 } else {
3269 if (log_chn->gzfile) {
3270 n = lseek(log_chn->handle, 0, SEEK_CUR);
3271 gzflush((gzFile) log_chn->gzfile, Z_FULL_FLUSH);
3272 written = lseek(log_chn->handle, 0, SEEK_CUR) - n;
3273 written += 10; // trailer? Obtained experimentally
3274 gzclose((gzFile) log_chn->gzfile);
3275 log_chn->statistics.bytes_written += written;
3276 log_chn->statistics.bytes_written_total += written;
3277 log_chn->gzfile = NULL;
3278 }
3279#ifdef OS_WINNT
3280 CloseHandle((HANDLE) log_chn->handle);
3281#else
3282 if (log_chn->pfile) {
3283 pclose(log_chn->pfile);
3284 log_chn->pfile = NULL;
3285 } else {
3286 close(log_chn->handle);
3287 }
3288#endif
3289 log_chn->handle = 0;
3290 }
3291
3292 assert(log_chn->midas_info != NULL);
3293 assert(log_chn->midas_info->buffer != NULL);
3294
3295 free(log_chn->midas_info->buffer);
3296 log_chn->midas_info->buffer = NULL;
3297 free(log_chn->midas_info);
3298 log_chn->midas_info = NULL;
3299
3300 return SS_SUCCESS;
3301}
3302#endif
3303
3304/*-- db_get_event_definition ---------------------------------------*/
3305
3306typedef struct {
3307 short int event_id;
3308 WORD format;
3309 HNDLE hDefKey;
3310} EVENT_DEF;
3311
3313{
3314 INT i, index, status, size;
3315 char str[80];
3317 WORD id;
3318
3319#define EVENT_DEF_CACHE_SIZE 30
3320 static EVENT_DEF *event_def = NULL;
3321
3322 /* allocate memory for cache */
3323 if (event_def == NULL)
3325
3326 /* lookup if event definition in cache */
3327 for (i = 0; event_def[i].event_id; i++)
3328 if (event_def[i].event_id == event_id)
3329 return &event_def[i];
3330
3331 /* search free cache entry */
3332 for (index = 0; index < EVENT_DEF_CACHE_SIZE; index++)
3333 if (event_def[index].event_id == 0)
3334 break;
3335
3336 if (index == EVENT_DEF_CACHE_SIZE) {
3337 cm_msg(MERROR, "db_get_event_definition", "too many event definitions");
3338 return NULL;
3339 }
3340
3341 /* check for system events */
3342 if (event_id < 0) {
3343 event_def[index].event_id = event_id;
3344 event_def[index].format = FORMAT_MIDAS;
3345 event_def[index].hDefKey = 0;
3346 return &event_def[index];
3347 }
3348
3349 status = db_find_key(hDB, 0, "/equipment", &hKeyRoot);
3350 if (status != DB_SUCCESS) {
3351 cm_msg(MERROR, "db_get_event_definition", "cannot find /equipment entry in ODB");
3352 return NULL;
3353 }
3354
3355 for (i = 0;; i++) {
3356 /* search for client with specific name */
3358 if (status == DB_NO_MORE_SUBKEYS) {
3359 cm_msg(MERROR, "db_get_event_definition", "Cannot find event id %d under /equipment", event_id);
3360 return NULL;
3361 }
3362
3363 size = sizeof(id);
3364 status = db_get_value(hDB, hKey, "Common/Event ID", &id, &size, TID_UINT16, TRUE);
3365 if (status != DB_SUCCESS)
3366 continue;
3367
3368 if (id == event_id) {
3369 /* set cache entry */
3370 event_def[index].event_id = id;
3371
3372 size = sizeof(str);
3373 str[0] = 0;
3374 db_get_value(hDB, hKey, "Common/Format", str, &size, TID_STRING, TRUE);
3375
3376 if (equal_ustring(str, "Fixed"))
3377 event_def[index].format = FORMAT_FIXED;
3378 else if (equal_ustring(str, "MIDAS"))
3379 event_def[index].format = FORMAT_MIDAS;
3380 else {
3381 cm_msg(MERROR, "db_get_event_definition", "unknown data format name \"%s\"", str);
3382 event_def[index].event_id = 0;
3383 return NULL;
3384 }
3385
3386 db_find_key(hDB, hKey, "Variables", &event_def[index].hDefKey);
3387 return &event_def[index];
3388 }
3389 }
3390}
3391
3392/*---- ROOT format routines ----------------------------------------*/
3393
3394#ifdef HAVE_ROOT
3395
3396#define MAX_BANKS 100
3397
3398typedef struct {
3399 int event_id;
3400 TTree *tree;
3401 int n_branch;
3404 int branch_len[MAX_BANKS];
3406} EVENT_TREE;
3407
3408struct TREE_STRUCT {
3409 TFile *f;
3410 int n_tree;
3412};
3413
3414/*------------------------------------------------------------------*/
3415
3417{
3418 int index, size, status;
3419 WORD id;
3420 char str[1000];
3422 KEY eqkey;
3423 EVENT_TREE *et;
3424
3425 status = db_find_key(hDB, 0, "/Equipment", &hKeyRoot);
3426 if (status != DB_SUCCESS) {
3427 cm_msg(MERROR, "root_book_trees", "cannot find \"/Equipment\" entry in ODB");
3428 return 0;
3429 }
3430
3431 tree_struct->n_tree = 0;
3432
3433 for (index = 0;; index++) {
3434 /* loop through all events under /Equipment */
3437 return 1;
3438
3440
3441 /* create tree */
3442 tree_struct->n_tree++;
3443 if (tree_struct->n_tree == 1)
3444 tree_struct->event_tree = (EVENT_TREE *) malloc(sizeof(EVENT_TREE));
3445 else
3446 tree_struct->event_tree =
3447 (EVENT_TREE *) realloc(tree_struct->event_tree, sizeof(EVENT_TREE) * tree_struct->n_tree);
3448
3449 et = tree_struct->event_tree + (tree_struct->n_tree - 1);
3450
3451 size = sizeof(id);
3452 status = db_get_value(hDB, hKeyEq, "Common/Event ID", &id, &size, TID_UINT16, TRUE);
3453 if (status != DB_SUCCESS)
3454 continue;
3455
3456 et->event_id = id;
3457 et->n_branch = 0;
3458
3459 /* check format */
3460 size = sizeof(str);
3461 str[0] = 0;
3462 db_get_value(hDB, hKeyEq, "Common/Format", str, &size, TID_STRING, TRUE);
3463
3464 if (!equal_ustring(str, "MIDAS")) {
3465 cm_msg(MERROR, "root_book_events",
3466 "ROOT output only for MIDAS events, but %s in %s format", eqkey.name, str);
3467 return 0;
3468 }
3469
3470 /* create tree */
3471 sprintf(str, "Event \"%s\", ID %d", eqkey.name, id);
3472 et->tree = new TTree(eqkey.name, str);
3473 }
3474
3475 return 1;
3476}
3477
3478/*------------------------------------------------------------------*/
3479
3481{
3482 int i, status;
3483 char str[1000];
3484 HNDLE hKeyVar, hKeySubVar;
3486
3487 /* find definition of bank */
3488 status = db_find_key(hDB, hKeyDef, bank_name, &hKeyVar);
3489 if (status != DB_SUCCESS) {
3490 cm_msg(MERROR, "root_book_bank", "received unknown bank \"%s\" in event #%d", bank_name, event_id);
3491 return 0;
3492 }
3493
3494 if (et->n_branch + 1 == MAX_BANKS) {
3495 cm_msg(MERROR, "root_book_bank", "max number of banks (%d) exceeded in event #%d", MAX_BANKS, event_id);
3496 return 0;
3497 }
3498
3499 db_get_key(hDB, hKeyVar, &varkey);
3500
3501 if (varkey.type != TID_KEY) {
3502 /* book variable length array size */
3503
3504 sprintf(str, "n%s/I:%s[n%s]/", varkey.name, varkey.name, varkey.name);
3505
3506 switch (varkey.type) {
3507 case TID_UINT8:
3508 case TID_CHAR:
3509 strcat(str, "b");
3510 break;
3511 case TID_INT8:
3512 strcat(str, "B");
3513 break;
3514 case TID_UINT16:
3515 strcat(str, "s");
3516 break;
3517 case TID_INT16:
3518 strcat(str, "S");
3519 break;
3520 case TID_UINT32:
3521 strcat(str, "i");
3522 break;
3523 case TID_INT32:
3524 strcat(str, "I");
3525 break;
3526 case TID_BOOL:
3527 strcat(str, "I");
3528 break;
3529 case TID_FLOAT:
3530 strcat(str, "F");
3531 break;
3532 case TID_DOUBLE:
3533 strcat(str, "D");
3534 break;
3535 case TID_STRING:
3536 strcat(str, "C");
3537 break;
3538 }
3539
3540 et->branch[et->n_branch] = et->tree->Branch(bank_name, 0, (const char*)str);
3541 et->branch_name[et->n_branch] = *(DWORD *) bank_name;
3542 et->n_branch++;
3543 } else {
3544 /* book structured bank */
3545 str[0] = 0;
3546
3547 for (i = 0;; i++) {
3548 /* loop through bank variables */
3549 status = db_enum_key(hDB, hKeyVar, i, &hKeySubVar);
3551 break;
3552
3554
3555 if (i != 0)
3556 strcat(str, ":");
3557 strcat(str, subvarkey.name);
3558 strcat(str, "/");
3559 switch (subvarkey.type) {
3560 case TID_UINT8:
3561 case TID_CHAR:
3562 strcat(str, "b");
3563 break;
3564 case TID_INT8:
3565 strcat(str, "B");
3566 break;
3567 case TID_UINT16:
3568 strcat(str, "s");
3569 break;
3570 case TID_INT16:
3571 strcat(str, "S");
3572 break;
3573 case TID_UINT32:
3574 strcat(str, "i");
3575 break;
3576 case TID_INT32:
3577 strcat(str, "I");
3578 break;
3579 case TID_BOOL:
3580 strcat(str, "I");
3581 break;
3582 case TID_FLOAT:
3583 strcat(str, "F");
3584 break;
3585 case TID_DOUBLE:
3586 strcat(str, "D");
3587 break;
3588 case TID_STRING:
3589 strcat(str, "C");
3590 break;
3591 }
3592 }
3593
3594 et->branch[et->n_branch] = et->tree->Branch(bank_name, 0, (const char*)str);
3595 et->branch_name[et->n_branch] = *(DWORD *) bank_name;
3596 et->n_branch++;
3597 }
3598
3599 return 1;
3600}
3601
3602/*------------------------------------------------------------------*/
3603
3605{
3606 INT i;
3607 char bank_name[32];
3609 void *pdata;
3610 EVENT_TREE *et;
3611 BANK *pbk;
3612 BANK32 *pbk32;
3613 BANK32A *pbk32a;
3614 DWORD bklen;
3615 DWORD bkname;
3616 WORD bktype;
3617 TBranch *branch;
3618
3619 if ((pevent->event_id == EVENTID_BOR) ||
3620 (pevent->event_id == EVENTID_EOR) ||
3621 (pevent->event_id == EVENTID_MESSAGE) ||
3622 (pevent->event_id == EVENTID_FRAG1) ||
3623 (pevent->event_id == EVENTID_FRAG)) {
3624 // Cannot write system event into ROOT file
3625 return 0;
3626 }
3627
3629 if (event_def == NULL) {
3630 cm_msg(MERROR, "root_write", "Definition for event #%d not found under /Equipment", pevent->event_id);
3631 return -1;
3632 }
3633
3634 TREE_STRUCT *ts = log_chn->root_tree_struct;
3635
3636 /*---- MIDAS format ----------------------------------------------*/
3637
3638 if (event_def->format == FORMAT_MIDAS) {
3639 pbh = (BANK_HEADER *) (pevent + 1);
3640 bk_swap(pbh, FALSE);
3641
3642 /* find event in tree structure */
3643 for (i = 0; i < ts->n_tree; i++)
3644 if (ts->event_tree[i].event_id == pevent->event_id)
3645 break;
3646
3647 if (i == ts->n_tree) {
3648 cm_msg(MERROR, "root_write", "Event #%d not booked by root_book_events()", pevent->event_id);
3649 return -1;
3650 }
3651
3652 et = ts->event_tree + i;
3653
3654 /* first mark all banks non-filled */
3655 for (i = 0; i < et->n_branch; i++)
3656 et->branch_filled[i] = FALSE;
3657
3658 /* go thourgh all banks and set the address */
3659 pbk = NULL;
3660 pbk32 = NULL;
3661 pbk32a = NULL;
3662 do {
3663 /* scan all banks */
3664 if (bk_is32a(pbh)) {
3666 if (pbk32a == NULL)
3667 break;
3668 bkname = *((DWORD *) pbk32a->name);
3669 bktype = (WORD) pbk32a->type;
3670 } else if (bk_is32(pbh)) {
3672 if (pbk32 == NULL)
3673 break;
3674 bkname = *((DWORD *) pbk32->name);
3675 bktype = (WORD) pbk32->type;
3676 } else {
3677 bklen = bk_iterate(pbh, &pbk, &pdata);
3678 if (pbk == NULL)
3679 break;
3680 bkname = *((DWORD *) pbk->name);
3681 bktype = (WORD) pbk->type;
3682 }
3683
3684 if (rpc_tid_size(bktype & 0xFF))
3685 bklen /= rpc_tid_size(bktype & 0xFF);
3686
3687 *((DWORD *) bank_name) = bkname;
3688 bank_name[4] = 0;
3689
3690 for (i = 0; i < et->n_branch; i++)
3691 if (et->branch_name[i] == bkname)
3692 break;
3693
3694 if (i == et->n_branch)
3695 root_book_bank(et, event_def->hDefKey, pevent->event_id, bank_name);
3696
3697 branch = et->branch[i];
3698 et->branch_filled[i] = TRUE;
3699 et->branch_len[i] = bklen;
3700
3701 if (bktype != TID_STRUCT) {
3702 TIter next(branch->GetListOfLeaves());
3703 TLeaf *leaf = (TLeaf *) next();
3704
3705 /* varibale length array */
3706 leaf->SetAddress(&et->branch_len[i]);
3707
3708 leaf = (TLeaf *) next();
3709 leaf->SetAddress(pdata);
3710 } else {
3711 /* structured bank */
3712 branch->SetAddress(pdata);
3713 }
3714
3715 } while (1);
3716
3717 /* check if all branches have been filled */
3718 for (i = 0; i < et->n_branch; i++)
3719 if (!et->branch_filled[i])
3720 cm_msg(MERROR, "root_write", "Bank %s booked but not received, tree cannot be filled", bank_name);
3721
3722 /* fill tree */
3723 et->tree->Fill();
3724 }
3725
3726 return (INT) ts->f->GetBytesWritten();
3727}
3728
3729/*------------------------------------------------------------------*/
3730
3732{
3733 INT size, level;
3734 char str[256+100], name[256];
3736
3737 /* Create device channel */
3738 if (log_chn->type == LOG_TYPE_FTP) {
3739 cm_msg(MERROR, "root_log_open", "ROOT files can only reside on disk");
3740 log_chn->handle = 0;
3741 return -1;
3742 } else {
3743 /* check if file exists */
3744 if (strstr(log_chn->path.c_str(), "null") == NULL) {
3745 log_chn->handle = open(log_chn->path.c_str(), O_RDONLY);
3746 if (log_chn->handle > 0) {
3747 /* check if file length is nonzero */
3748 if (lseek(log_chn->handle, 0, SEEK_END) > 0) {
3749 close(log_chn->handle);
3750 log_chn->handle = 0;
3751 return SS_FILE_EXISTS;
3752 }
3753 }
3754 }
3755
3756 name[0] = 0;
3757 size = sizeof(name);
3758 db_get_value(hDB, 0, "/Experiment/Name", name, &size, TID_STRING, TRUE);
3759
3760 sprintf(str, "MIDAS exp. %s, run #%d", name, run_number);
3761
3762 TFile *f = new TFile(log_chn->path.c_str(), "create", str, 1);
3763 if (!f->IsOpen()) {
3764 delete f;
3765 log_chn->handle = 0;
3766 return SS_FILE_ERROR;
3767 }
3768 log_chn->handle = 1;
3769
3770 /* set compression level */
3771 level = 0;
3772 size = sizeof(level);
3773 db_get_value(hDB, log_chn->settings_hkey, "Compression", &level, &size, TID_INT32, FALSE);
3774 f->SetCompressionLevel(level);
3775
3776 /* create root structure with trees and branches */
3778 tree_struct->f = f;
3779
3780 /* book event tree */
3782
3783 /* store file object in format_info */
3784 log_chn->root_tree_struct = tree_struct;
3785 }
3786
3787#if 0
3788 /* write ODB dump */
3789 if (log_chn->settings.odb_dump) {
3790 EVENT_HEADER event;
3791
3792 event.event_id = EVENTID_BOR;
3793 event.data_size = 0;
3794 event.serial_number = run_number;
3795
3796 //root_write(log_chn, &event, sizeof(EVENT_HEADER));
3797 }
3798#endif
3799
3800 return SS_SUCCESS;
3801}
3802
3803/*------------------------------------------------------------------*/
3804
3806{
3807 TREE_STRUCT *ts = log_chn->root_tree_struct;
3808
3809 /* flush and close file */
3810 ts->f->Write();
3811 ts->f->Close();
3812 delete ts->f; // deletes also all trees and branches!
3813
3814 /* delete event tree */
3815 free(ts->event_tree);
3816 ts->event_tree = NULL;
3817 free(ts);
3818 ts = NULL;
3819
3820 log_chn->root_tree_struct = NULL;
3821
3822 return SS_SUCCESS;
3823}
3824
3825class WriterROOT : public WriterInterface
3826{
3827public:
3828 WriterROOT(LOG_CHN* log_chn) // ctor
3829 {
3830 if (fTrace)
3831 printf("WriterROOT: path [%s]\n", log_chn->path.c_str());
3832 }
3833
3834 ~WriterROOT() // dtor
3835 {
3836 if (fTrace)
3837 printf("WriterROOT: destructor\n");
3838 }
3839
3841 {
3842 fBytesIn = 0;
3843 fBytesOut = 0;
3844
3845 if (fTrace)
3846 printf("WriterROOT: open path [%s]\n", log_chn->path.c_str());
3847
3849 if (status != SUCCESS)
3850 return status;
3851
3852 log_chn->handle = 9999;
3853
3854 return SUCCESS;
3855 }
3856
3857 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
3858 {
3859 if (fTrace)
3860 printf("WriterROOT: write path [%s], size %d\n", log_chn->path.c_str(), size);
3861
3862 if (size == 0)
3863 return SUCCESS;
3864
3865 fBytesIn += size;
3866
3867 int written = root_write(log_chn, (const EVENT_HEADER*)data, size);
3868
3869 if (written < 0) {
3870 return SS_FILE_ERROR;
3871 }
3872
3873 fBytesOut += size;
3874
3875 return SUCCESS;
3876 }
3877
3879 {
3880 if (fTrace)
3881 printf("WriterROOT: close path [%s]\n", log_chn->path.c_str());
3882
3884
3885 log_chn->handle = 0;
3886
3887 return status;
3888 }
3889
3890 std::string wr_get_file_ext()
3891 {
3892 return ".root";
3893 }
3894
3895 std::string wr_get_chain()
3896 {
3897 return "ROOT";
3898 }
3899
3900private:
3901};
3902
3903#endif /* HAVE_ROOT */
3904
3905/*------------------------------------------------------------------*/
3906
3908{
3909 std::string bzip2_command = "bzip2 -z";
3910
3911 if (log_chn->settings.bzip2_compression) {
3912 bzip2_command += " -";
3913 bzip2_command += IntToString(log_chn->settings.bzip2_compression);
3914 }
3915
3916 return new WriterPopen(log_chn, (bzip2_command + " > ").c_str(), ".bz2");
3917}
3918
3920{
3921 std::string pbzip2_command = "pbzip2 -c -z";
3922
3923 if (log_chn->settings.pbzip2_num_cpu) {
3924 pbzip2_command += " -p";
3925 pbzip2_command += IntToString(log_chn->settings.pbzip2_num_cpu);
3926 }
3927
3928 if (log_chn->settings.pbzip2_compression) {
3929 pbzip2_command += " -";
3930 pbzip2_command += IntToString(log_chn->settings.pbzip2_compression);
3931 }
3932
3933 if (strlen(log_chn->settings.pbzip2_options) > 0) {
3934 pbzip2_command += " ";
3935 pbzip2_command += log_chn->settings.pbzip2_options;
3936 }
3937
3938 return new WriterPopen(log_chn, (pbzip2_command + " > ").c_str(), ".bz2");
3939}
3940
3941#define CHECKSUM_NONE 0
3942#define CHECKSUM_ZLIB 1
3943#define CHECKSUM_CRC32C 2
3944#define CHECKSUM_SHA256 3
3945#define CHECKSUM_SHA512 4
3946
3948{
3949 if (code == CHECKSUM_NONE) {
3950 return chained;
3951 } else if (code == CHECKSUM_ZLIB) {
3952 return new WriterCRC32Zlib(log_chn, level, chained);
3953 } else if (code == CHECKSUM_CRC32C) {
3954 return new WriterCRC32C(log_chn, level, chained);
3955 } else if (code == CHECKSUM_SHA256) {
3956 return new WriterSHA256(log_chn, level, chained);
3957 } else if (code == CHECKSUM_SHA512) {
3958 return new WriterSHA512(log_chn, level, chained);
3959 } else {
3960 cm_msg(MERROR, "log_create_writer", "channel %s unknown checksum code %d", log_chn->path.c_str(), code);
3961 return chained;
3962 }
3963}
3964
3965#define COMPRESS_NONE 0
3966#define COMPRESS_ZLIB 1
3967#define COMPRESS_LZ4 2
3968#define COMPRESS_BZIP2 3
3969#define COMPRESS_PBZIP2 4
3970
3972{
3973 if (code == COMPRESS_NONE) {
3974 return chained;
3975 } else if (code == COMPRESS_LZ4) {
3976 return new WriterLZ4(log_chn, chained);
3977 } else {
3978 cm_msg(MERROR, "log_create_writer", "channel %s unknown compression code %d", log_chn->path.c_str(), code);
3979 return chained;
3980 }
3981}
3982
3983#define OUTPUT_NONE 0
3984#define OUTPUT_NULL 1
3985#define OUTPUT_FILE 2
3986#define OUTPUT_FTP 3
3987#define OUTPUT_ROOT 4
3988#define OUTPUT_PIPE 5
3989
3990std::string get_value(HNDLE hDB, HNDLE hDir, const char* name)
3991{
3993 value[0] = 0;
3994 int size = sizeof(value);
3995 int status = db_get_value(hDB, hDir, name, &value, &size, TID_STRING, FALSE);
3996 if (status != DB_SUCCESS)
3997 return "";
3998 return value;
3999}
4000
4001void set_value(HNDLE hDB, HNDLE hDir, const char* name, const std::string& set, const std::string& def)
4002{
4003 std::string s = set + " (one of:" + def + ")";
4004 int size = 256; // MUST match record definition // strlen(value);
4005 s.reserve(size);
4006 const char* value = s.c_str();
4007 db_set_value(hDB, hDir, name, value, size, 1, TID_STRING);
4008}
4009
4010int check_add(int v, int n, const std::string& val, const char* str, bool bdef, std::string* def, std::string* sel)
4011{
4012 (*def) += std::string(" ") + str;
4013 if (v)
4014 return v; // keep returning the first selection
4015 if (val.find(str) == 0) {
4016 *sel = str;
4017 return n; // if no selection yet, return the new selection
4018 }
4019 return v;
4020}
4021
4023{
4024 std::string val = get_value(hDB, hSet, name);
4025 std::string sel;
4026 std::string def;
4027 int s = 0;
4028 s = check_add(s, CHECKSUM_NONE, val, "NONE", false, &def, &sel);
4029 s = check_add(s, CHECKSUM_CRC32C, val, "CRC32C", true, &def, &sel);
4030 s = check_add(s, CHECKSUM_SHA256, val, "SHA256", false, &def, &sel);
4031 s = check_add(s, CHECKSUM_SHA512, val, "SHA512", false, &def, &sel);
4032 s = check_add(s, CHECKSUM_ZLIB, val, "ZLIB", false, &def, &sel);
4033 if (sel == "")
4034 sel = "NONE";
4035 //set_value(hDB, hSet, name, sel, def);
4036 return s;
4037}
4038
4040{
4041 std::string val = get_value(hDB, hSet, name);
4042 std::string sel;
4043 std::string def;
4044 int s = 0;
4045 s = check_add(s, COMPRESS_NONE, val, "none", false, &def, &sel);
4046 s = check_add(s, COMPRESS_ZLIB, val, "gzip", true, &def, &sel);
4047 s = check_add(s, COMPRESS_LZ4, val, "lz4", false, &def, &sel);
4048 s = check_add(s, COMPRESS_BZIP2, val, "bzip2", false, &def, &sel);
4049 s = check_add(s, COMPRESS_PBZIP2, val, "pbzip2", false, &def, &sel);
4050 if (sel == "")
4051 sel = "none";
4052 //set_value(hDB, hSet, name, sel, def);
4053 return s;
4054}
4055
4057{
4058 std::string val = get_value(hDB, hSet, name);
4059 std::string sel;
4060 std::string def;
4061 int s = 0;
4062 s = check_add(s, OUTPUT_NULL, val, "NULL", false, &def, &sel);
4063 s = check_add(s, OUTPUT_FILE, val, "FILE", true, &def, &sel);
4064 s = check_add(s, OUTPUT_FTP, val, "FTP", false, &def, &sel);
4065 s = check_add(s, OUTPUT_ROOT, val, "ROOT", false, &def, &sel);
4066 s = check_add(s, OUTPUT_PIPE, val, "PIPE", false, &def, &sel);
4067 if (sel == "")
4068 sel = "FILE";
4069 //set_value(hDB, hSet, name, sel, def);
4070 return s;
4071}
4072
4074{
4075 assert(log_chn->writer == NULL);
4076 log_chn->writer = NULL;
4077
4078 if (log_chn->output_module > 0) {
4079
4080 if (log_chn->compression_module == COMPRESS_ZLIB) {
4081
4082 if (log_chn->output_module != OUTPUT_FILE) {
4083 cm_msg(MERROR, "log_create_writer", "channel %s requested GZIP/ZLIB compression, output module must be FILE", log_chn->path.c_str());
4084 return SS_FILE_ERROR;
4085 }
4086
4087 log_chn->writer = new WriterGzip(log_chn, 0);
4088 log_chn->do_disk_level = TRUE;
4089 }
4090 else if (log_chn->compression_module == COMPRESS_BZIP2) {
4091
4092 if (log_chn->output_module != OUTPUT_FILE) {
4093 cm_msg(MERROR, "log_create_writer", "channel %s requested BZIP2 compression, output module must be FILE", log_chn->path.c_str());
4094 return SS_FILE_ERROR;
4095 }
4096
4097 log_chn->writer = NewWriterBzip2(log_chn);
4098 log_chn->do_disk_level = TRUE;
4099
4100 }
4101 else if (log_chn->compression_module == COMPRESS_PBZIP2) {
4102
4103 if (log_chn->output_module != OUTPUT_FILE) {
4104 cm_msg(MERROR, "log_create_writer", "channel %s requested PBZIP2 compression, output module must be FILE", log_chn->path.c_str());
4105 return SS_FILE_ERROR;
4106 }
4107
4108 log_chn->writer = NewWriterPbzip2(log_chn);
4109 log_chn->do_disk_level = TRUE;
4110 }
4111 else if (log_chn->output_module == OUTPUT_NULL) {
4112
4113 log_chn->writer = new WriterNull(log_chn);
4114 log_chn->do_disk_level = TRUE;
4115 }
4116 else if (log_chn->output_module == OUTPUT_FILE) {
4117
4118 log_chn->writer = NewCompression(log_chn, log_chn->compression_module, NewChecksum(log_chn, log_chn->post_checksum_module, 0, new WriterFile(log_chn)));
4119 log_chn->do_disk_level = TRUE;
4120 }
4121 else if (log_chn->output_module == OUTPUT_FTP) {
4122
4123 log_chn->writer = NewCompression(log_chn, log_chn->compression_module, NewChecksum(log_chn, log_chn->post_checksum_module, 0, new WriterFtp(log_chn)));
4124 log_chn->do_disk_level = FALSE;
4125 log_chn->statistics.disk_level = -1;
4126 }
4127 else if (log_chn->output_module == OUTPUT_ROOT) {
4128
4129#ifdef HAVE_ROOT
4130 log_chn->writer = new WriterROOT(log_chn);
4131 log_chn->do_disk_level = TRUE;
4132#else
4133 cm_msg(MERROR, "log_create_writer", "channel \"%s\" requested ROOT output, but mlogger is built without HAVE_ROOT", log_chn->name.c_str());
4134 log_chn->writer = new WriterNull(log_chn);
4135 log_chn->do_disk_level = TRUE;
4136#endif
4137 }
4138 else if (log_chn->output_module == OUTPUT_PIPE) {
4139
4140 log_chn->writer = NewCompression(log_chn, log_chn->compression_module, NewChecksum(log_chn, log_chn->post_checksum_module, 0, new WriterPopen(log_chn, "xxx", "")));
4141 log_chn->do_disk_level = FALSE;
4142 log_chn->statistics.disk_level = -1;
4143 }
4144
4145 //log_chn->writer = new WriterROOT(log_chn);
4146 //log_chn->do_disk_level = TRUE;
4147
4148 if (log_chn->pre_checksum_module) {
4149 log_chn->writer = NewChecksum(log_chn, log_chn->pre_checksum_module, 1, log_chn->writer);
4150 }
4151
4152 //cm_msg(MINFO, "log_create_writer", "channel \"%s\" writer chain: %s", log_chn->path.c_str(), log_chn->writer->wr_get_chain().c_str());
4153
4154 return SUCCESS;
4155 }
4156
4157 cm_msg(MERROR, "log_create_writer", "channel %s invalid output module value %d", log_chn->path.c_str(), log_chn->output_module);
4158 return SS_FILE_ERROR;
4159
4160#ifdef OBSOLETE
4161 int xcompress = log_chn->compression;
4162 // compression format: ABNNN
4163 // A - pre-compression checksum,
4164 // B - post-compression (file) checksum,
4165 // NNN - compression code
4166 int compression = xcompress%1000;
4167 int prechecksum = (xcompress/10000)%10;
4168 int postchecksum = (xcompress/1000)%10;
4169
4170 // 0=old file output, 1-9=old gzip output
4171 if (compression < 10)
4172 return SUCCESS;
4173
4174 if (compression==80) {
4175#ifdef HAVE_ROOT
4176 log_chn->writer = new WriterROOT(log_chn);
4177 log_chn->do_disk_level = TRUE;
4178#else
4179 log_chn->writer = new WriterNull(log_chn);
4180 log_chn->do_disk_level = TRUE;
4181#endif
4182 } else if (compression==81) {
4183 log_chn->writer = new WriterFtp(log_chn);
4184 log_chn->do_disk_level = FALSE;
4185 log_chn->statistics.disk_level = -1;
4186 } else if (compression==82) {
4188 log_chn->do_disk_level = FALSE;
4189 log_chn->statistics.disk_level = -1;
4190 } else if (compression==98) {
4191 log_chn->writer = new WriterNull(log_chn);
4192 log_chn->do_disk_level = TRUE;
4193 } else if (compression==99) {
4194 log_chn->writer = new WriterFile(log_chn);
4195 log_chn->do_disk_level = TRUE;
4196 } else if (compression==100) {
4198 log_chn->do_disk_level = TRUE;
4199 } else if (compression==200) {
4200 log_chn->writer = NewWriterBzip2(log_chn);
4201 log_chn->do_disk_level = TRUE;
4202 } else if (compression==201) {
4203 log_chn->writer = NewWriterPbzip2(log_chn);
4204 log_chn->do_disk_level = TRUE;
4205 } else if (compression==300) {
4206 log_chn->writer = new WriterGzip(log_chn, 0);
4207 log_chn->do_disk_level = TRUE;
4208 } else if (compression==301) {
4209 log_chn->writer = new WriterGzip(log_chn, 1);
4210 log_chn->do_disk_level = TRUE;
4211 } else if (compression==309) {
4212 log_chn->writer = new WriterGzip(log_chn, 9);
4213 log_chn->do_disk_level = TRUE;
4214 } else {
4215 cm_msg(MERROR, "log_create_writer", "channel %s unknown compression mode %d", log_chn->path.c_str(), log_chn->compression);
4216 return SS_FILE_ERROR;
4217 }
4218
4219 if (prechecksum) {
4220 log_chn->writer = NewChecksum(log_chn, prechecksum, 1, log_chn->writer);
4221 }
4222#endif
4223
4224 return SS_SUCCESS;
4225}
4226
4227/*---- log_open ----------------------------------------------------*/
4228
4230{
4231 INT status = SUCCESS;
4232
4233 log_chn->last_checked = ss_millitime();
4234
4235 if (log_chn->writer) {
4236 WriterInterface* wr = log_chn->writer;
4237
4239
4240 if (status != SUCCESS)
4241 return status;
4242
4243 /* write ODB dump */
4244 if (log_chn->settings.odb_dump)
4246
4247 /* update statistics */
4248 double incr = wr->fBytesOut - log_chn->statistics.bytes_written_subrun;
4249 if (incr < 0)
4250 incr = 0;
4251
4252 //printf("bytes out %f, incr %f, subrun %f, written %f, total %f (log_open)\n", wr->fBytesOut, incr, log_chn->statistics.bytes_written_subrun, log_chn->statistics.bytes_written, log_chn->statistics.bytes_written_total);
4253
4254 log_chn->statistics.bytes_written += incr;
4255 log_chn->statistics.bytes_written_subrun = wr->fBytesOut;
4256 log_chn->statistics.bytes_written_total += incr;
4257 } else {
4258 return SS_INVALID_FORMAT;
4259 }
4260#ifdef OBSOLETE
4261 } else if (equal_ustring(log_chn->settings.format, "ROOT")) {
4262#ifdef HAVE_ROOT
4263 log_chn->format = FORMAT_ROOT;
4265#else
4266 return SS_NO_ROOT;
4267#endif
4268 } else if (equal_ustring(log_chn->settings.format, "MIDAS")) {
4269 log_chn->format = FORMAT_MIDAS;
4271 } else
4272 return SS_INVALID_FORMAT;
4273#endif
4274 return status;
4275}
4276
4277/*---- log_close ---------------------------------------------------*/
4278
4280{
4281 if (log_chn->writer) {
4282 /* write ODB dump */
4283 if (log_chn->settings.odb_dump)
4285
4286 WriterInterface* wr = log_chn->writer;
4287
4289
4290 /* update statistics */
4291
4292 double incr = wr->fBytesOut - log_chn->statistics.bytes_written_subrun;
4293 if (incr < 0)
4294 incr = 0;
4295
4296 //printf("bytes out %f, incr %f, subrun %f, written %f, total %f (log_close)\n", wr->fBytesOut, incr, log_chn->statistics.bytes_written_subrun, log_chn->statistics.bytes_written, log_chn->statistics.bytes_written_total);
4297
4298 log_chn->statistics.bytes_written += incr;
4299 log_chn->statistics.bytes_written_subrun = wr->fBytesOut;
4300 log_chn->statistics.bytes_written_total += incr;
4301 }
4302#ifdef OBSOLETE
4303#ifdef HAVE_ROOT
4304 } else if (log_chn->format == FORMAT_ROOT) {
4306#endif
4307 } else if (log_chn->format == FORMAT_MIDAS) {
4309 }
4310#endif
4311
4312 /* if file name starts with '.', rename it */
4313 char str[256]; // FIXME: this will truncate the filename of the output file. K.O.
4314 mstrlcpy(str, log_chn->path.c_str(), sizeof(str));
4315 char* p = str;
4316 if (strrchr(str, DIR_SEPARATOR)) {
4317 p = strrchr(str, DIR_SEPARATOR)+1;
4318 }
4319 if (*p == '.') {
4320 mstrlcpy(p, p+1, sizeof(str));
4321 rename(log_chn->path.c_str(), str); // FIXME: must check return status. K.O.
4322 }
4323
4324 log_chn->statistics.files_written += 1;
4325 log_chn->handle = 0;
4326 log_chn->ftp_con = NULL;
4327
4328 if (log_chn->writer) {
4329 delete log_chn->writer;
4330 log_chn->writer = NULL;
4331 }
4332
4333 return SS_SUCCESS;
4334}
4335
4336/*---- log disk levels ---------------------------------------------*/
4337
4339{
4340 std::string str = log_chn->path.c_str();
4341 size_t pos = str.rfind('/');
4342 if (pos != std::string::npos) {
4343 str.erase(pos); // strip filename for bzip2
4344 }
4345
4346 //printf("log_disk_level [%s] [%s]\n", log_chn->path.c_str(), str.c_str());
4347
4348 double MiB = 1024*1024;
4349 double disk_size = ss_disk_size(str.c_str());
4350 double disk_free = ss_disk_free(str.c_str());
4351 double limit = 10E6;
4352 double level = 1.0-disk_free/disk_size;
4353
4354 if (pdisk_size)
4355 *pdisk_size = disk_size; // should be in statistics
4356 if (pdisk_free)
4357 *pdisk_free = disk_free; // should be in statistics
4358
4359 log_chn->statistics.disk_level = level;
4360
4361 if (verbose)
4362 printf("log_disk_level: channel path [%s], disk_size %1.0lf MiB, disk_free %1.0lf MiB, limit %1.0f MiB, disk level %.1f%%\n", log_chn->path.c_str(), disk_size/MiB, disk_free/MiB, limit/MiB, level*100.0);
4363
4364 return SUCCESS;
4365}
4366
4368{
4370 static DWORD last_check_time = 0;
4371
4372 if (last_check_time == 0)
4374
4376 return SUCCESS;
4377
4379
4380 for (unsigned i = 0; i < log_channels.size(); i++) {
4382
4383 if (!chn->do_disk_level)
4384 continue;
4385
4387 }
4388
4389 return SUCCESS;
4390}
4391
4392static int get_trans_flag()
4393{
4394 int status, size, flag;
4395
4396 size = sizeof(BOOL);
4397 flag = FALSE;
4398 status = db_get_value(hDB, 0, "/Logger/Async transitions", &flag, &size, TID_BOOL, FALSE);
4399
4400 if (status == DB_SUCCESS) {
4401 cm_msg(MINFO, "get_trans_flag", "ODB \"/Logger/Async transitions\" is obsolete, please delete it");
4402 }
4403
4404 size = sizeof(BOOL);
4405 flag = TRUE;
4406 status = db_get_value(hDB, 0, "/Logger/Multithread transitions", &flag, &size, TID_BOOL, FALSE);
4407
4408 if (status == DB_SUCCESS) {
4409 cm_msg(MINFO, "get_trans_flag", "ODB \"/Logger/Multithread transitions\" is obsolete, please delete it");
4410 }
4411
4412 size = sizeof(BOOL);
4413 flag = FALSE;
4414 db_get_value(hDB, 0, "/Logger/Detached transitions", &flag, &size, TID_BOOL, TRUE);
4415
4416 // NB: we must use multithread or detached (via mtransition) transition
4417 // otherwise we deadlock against frontends: they are writing to the SYSTEM
4418 // buffer but we (mlogger) are not reading from it. if SYSTEM buffer is full,
4419 // clients get stuck waiting for free space and cannot not handle TR_STOP RPC.
4420 // if they could handle, it, they would still be stuck in bm_flush_cache()
4421 // because we (mlogger) are not reading the SYSTEM buffer and these last
4422 // events have nowhere to go. K.O.
4423
4424 if (flag)
4425 return TR_DETACH;
4426 else
4427 return TR_MTHREAD;
4428}
4429
4430/*---- log_write ---------------------------------------------------*/
4431
4433{
4434 int status, flag, size;
4435 char errstr[256];
4436
4437 if (restart) {
4438 size = sizeof(BOOL);
4439 flag = FALSE;
4440 db_get_value(hDB, 0, "/Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
4441
4442 if (flag) {
4444 auto_restart = 0;
4445 }
4446 }
4447
4449 stop_try_later = 0;
4450
4451 int trans_flag = get_trans_flag();
4452
4453 status = cm_transition(TR_STOP, 0, errstr, sizeof(errstr), trans_flag, verbose);
4455 cm_msg(MERROR, "stop_the_run", "another transition is in progress, will try again later");
4457 stop_try_later = ss_time_sec() + 10.0;
4458 } else if (status != CM_SUCCESS) {
4459 cm_msg(MERROR, "stop_the_run", "cannot stop the run, cm_transition() status %d, error: %s", status, errstr);
4460 return status;
4461 }
4462
4463 return status;
4464}
4465
4467{
4468 int status, size, state, run_number, flag;
4469 char errstr[256];
4470
4472 auto_restart = 0;
4473
4474 /* check if autorestart is still on */
4475 size = sizeof(BOOL);
4476 flag = FALSE;
4477 db_get_value(hDB, 0, "/Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
4478
4479 if (!flag) {
4480 cm_msg(MINFO, "start_the_run", "Run auto restart canceled");
4481 return SUCCESS;
4482 }
4483
4484 /* check if really stopped */
4485 size = sizeof(state);
4486 status = db_get_value(hDB, 0, "Runinfo/State", &state, &size, TID_INT32, TRUE);
4487 if (status != DB_SUCCESS) {
4488 cm_msg(MERROR, "start_the_run", "cannot get Runinfo/State in database, db_get_value() status %d", status);
4489 return status;
4490 }
4491
4492 static int backoff = 1;
4493
4494 if (state != STATE_STOPPED) {
4495 cm_msg(MINFO, "start_the_run", "Runinfo/State %d is not STATE_STOPPED, will try again in %d seconds", state, backoff);
4496 auto_restart = ss_time() + backoff; /* try again later */
4497 if (backoff < 1)
4498 backoff = 1;
4499 else if (backoff > 1*60)
4500 backoff = 1*60;
4501 else
4502 backoff *= 2;
4503 return SUCCESS;
4504 }
4505
4506 backoff = 1;
4507
4508 size = sizeof(run_number);
4509 status = db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
4510 assert(status == SUCCESS);
4511
4512 if (run_number <= 0) {
4513 cm_msg(MERROR, "start_the_run", "aborting on attempt to use invalid run number %d", run_number);
4514 abort();
4515 }
4516
4517 int trans_flag = get_trans_flag();
4518
4519 cm_msg(MTALK, "start_the_run", "starting new run");
4520 status = cm_transition(TR_START, run_number + 1, errstr, sizeof(errstr), trans_flag, verbose);
4521 if (status != CM_SUCCESS)
4522 cm_msg(MERROR, "start_the_run", "cannot restart run: cm_transition() status %d, error: %s", status, errstr);
4523
4524 return status;
4525}
4526
4528{
4529 INT status = 0, size;
4532
4533 //printf("log_write %d\n", pevent->data_size + sizeof(EVENT_HEADER));
4534
4535 DWORD start_time = ss_millitime();
4536 int evt_size = pevent->data_size + sizeof(EVENT_HEADER);
4537
4538 if (log_chn->writer) {
4539 WriterInterface* wr = log_chn->writer;
4540 status = wr->wr_write(log_chn, pevent, evt_size);
4541
4542 if (status == SUCCESS) {
4543 /* update statistics */
4544 log_chn->statistics.events_written++;
4545 log_chn->statistics.bytes_written_uncompressed += evt_size;
4546 }
4547
4548 double incr = wr->fBytesOut - log_chn->statistics.bytes_written_subrun;
4549 if (incr < 0)
4550 incr = 0;
4551
4552 //printf("events %.0f, bytes out %.0f, incr %.0f, subrun %.0f, written %.0f, total %.0f\n", log_chn->statistics.events_written, wr->fBytesOut, incr, log_chn->statistics.bytes_written_subrun, log_chn->statistics.bytes_written, log_chn->statistics.bytes_written_total);
4553
4554 log_chn->statistics.bytes_written += incr;
4555 log_chn->statistics.bytes_written_subrun = wr->fBytesOut;
4556 log_chn->statistics.bytes_written_total += incr;
4557 }
4558#ifdef OBSOLETE
4559 } else {
4560 int written = 0;
4561
4562 if (log_chn->format == FORMAT_MIDAS) {
4563 written = midas_write(log_chn, pevent, pevent->data_size + sizeof(EVENT_HEADER));
4564#ifdef HAVE_ROOT
4565 } else if (log_chn->format == FORMAT_ROOT) {
4566 written = root_write(log_chn, pevent, pevent->data_size + sizeof(EVENT_HEADER));
4567#endif
4568 }
4569
4570 /* update statistics */
4571 if (written > 0) {
4572 log_chn->statistics.events_written++;
4573 log_chn->statistics.bytes_written_uncompressed += evt_size;
4574 log_chn->statistics.bytes_written += written;
4575 log_chn->statistics.bytes_written_total += written;
4576 log_chn->statistics.bytes_written_subrun += written;
4577 }
4578
4579 if (written < 0)
4581 else
4583 }
4584#endif
4585
4587 if (actual_time - start_time > 3000)
4588 cm_msg(MINFO, "log_write", "Write operation on \'%s\' took %d ms", log_chn->path.c_str(), actual_time - start_time);
4589
4590 if (status != SS_SUCCESS && !stop_requested) {
4591 cm_msg(MTALK, "log_write", "Error writing output file, stopping run");
4592 cm_msg(MERROR, "log_write", "Cannot write \'%s\', error %d, stopping run", log_chn->path.c_str(), status);
4593 stop_the_run(0);
4594
4595 return status;
4596 }
4597
4598 /* check if event limit is reached to stop run */
4600 log_chn->settings.event_limit > 0 &&
4601 log_chn->statistics.events_written >= log_chn->settings.event_limit) {
4603
4604 cm_msg(MTALK, "log_write", "stopping run after having received %1.0lf events",
4605 log_chn->settings.event_limit);
4606
4607 status = stop_the_run(1);
4608 return status;
4609 }
4610
4611 /* check if duration is reached for subrun */
4612 duration = 0;
4613 size = sizeof(duration);
4614 db_get_value(hDB, 0, "/Logger/Subrun duration", &duration, &size, TID_UINT32, TRUE);
4616 int run_number;
4617
4618 // cm_msg(MTALK, "main", "stopping subrun after %d seconds", duration);
4619
4620 size = sizeof(run_number);
4621 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
4622 assert(status == SUCCESS);
4623
4624 stop_requested = TRUE; // avoid recursive call thourgh log_odb_dump
4626 log_chn->subrun_number++;
4627 log_chn->statistics.bytes_written_subrun = 0;
4633 }
4634
4635 /* check if byte limit is reached for subrun */
4636 if (!stop_requested && log_chn->settings.subrun_byte_limit > 0 &&
4637 log_chn->statistics.bytes_written_subrun >= log_chn->settings.subrun_byte_limit) {
4638 int run_number;
4639
4640 // cm_msg(MTALK, "main", "stopping subrun after %1.0lf bytes", log_chn->settings.subrun_byte_limit);
4641
4642 size = sizeof(run_number);
4643 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
4644 assert(status == SUCCESS);
4645
4646 stop_requested = TRUE; // avoid recursive call thourgh log_odb_dump
4648 log_chn->subrun_number++;
4649 log_chn->statistics.bytes_written_subrun = 0;
4655 }
4656
4657 /* check if new subrun is requested manually */
4659 size = sizeof(next_subrun);
4660 db_get_value(hDB, 0, "/Logger/Next subrun", &next_subrun, &size, TID_BOOL, true);
4661 if (!stop_requested && next_subrun) {
4662 int run_number;
4663
4664 // cm_msg(MTALK, "main", "stopping subrun by user request");
4665
4666 size = sizeof(run_number);
4667 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
4668 assert(status == SUCCESS);
4669
4670 stop_requested = TRUE; // avoid recursive call thourgh log_odb_dump
4672 log_chn->subrun_number++;
4673 log_chn->statistics.bytes_written_subrun = 0;
4679
4681 db_set_value(hDB, 0, "/Logger/Next subrun", &next_subrun, sizeof(next_subrun), 1, TID_BOOL);
4682 }
4683
4684 /* check if byte limit is reached to stop run */
4686 log_chn->settings.byte_limit > 0 &&
4687 log_chn->statistics.bytes_written >= log_chn->settings.byte_limit) {
4689
4690 cm_msg(MTALK, "log_write", "stopping run after having received %1.0lf mega bytes",
4691 log_chn->statistics.bytes_written / 1E6);
4692
4693 status = stop_the_run(1);
4694
4695 return status;
4696 }
4697
4698 /* stop run if less than 10MB free disk space */
4700 if (log_chn->type == LOG_TYPE_DISK && log_chn->do_disk_level && actual_time - log_chn->last_checked > DISK_CHECK_INTERVAL_MILLISEC) {
4701 log_chn->last_checked = actual_time;
4702
4703 const double MiB = 1024*1024;
4704 double disk_size = 0;
4705 double disk_free = 0;
4706
4708
4709 double limit = 10E6;
4710
4711 if (disk_size > 100E9) {
4712 limit = 1000E6;
4713 } else if (disk_size > 10E9) {
4714 limit = 100E6;
4715 }
4716
4717 if (disk_free < limit) {
4719 cm_msg(MTALK, "log_write", "disk nearly full, stopping the run");
4720 cm_msg(MERROR, "log_write", "Disk \'%s\' is almost full: %1.0lf MiBytes free out of %1.0f MiBytes, stopping the run", log_chn->path.c_str(), disk_free/MiB, disk_size/MiB);
4721
4722 status = stop_the_run(0);
4723 }
4724 }
4725
4726 return status;
4727}
4728
4729/*---- open_history ------------------------------------------------*/
4730
4731void log_history(HNDLE hDB, HNDLE hKey, void *info);
4732
4733#include "history.h"
4734
4735static std::vector<MidasHistoryInterface*> mh;
4736static std::vector<std::string> history_events;
4737
4738static int add_event(int* indexp, time_t timestamp, int event_id, const char* event_name, HNDLE hKey, int ntags, const TAG* tags, time_t min_period, int hotlink)
4739{
4740 int status;
4741 int size, i;
4742 int index = *indexp;
4743
4744#if 0
4745 {
4746 /* print the tags */
4747 printf("add_event: event %d, name \"%s\", ntags %d\n", event_id, event_name, ntags);
4748 for (i=0; i<ntags; i++) {
4749 printf("tag %d: name \"%s\", type %d, n_data %d\n", i, tags[i].name, tags[i].type, tags[i].n_data);
4750 }
4751 }
4752#endif
4753
4754 /* check for duplicate event id's */
4755 for (i=0; i<index; i++) {
4756 if (strcmp(hist_log[i].event_name, event_name) == 0) {
4757 cm_msg(MERROR, "add_event", "Duplicate event name \'%s\' with event id %d", event_name, event_id);
4758 return 0;
4759 }
4760 }
4761
4762 while (index >= hist_log_size) {
4763 int new_size = 2*hist_log_size;
4764
4765 if (hist_log_size == 0)
4766 new_size = 10;
4767
4769 assert(hist_log!=NULL);
4770
4772 }
4773
4774 if (index >= hist_log_max)
4775 hist_log_max = index + 1;
4776
4777 /* check for invalid history tags */
4778 for (i=0; i<ntags; i++) {
4779 if (tags[i].type == TID_STRING) {
4780 cm_msg(MERROR, "add_event", "Invalid tag %d \'%s\' in event %d \'%s\': cannot do history for TID_STRING data, sorry!", i, tags[i].name, event_id, event_name);
4781 return 0;
4782 }
4783 if (tags[i].type == TID_INT64) {
4784 cm_msg(MERROR, "add_event", "Invalid tag %d \'%s\' in event %d \'%s\': cannot do history for TID_INT64 data, sorry!", i, tags[i].name, event_id, event_name);
4785 return 0;
4786 }
4787 if (tags[i].type == TID_UINT64) {
4788 cm_msg(MERROR, "add_event", "Invalid tag %d \'%s\' in event %d \'%s\': cannot do history for TID_UINT64 data, sorry!", i, tags[i].name, event_id, event_name);
4789 return 0;
4790 }
4791 if (rpc_tid_size(tags[i].type) == 0) {
4792 cm_msg(MERROR, "add_event", "Invalid tag %d \'%s\' in event %d \'%s\': type %d size is zero", i, tags[i].name, event_id, event_name, tags[i].type);
4793 return 0;
4794 }
4795 }
4796
4797 /* check for trailing spaces in tag names */
4798 for (i=0; i<ntags; i++) {
4799 if (isspace(tags[i].name[strlen(tags[i].name)-1])) {
4800 cm_msg(MERROR, "add_event", "Invalid tag %d \'%s\' in event %d \'%s\': has trailing spaces", i, tags[i].name, event_id, event_name);
4801 return 0;
4802 }
4803 }
4804
4805 for (unsigned i=0; i<mh.size(); i++) {
4806 status = mh[i]->hs_define_event(event_name, timestamp, ntags, tags);
4807 if (status != HS_SUCCESS) {
4808 cm_msg(MERROR, "add_event", "Cannot define event \"%s\", hs_define_event() status %d", event_name, status);
4809 return 0;
4810 }
4811 }
4812
4813 status = db_get_record_size(hDB, hKey, 0, &size);
4814
4815 if (status != DB_SUCCESS) {
4816 cm_msg(MERROR, "add_event", "Cannot define event \"%s\", db_get_record_size() status %d", event_name, status);
4817 return 0;
4818 }
4819
4820 /* setup hist_log structure for this event */
4821 mstrlcpy(hist_log[index].event_name, event_name, sizeof(hist_log[index].event_name));
4824 hist_log[index].buffer_size = size;
4825 hist_log[index].buffer = (char*)malloc(size);
4826 hist_log[index].min_period = min_period;
4827 hist_log[index].last_log = 0;
4828
4829 if (hist_log[index].buffer == NULL) {
4830 cm_msg(MERROR, "add_event", "Cannot allocate data buffer for event \"%s\" size %d", event_name, size);
4831 return 0;
4832 }
4833
4834 /* open hot link to variables */
4835 if (hotlink) {
4837 if (status != DB_SUCCESS) {
4838 cm_msg(MERROR, "add_event",
4839 "Cannot hotlink event %d \"%s\" for history logging, db_open_record() status %d",
4840 event_id, event_name, status);
4841 return status;
4842 }
4843 }
4844
4845 history_events.push_back(event_name);
4846
4847 if (verbose)
4848 printf("Created event %d for equipment \"%s\", %d tags, size %d\n", event_id, event_name, ntags, size);
4849
4850 *indexp = index+1;
4851
4852 return SUCCESS;
4853}
4854
4856{
4857 INT size, index, i_tag, status, i, j, li, max_event_id;
4858 int ieq;
4859 INT n_var, n_tags, n_names = 0;
4862 TAG *tag = NULL;
4864 WORD eq_id;
4867
4868 time_t now = time(NULL);
4869
4870 double tstart = ss_time_sec();
4871
4872 // delete old history channels
4873
4874 for (unsigned i=0; i<mh.size(); i++)
4875 delete mh[i];
4876 mh.clear();
4877
4878 history_events.clear();
4879
4880 // create and initialize the history channels tree
4881
4882 status = db_find_key(hDB, 0, "/Logger/History", &hKeyHist);
4883
4884 if (status == DB_NO_KEY) {
4885 int active;
4886 std::string type;
4887 int debug;
4888
4889 // create entry for FILE history
4890
4891 type = "FILE";
4892 status = db_get_value_string(hDB, 0, "/Logger/History/FILE/Type", 0, &type, TRUE);
4893 assert(status==DB_SUCCESS);
4894
4895 active = 1;
4896 size = sizeof(active);
4897 status = db_get_value(hDB, 0, "/Logger/History/FILE/Active", &active, &size, TID_BOOL, TRUE);
4898 assert(status==DB_SUCCESS);
4899
4900 debug = 0;
4901 size = sizeof(debug);
4902 status = db_get_value(hDB, 0, "/Logger/History/FILE/Debug", &debug, &size, TID_INT32, TRUE);
4903 assert(status==DB_SUCCESS);
4904
4905 int per_variable = 1;
4906 size = sizeof(per_variable);
4907 status = db_get_value(hDB, 0, "/Logger/History/FILE/PerVariableHistory", &per_variable, &size, TID_INT32, TRUE);
4908 assert(status==DB_SUCCESS);
4909
4910 // create entry for the MIDAS history
4911
4912 type = "MIDAS";
4913 status = db_get_value_string(hDB, 0, "/Logger/History/MIDAS/Type", 0, &type, TRUE);
4914 assert(status==DB_SUCCESS);
4915
4916 active = 0;
4917 size = sizeof(active);
4918 status = db_get_value(hDB, 0, "/Logger/History/MIDAS/Active", &active, &size, TID_BOOL, TRUE);
4919 assert(status==DB_SUCCESS);
4920
4921 debug = 0;
4922 size = sizeof(debug);
4923 status = db_get_value(hDB, 0, "/Logger/History/MIDAS/Debug", &debug, &size, TID_INT32, TRUE);
4924 assert(status==DB_SUCCESS);
4925
4926 // create entry for ODBC (MySQL) history
4927
4928 type = "ODBC";
4929 status = db_get_value_string(hDB, 0, "/Logger/History/ODBC/Type", 0, &type, TRUE);
4930 assert(status==DB_SUCCESS);
4931
4932 active = 0;
4933 size = sizeof(active);
4934 status = db_get_value(hDB, 0, "/Logger/History/ODBC/Active", &active, &size, TID_BOOL, TRUE);
4935 assert(status==DB_SUCCESS);
4936
4937 debug = 0;
4938 size = sizeof(debug);
4939 status = db_get_value(hDB, 0, "/Logger/History/ODBC/Debug", &debug, &size, TID_INT32, TRUE);
4940 assert(status==DB_SUCCESS);
4941
4942 // create entry for SQLITE history
4943
4944 type = "SQLITE";
4945 status = db_get_value_string(hDB, 0, "/Logger/History/SQLITE/Type", 0, &type, TRUE);
4946 assert(status==DB_SUCCESS);
4947
4948 active = 0;
4949 size = sizeof(active);
4950 status = db_get_value(hDB, 0, "/Logger/History/SQLITE/Active", &active, &size, TID_BOOL, TRUE);
4951 assert(status==DB_SUCCESS);
4952
4953 debug = 0;
4954 size = sizeof(debug);
4955 status = db_get_value(hDB, 0, "/Logger/History/SQLITE/Debug", &debug, &size, TID_INT32, TRUE);
4956 assert(status==DB_SUCCESS);
4957
4958 // create entry for MYSQL history writer
4959
4960 type = "MYSQL";
4961 status = db_get_value_string(hDB, 0, "/Logger/History/MYSQL/Type", 0, &type, TRUE);
4962 assert(status==DB_SUCCESS);
4963
4964 active = 0;
4965 size = sizeof(active);
4966 status = db_get_value(hDB, 0, "/Logger/History/MYSQL/Active", &active, &size, TID_BOOL, TRUE);
4967 assert(status==DB_SUCCESS);
4968
4969 debug = 0;
4970 size = sizeof(debug);
4971 status = db_get_value(hDB, 0, "/Logger/History/MYSQL/Debug", &debug, &size, TID_INT32, TRUE);
4972 assert(status==DB_SUCCESS);
4973
4974 // create entry for PGSQL history writer
4975
4976 type = "PGSQL";
4977 status = db_get_value_string(hDB, 0, "/Logger/History/PGSQL/Type", 0, &type, TRUE);
4978 assert(status==DB_SUCCESS);
4979
4980 active = 0;
4981 size = sizeof(active);
4982 status = db_get_value(hDB, 0, "/Logger/History/PGSQL/Active", &active, &size, TID_BOOL, TRUE);
4983 assert(status==DB_SUCCESS);
4984
4985 debug = 0;
4986 size = sizeof(debug);
4987 status = db_get_value(hDB, 0, "/Logger/History/PGSQL/Debug", &debug, &size, TID_INT32, TRUE);
4988 assert(status==DB_SUCCESS);
4989
4990 // get newly created /Logger/History
4991
4992 status = db_find_key(hDB, 0, "/Logger/History", &hKeyHist);
4993 }
4994
4995 if (status != DB_SUCCESS) {
4996 cm_msg(MERROR, "open_history", "Something is wrong with /Logger/History, db_find_key() status %d", status);
4997 return status;
4998 }
4999
5000 // loop over history channels
5001
5002 for (int ichan = 0; ; ichan++) {
5004 if (status != DB_SUCCESS)
5005 break;
5006
5008
5010
5011 if (status==HS_SUCCESS && hi) {
5012 if (strcasecmp(hi->type, "MIDAS")==0) {
5013 i = 0;
5014 size = sizeof(i);
5015 status = db_get_value(hDB, hKey, "PerVariableHistory", &i, &size, TID_INT32, TRUE);
5016 assert(status==DB_SUCCESS);
5017
5018 if (i)
5020 } else if (strcasecmp(hi->type, "FILE")==0) {
5021 i = 0;
5022 size = sizeof(i);
5023 status = db_get_value(hDB, hKey, "PerVariableHistory", &i, &size, TID_INT32, TRUE);
5024 assert(status==DB_SUCCESS);
5025
5026 if (i)
5028 } else if (strcasecmp(hi->type, "ODBC")==0) {
5030 } else if (strcasecmp(hi->type, "SQLITE")==0) {
5032 } else if (strcasecmp(hi->type, "MYSQL")==0) {
5034 } else if (strcasecmp(hi->type, "PGSQL")==0) {
5036 }
5037
5038 if (verbose)
5039 cm_msg(MINFO, "open_history", "Writing history to channel \'%s\' type \'%s\'", hi->name, hi->type);
5040
5041 mh.push_back(hi);
5042 }
5043 }
5044
5045 // prepare history channels
5046
5047 for (unsigned i=0; i<mh.size(); i++) {
5048 status = mh[i]->hs_clear_cache();
5049 assert(status == HS_SUCCESS);
5050 }
5051
5052 // check global per-variable history settings
5053
5054 i = 0;
5055 size = sizeof(i);
5056 status = db_get_value(hDB, 0, "/History/PerVariableHistory", &i, &size, TID_INT32, FALSE);
5057 if (status==DB_SUCCESS) {
5058 cm_msg(MERROR, "open_history", "mlogger ODB setting /History/PerVariableHistory is obsolete, please delete it. Use /Logger/History/MIDAS/PerVariableHistory instead");
5059 if (i)
5061 }
5062
5064 static int previous = -1;
5067 cm_msg(MINFO, "open_history", "Per-variable history is enabled");
5068 else
5069 ;//cm_msg(MINFO, "open_history", "Per-variable history is disabled");
5070 }
5072 }
5073
5074 // setup history links
5075
5076 if (db_find_key(hDB, 0, "/History/Links", &hKeyRoot) != DB_SUCCESS ||
5077 db_find_key(hDB, 0, "/History/Links/System", &hKeyRoot) != DB_SUCCESS) {
5078 /* create default history keys */
5079 db_create_key(hDB, 0, "/History/Links", TID_KEY);
5080
5081 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/Events per sec.", &hKeyEq) == DB_SUCCESS)
5082 db_create_link(hDB, 0, "/History/Links/System/Trigger per sec.",
5083 "/Equipment/Trigger/Statistics/Events per sec.");
5084
5085 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/kBytes per sec.", &hKeyEq) == DB_SUCCESS)
5086 db_create_link(hDB, 0, "/History/Links/System/Trigger kB per sec.",
5087 "/Equipment/Trigger/Statistics/kBytes per sec.");
5088 }
5089
5090 /*---- define equipment events as history ------------------------*/
5091
5092 max_event_id = 0;
5093
5094 status = db_find_key(hDB, 0, "/Equipment", &hKeyRoot);
5095 if (status == DB_NO_KEY) {
5096 cm_msg(MINFO, "open_history", "Cannot find /Equipment entry in database, history system is inactive");
5097 return CM_SUCCESS;
5098 }
5099
5100 if (status != DB_SUCCESS) {
5101 cm_msg(MERROR, "open_history", "Cannot find /Equipment entry in database, db_find_key() status %d", status);
5102 return status;
5103 }
5104
5105 /* loop over equipment */
5106 index = 0;
5107 for (ieq = 0; ; ieq++) {
5109 if (status != DB_SUCCESS)
5110 break;
5111
5112 int32_t min_period = 0; // in seconds
5113
5114 /* retrieve min period for history logging */
5115 size = sizeof(min_period);
5116 db_get_value(hDB, hKeyEq, "Common/Log history", &min_period, &size, TID_INT32, TRUE);
5117
5118 /* define history tags only if log history flag is on */
5119 if (min_period > 0) {
5121
5122 /* get equipment name */
5124 strcpy(eq_name, key.name);
5125
5126 if (strchr(eq_name, ':'))
5127 cm_msg(MERROR, "open_history", "Equipment name \'%s\' contains characters \':\', this may break the history system", eq_name);
5128
5129 status = db_find_key(hDB, hKeyEq, "Variables", &hKeyVar);
5130 if (status != DB_SUCCESS) {
5131 cm_msg(MERROR, "open_history", "Cannot find /Equipment/%s/Variables entry in database", eq_name);
5132 return 0;
5133 }
5134
5135 size = sizeof(eq_id);
5136 status = db_get_value(hDB, hKeyEq, "Common/Event ID", &eq_id, &size, TID_UINT16, TRUE);
5137 assert(status == DB_SUCCESS);
5138
5139 size = sizeof(int);
5140 status = db_get_value(hDB, hKeyEq, "Settings/PerVariableHistory", &per_variable_history, &size, TID_INT32, FALSE);
5141 assert(status == DB_SUCCESS || status == DB_NO_KEY);
5142
5143 if (verbose)
5144 printf
5145 ("\n==================== Equipment \"%s\", ID %d =======================\n",
5146 eq_name, eq_id);
5147
5148 /* count keys in variables tree */
5149 for (n_var = 0, n_tags = 0;; n_var++) {
5150 status = db_enum_key(hDB, hKeyVar, n_var, &hKey);
5152 break;
5153 db_get_key(hDB, hKey, &key);
5154 if (key.type != TID_KEY) {
5156 }
5157 else {
5158 int ii;
5159 for (ii=0;; ii++) {
5160 KEY vvarkey;
5161 HNDLE hhKey;
5162
5165 break;
5166
5167 /* get variable key */
5169
5170 n_tags += vvarkey.num_values;
5171 }
5172 }
5173 }
5174
5175 if (n_var == 0)
5176 cm_msg(MINFO, "open_history", "Equipment \"%s\" history is enabled, but there are no Variables in ODB", eq_name);
5177
5178 /* create tag array */
5179 tag = (TAG *) calloc(sizeof(TAG), n_tags);
5180
5181 i_tag = 0;
5182 for (i=0; ; i++) {
5183 status = db_enum_key(hDB, hKeyVar, i, &hKey);
5185 break;
5186
5187 /* get variable key */
5189
5190
5191 HNDLE hKeyNames = 0;
5192 BOOL single_names = false;
5193
5194 /* look for names */
5195
5196 if (!hKeyNames) {
5197 sprintf(str, "Settings/Names %s", varkey.name);
5199 if (hKeyNames) {
5200 if (verbose)
5201 printf("Using \"/Equipment/%s/Settings/Names %s\" for variable \"%s\"\n", eq_name, varkey.name, varkey.name);
5202
5203 /* define tags from names list */
5206 }
5207 }
5208
5209 if (!hKeyNames) {
5210 db_find_key(hDB, hKeyEq, "Settings/Names", &hKeyNames);
5211 single_names = (hKeyNames > 0);
5212
5213 if (hKeyNames) {
5214 if (verbose)
5215 printf("Using \"/Equipment/%s/Settings/Names\" for variable \"%s\"\n", eq_name, varkey.name);
5216
5217 /* define tags from names list */
5220 }
5221 }
5222
5223 if (hKeyNames && n_names < varkey.num_values) {
5224 cm_msg(MERROR, "open_history",
5225 "Array size mismatch: \"/Equipment/%s/Settings/%s\" has %d entries while \"/Equipment/%s/Variables/%s\" has %d entries",
5227 eq_name, varkey.name, varkey.num_values);
5228 free(tag);
5229 return 0;
5230 }
5231
5232 if (hKeyNames) {
5233 /* loop over array elements */
5234 for (j = 0; j < varkey.num_values; j++) {
5235 char xname[256];
5236
5237 tag[i_tag].name[0] = 0;
5238
5239 /* get name #j */
5240 size = sizeof(xname);
5242 if (status == DB_SUCCESS)
5243 mstrlcpy(tag[i_tag].name, xname, sizeof(tag[i_tag].name));
5244
5245 if (strlen(tag[i_tag].name) < 1) {
5246 char buf[256];
5247 sprintf(buf, "%d", j);
5249 mstrlcat(tag[i_tag].name, "_", NAME_LENGTH);
5250 mstrlcat(tag[i_tag].name, buf, NAME_LENGTH);
5251 }
5252
5253 /* append variable key name for single name array */
5254 if (single_names) {
5255 if (strlen(tag[i_tag].name) + 1 + strlen(varkey.name) >= NAME_LENGTH) {
5256 cm_msg(MERROR, "open_history",
5257 "Name for history entry \"%s %s\" too long", tag[i_tag].name, varkey.name);
5258 free(tag);
5259 return 0;
5260 }
5261 mstrlcat(tag[i_tag].name, " ", NAME_LENGTH);
5263 }
5264
5265 tag[i_tag].type = varkey.type;
5266 tag[i_tag].n_data = 1;
5267
5268 if (verbose)
5269 printf("Defined tag %d, name \"%s\", type %d, num_values %d\n",
5270 i_tag, tag[i_tag].name, tag[i_tag].type, tag[i_tag].n_data);
5271
5272 i_tag++;
5273 }
5274 } else if (varkey.type == TID_KEY) {
5275 int ii;
5276 for (ii=0;; ii++) {
5277 KEY vvarkey;
5278 HNDLE hhKey;
5279
5282 break;
5283
5284 /* get variable key */
5286
5288 mstrlcat(tag[i_tag].name, "_", NAME_LENGTH);
5290 tag[i_tag].type = vvarkey.type;
5291 tag[i_tag].n_data = vvarkey.num_values;
5292
5293 if (verbose)
5294 printf("Defined tag %d, name \"%s\", type %d, num_values %d\n", i_tag, tag[i_tag].name,
5295 tag[i_tag].type, tag[i_tag].n_data);
5296
5297 i_tag++;
5298 }
5299 } else {
5301 tag[i_tag].type = varkey.type;
5302 tag[i_tag].n_data = varkey.num_values;
5303
5304 if (verbose)
5305 printf("Defined tag %d, name \"%s\", type %d, num_values %d\n", i_tag, tag[i_tag].name,
5306 tag[i_tag].type, tag[i_tag].n_data);
5307
5308 i_tag++;
5309 }
5310
5311 if (per_variable_history && i_tag>0) {
5312 WORD event_id = 0;
5313 char event_name[NAME_LENGTH];
5314
5315 mstrlcpy(event_name, eq_name, NAME_LENGTH);
5316 mstrlcat(event_name, "/", NAME_LENGTH);
5317 mstrlcat(event_name, varkey.name, NAME_LENGTH);
5318
5319 assert(i_tag <= n_tags);
5320
5321 status = add_event(&index, now, event_id, event_name, hKey, i_tag, tag, min_period, 1);
5322 if (status != DB_SUCCESS)
5323 return status;
5324
5325 i_tag = 0;
5326 } /* if per-variable history */
5327
5328 } /* loop over variables */
5329
5330 if (!per_variable_history && i_tag>0) {
5331 assert(i_tag <= n_tags);
5332
5333 status = add_event(&index, now, eq_id, eq_name, hKeyVar, i_tag, tag, min_period, 1);
5334 if (status != DB_SUCCESS)
5335 return status;
5336
5337 }
5338
5339 if (tag) {
5340 free(tag);
5341 tag = NULL;
5342 }
5343
5344 /* remember maximum event id for later use with system events */
5345 if (eq_id > max_event_id)
5347 }
5348 } /* loop over equipments */
5349
5350 /*---- define linked trees --------------------------------------*/
5351
5352 /* round up event id */
5353 max_event_id = ((int) ((max_event_id + 1) / 10) + 1) * 10;
5354
5355 status = db_find_key(hDB, 0, "/History/Links", &hKeyRoot);
5356 if (status == DB_SUCCESS) {
5357 for (li = 0;; li++) {
5360 break;
5361
5363 strcpy(hist_name, histkey.name);
5365
5367 if (key.type != TID_KEY) {
5368 cm_msg(MERROR, "open_history", "Only subkeys allows in /history/Links");
5369 continue;
5370 }
5371
5372 if (verbose)
5373 printf("\n==================== History link \"%s\", ID %d =======================\n",
5375
5376 /* count subkeys in link */
5377 for (i = n_var = 0;; i++) {
5380 break;
5381
5382 if (status == DB_SUCCESS && db_get_key(hDB, hKey, &key) == DB_SUCCESS) {
5383 if (key.type != TID_KEY)
5384 n_var++;
5385 } else {
5387 db_get_key(hDB, hKey, &key);
5388 cm_msg(MERROR, "open_history",
5389 "History link /History/Links/%s/%s is invalid", hist_name, key.name);
5390 return 0;
5391 }
5392 }
5393
5394 if (n_var == 0)
5395 cm_msg(MERROR, "open_history", "History event %s has no variables in ODB", hist_name);
5396 else {
5397 /* create tag array */
5398 tag = (TAG *) calloc(sizeof(TAG), n_var);
5399
5400 for (i = 0, size = 0, n_var = 0;; i++) {
5403 break;
5404
5405 /* get link key */
5407
5408 if (linkkey.type == TID_KEY)
5409 continue;
5410
5411 /* get link target */
5413 if (db_get_key(hDB, hVarKey, &varkey) == DB_SUCCESS) {
5414 /* hot-link individual values */
5415 if (histkey.type == TID_KEY) {
5416 db_close_record(hDB, hVarKey); // close previously opened record
5418 (void *) (POINTER_T) index);
5419 }
5420
5421 strcpy(tag[n_var].name, linkkey.name);
5422 tag[n_var].type = varkey.type;
5423 tag[n_var].n_data = varkey.num_values;
5424
5425 if (verbose)
5426 printf("Defined tag \"%s\", type %d, num_values %d\n",
5427 tag[n_var].name, tag[n_var].type, tag[n_var].n_data);
5428
5429 size += varkey.total_size;
5430 n_var++;
5431 }
5432 }
5433
5434 /* hot-link whole subtree */
5435 if (histkey.type == TID_LINK) {
5436 db_close_record(hDB, hHistKey); // close previously opened record
5438 }
5439
5440 status = add_event(&index, now, max_event_id, hist_name, hHistKey, n_var, tag, 0, 0);
5441 if (status != DB_SUCCESS)
5442 return status;
5443
5444 free(tag);
5445 tag = NULL;
5446
5447 max_event_id++;
5448 }
5449 }
5450 }
5451
5452 /*---- define run start/stop event ------------------------------*/
5453
5454 tag = (TAG *) calloc(sizeof(TAG), 2);
5455
5456 strcpy(tag[0].name, "State");
5457 tag[0].type = TID_UINT32;
5458 tag[0].n_data = 1;
5459
5460 strcpy(tag[1].name, "Run number");
5461 tag[1].type = TID_UINT32;
5462 tag[1].n_data = 1;
5463
5464 const char* event_name = "Run transitions";
5465
5466 for (unsigned i=0; i<mh.size(); i++) {
5467 status = mh[i]->hs_define_event(event_name, now, 2, tag);
5468 if (status != HS_SUCCESS) {
5469 cm_msg(MERROR, "add_event", "Cannot define event \"%s\", hs_define_event() status %d", event_name, status);
5470 return 0;
5471 }
5472 }
5473
5474 history_events.push_back(event_name);
5475
5476 free(tag);
5477 tag = NULL;
5478
5479 /* outcommented not to produce a log entry on every run
5480 cm_msg(MINFO, "open_history", "Configured history with %d events", count_events);
5481 */
5482
5484 if (status != HS_SUCCESS)
5485 return status;
5486
5487 double tend = ss_time_sec();
5488 double telapsed = tend - tstart;
5489 if (telapsed > 10.0) {
5490 cm_msg(MERROR, "open_history", "open_history() took %.3f seconds", telapsed);
5491 }
5492
5493 return CM_SUCCESS;
5494}
5495
5496/*---- periodically flush history buffers---------------------------*/
5497
5499
5501{
5502 time_t flush_period_sec = 1; // flush once every 1 seconds
5503
5505
5506 if (verbose)
5507 printf("flush history buffers!\n");
5508
5509 for (unsigned h = 0; h < mh.size(); h++)
5510 mh[h]->hs_flush_buffers();
5511
5513 }
5514}
5515
5516/*---- close_history -----------------------------------------------*/
5517
5519{
5520 INT status;
5522
5523 /* close system history */
5524 status = db_find_key(hDB, 0, "/History/Links", &hKeyRoot);
5525 if (status == DB_SUCCESS) {
5526 for (int i = 0;; i++) {
5527 HNDLE hKey;
5530 break;
5532 }
5533 }
5534
5535 /* close event history */
5536 for (int i = 0; i < hist_log_max; i++)
5537 if (hist_log[i].hKeyVar) {
5538 db_close_record(hDB, hist_log[i].hKeyVar);
5539 hist_log[i].hKeyVar = 0;
5540 if (hist_log[i].buffer)
5541 free(hist_log[i].buffer);
5542 hist_log[i].buffer = NULL;
5543 }
5544
5545 for (unsigned h=0; h<mh.size(); h++) {
5546 mh[h]->hs_disconnect();
5547 delete mh[h];
5548 mh[h] = NULL;
5549 }
5550
5551 mh.clear();
5552}
5553
5554/*---- log_history -------------------------------------------------*/
5555
5557{
5558 INT i, size, status;
5560
5561 time_t now = time(NULL);
5562
5563 for (i = 0; i < hist_log_max; i++)
5564 if (hist_log[i].hKeyVar == hKey)
5565 break;
5566
5567 if (i == hist_log_max)
5568 return;
5569
5570 /* check if over minimum period */
5571 if (now - hist_log[i].last_log < hist_log[i].min_period)
5572 return;
5573
5574 /* check if event size has changed */
5575 db_get_record_size(hDB, hKey, 0, &size);
5576 if (size != hist_log[i].buffer_size) {
5577 close_history();
5578 status = open_history();
5579 if (status != CM_SUCCESS) {
5580 printf("Error in history system, aborting.\n");
5582 exit(1);
5583 }
5584 return;
5585 }
5586
5588
5589 if (verbose)
5590 printf("Log history event: \'%s\', timestamp %s, buffer %p, size %d\n", hist_log[i].event_name, TimeToString(hist_log[i].last_log).c_str(), hist_log[i].buffer, hist_log[i].buffer_size);
5591
5592 for (unsigned h=0; h<mh.size(); h++) {
5593 status = mh[h]->hs_write_event(hist_log[i].event_name, hist_log[i].last_log, hist_log[i].buffer_size, hist_log[i].buffer);
5594 if (verbose)
5595 if (status != HS_SUCCESS)
5596 printf("write_history_event: \'%s\', channel \'%s\' hs_write_event() status %d\n", hist_log[i].event_name, mh[h]->name, status);
5597 }
5598
5600
5602 if (end_millitime - start_millitime > 3000)
5603 cm_msg(MINFO, "log_history", "History write operation took %d ms", end_millitime - start_millitime);
5604}
5605
5606/*------------------------------------------------------------------*/
5607
5609{
5610 INT size, total_size, status, index;
5611 DWORD i;
5612 KEY key;
5614
5615 index = (INT) (POINTER_T) info;
5616
5617 time_t now = time(NULL);
5618
5619 /* check if over period */
5620 if (now - hist_log[index].last_log < hist_log[index].min_period)
5621 return;
5622
5623 for (i = 0, total_size = 0;; i++) {
5624 status = db_enum_key(hDB, hist_log[index].hKeyVar, i, &hKey);
5626 break;
5627
5628 db_get_key(hDB, hKey, &key);
5629 size = key.total_size;
5630 db_get_data(hDB, hKey, (char *) hist_log[index].buffer + total_size, &size, key.type);
5631 total_size += size;
5632 }
5633
5634 if (i != hist_log[index].n_var) {
5635 close_history();
5636 status = open_history();
5637 if (status != CM_SUCCESS) {
5638 printf("Error in history system, aborting.\n");
5640 exit(1);
5641 }
5642 return;
5643 }
5644
5646
5647 if (verbose)
5648 printf("write history event: \'%s\', timestamp %s, buffer %p, size %d\n", hist_log[index].event_name, TimeToString(hist_log[index].last_log).c_str(), hist_log[index].buffer, hist_log[index].buffer_size);
5649
5650 for (unsigned h=0; h<mh.size(); h++)
5651 mh[h]->hs_write_event(hist_log[index].event_name, hist_log[index].last_log, total_size, hist_log[index].buffer);
5652
5654
5656 if (end_millitime - start_millitime > 3000)
5657 cm_msg(MINFO, "log_system_history", "History write operation took %d ms", end_millitime - start_millitime);
5658}
5659
5660/*------------------------------------------------------------------*/
5661
5663{
5664 INT size, status, run_number = 0;
5665 std::string path;
5666 std::string data_dir;
5668
5669 chn_settings = &log_chn->settings;
5670 size = sizeof(run_number);
5671 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
5672 assert(status == SUCCESS);
5673
5674 std::string filename = chn_settings->filename;
5675 /* Check if data stream are throw pipe command */
5676 log_chn->pipe_command = "";
5677 bool ispipe = false;
5678 if (log_chn->type == LOG_TYPE_DISK) {
5679 char* p = strchr(chn_settings->filename, '>');
5680 if (chn_settings->filename[0] == '|' && p) {
5681 /* skip second arrow in ">>" */
5682 while (*p == '>')
5683 p++;
5684 /* skip spaces after '>' */
5685 while (*p == ' ')
5686 p++;
5687 filename = p;
5688 ispipe = true;
5689 // pipe_command is contents of chn_settings->filename without the leading "|" and trailing ">"
5690 log_chn->pipe_command = "";
5691 const char*s = chn_settings->filename;
5692 /* skip leading pipe */
5693 if (*s == '|')
5694 s++;
5695 /* skip spaces */
5696 while (*s == ' ')
5697 s++;
5698 /* copy up to ">" */
5699 while (*s != '>') {
5700 log_chn->pipe_command += *s++;
5701 }
5702 /* copy as many ">" as they put there */
5703 while (*s == '>') {
5704 log_chn->pipe_command += *s++;
5705 }
5706 }
5707 }
5708
5709 std::string str;
5710
5711 /* if disk, precede filename with directory if not already there */
5712 if (log_chn->type == LOG_TYPE_DISK && filename[0] != DIR_SEPARATOR) {
5713 db_get_value_string(hDB, 0, "/Logger/Data Dir", 0, &data_dir, TRUE);
5714 if (data_dir.empty()) {
5716 } else {
5717 if (data_dir.back() != DIR_SEPARATOR)
5719 }
5720 str = data_dir;
5721
5722 /* append subdirectory if requested */
5723 if (chn_settings->subdir_format[0]) {
5724 ss_tzset(); // required for localtime_r()
5725 time_t now;
5726 time(&now);
5727 struct tm tms;
5728 localtime_r(&now, &tms);
5729
5730 char dir[256];
5731 strftime(dir, sizeof(dir), chn_settings->subdir_format, &tms);
5732 str += dir;
5734 }
5735
5736 /* create directory if needed */
5737#ifdef OS_WINNT
5738 status = mkdir(str.c_str());
5739#else
5740 status = mkdir(str.c_str(), 0755);
5741#endif
5742#if defined(EEXIST)
5743 if (status == -1 && errno != EEXIST)
5744 cm_msg(MERROR, "log_generate_file_name", "Cannot create subdirectory \"%s\", mkdir() errno %d (%s)", str.c_str(), errno, strerror(errno));
5745#endif
5746
5747 str += filename;
5748 } else {
5749 str = filename;
5750 }
5751
5752 /* check if two "%" are present in filename */
5753 if (strchr(str.c_str(), '%')) {
5754 if (strchr(strchr(str.c_str(), '%')+1, '%')) {
5755 /* substitude first "%d" by current run number, second "%d" by subrun number */
5756 path = msprintf(str.c_str(), run_number, log_chn->subrun_number);
5757 } else {
5758 /* substitue "%d" by current run number */
5759 path = msprintf(str.c_str(), run_number);
5760 }
5761 } else {
5762 path = str;
5763 }
5764
5765 /* add required file extension */
5766 if (log_chn->writer) {
5767 path += log_chn->writer->wr_get_file_ext();
5768 }
5769
5770 log_chn->path = path;
5771
5772 /* write back current file name to ODB */
5773 std::string tmpstr;
5774 if (strncmp(path.c_str(), data_dir.c_str(), data_dir.length()) == 0)
5775 tmpstr = path.c_str() + data_dir.length();
5776 else
5777 tmpstr = path;
5778 char cstr[256];
5779 mstrlcpy(cstr, tmpstr.c_str(), sizeof(cstr));
5780 db_set_value(hDB, log_chn->settings_hkey, "Current filename", cstr, 256, 1, TID_STRING);
5781
5782 /* construct full pipe command */
5783 if (ispipe) {
5784 /* check if %d must be substitude by current run number in pipe command options */
5785 if (strchr(log_chn->pipe_command.c_str(), '%')) {
5786 std::string str = log_chn->pipe_command;
5787 if (strchr(strchr(str.c_str(), '%')+1, '%')) {
5788 /* substitude first "%d" by current run number, second "%d" by subrun number */
5789 log_chn->pipe_command = msprintf(str.c_str(), run_number, log_chn->subrun_number);
5790 } else {
5791 /* substitue "%d" by current run number */
5792 log_chn->pipe_command = msprintf(str.c_str(), run_number);
5793 }
5794 } else {
5795 }
5796 /* add a space */
5797 if (log_chn->pipe_command.back() != ' ')
5798 log_chn->pipe_command += " ";
5799 /* add generated filename to pipe command */
5800 log_chn->pipe_command += path;
5801 //printf("pipe command [%s]\n", log_chn->pipe_command.c_str());
5802 }
5803
5804 return CM_SUCCESS;
5805}
5806
5807/*------------------------------------------------------------------*/
5808
5809/********************************************************************\
5810
5811 transition callbacks
5812
5813\********************************************************************/
5814
5815/*------------------------------------------------------------------*/
5816
5818{
5820
5821 for (unsigned i = 0; i < log_channels.size(); i++) {
5823 if (chn->handle || chn->ftp_con|| chn->pfile) {
5824 /* generate MTALK message */
5825#ifndef FAL_MAIN
5826 /* wait until buffer is empty */
5827 if (chn->buffer_handle) {
5828#ifdef DELAYED_STOP
5829 DWORD start_time = ss_millitime();
5830 do {
5831 cm_yield(100);
5832 } while (ss_millitime() - start_time < DELAYED_STOP);
5833#else
5834 INT n_bytes;
5835 do {
5836 bm_get_buffer_level(chn->buffer_handle, &n_bytes);
5837 if (n_bytes > 0)
5838 cm_yield(100);
5839 } while (n_bytes > 0);
5840#endif
5841 }
5842#endif /* FAL_MAIN */
5843
5844 /* close logging channel */
5846
5847 /* close statistics record */
5848 db_set_record(hDB, chn->stats_hkey, &chn->statistics, sizeof(CHN_STATISTICS), 0);
5849 db_close_record(hDB, chn->stats_hkey);
5850 db_unwatch(hDB, chn->settings_hkey);
5851 chn->stats_hkey = 0;
5852 chn->settings_hkey = 0;
5853 }
5854 }
5855
5856 if (p_tape_flag)
5858
5859 return SUCCESS;
5860}
5861
5863{
5864 /* close buffers */
5865 for (unsigned i = 0; i < log_channels.size(); i++) {
5867#ifndef FAL_MAIN
5868 if (chn->buffer_handle) {
5869 bm_close_buffer(chn->buffer_handle);
5870 for (unsigned j = i + 1; j < log_channels.size(); j++)
5871 if (log_channels[j]->buffer_handle == chn->buffer_handle)
5872 log_channels[j]->buffer_handle = 0;
5873 }
5874
5875 if (chn->msg_request_id)
5876 bm_delete_request(chn->msg_request_id);
5877#endif
5878
5879 delete chn;
5880 log_channels[i] = NULL;
5881 }
5882
5883 log_channels.clear();
5884
5885 return SUCCESS;
5886}
5887
5888/*------------------------------------------------------------------*/
5889
5891{
5892 DWORD eb[2];
5893 eb[0] = transition;
5894 eb[1] = run_number;
5895
5896 time_t now = time(NULL);
5897
5898 for (unsigned h=0; h<mh.size(); h++)
5899 mh[h]->hs_write_event("Run transitions", now, sizeof(eb), (const char*)eb);
5900
5901 return SUCCESS;
5902}
5903
5904/*------------------------------------------------------------------*/
5905
5907{
5908 int status;
5909 assert(info != NULL);
5911 int size = sizeof(CHN_SETTINGS);
5912 status = db_get_record1(hDB, log_chn->settings_hkey, &log_chn->settings, &size, 0, strcomb1(chn_settings_str).c_str());
5913 if (status != DB_SUCCESS) {
5914 cm_msg(MINFO, "watch_settings", "db_get_record(%s) status %d", log_chn->name.c_str(), status);
5915 return;
5916 }
5917
5918 if (verbose)
5919 printf("Channel %s settings updated\n", log_chn->name.c_str());
5920}
5921
5922/*------------------------------------------------------------------*/
5923
5925/********************************************************************\
5926
5927 Prestart:
5928
5929 Loop through channels defined in /logger/channels.
5930 Neglect channels with are not active.
5931 If "filename" contains a "%", substitute it by the
5932 current run number. Open logging channel and
5933 corresponding buffer. Place a event request
5934 into the buffer.
5935
5936\********************************************************************/
5937{
5938 INT size, status;
5941 KEY key;
5943 HNDLE hDB;
5944
5945 if (verbose)
5946 printf("tr_start: run %d\n", run_number);
5947
5948 DWORD t0 = ss_millitime();
5949
5951
5952 /* save current ODB */
5953 std::string str = "last.json";
5954 db_get_value_string(hDB, 0, "/Logger/ODB Last Dump File", 0, &str, TRUE);
5955 odb_save(str.c_str(), false);
5956
5957 DWORD t1 = ss_millitime();
5958
5960
5962 close_buffers();
5963
5964 DWORD t2 = ss_millitime();
5965
5967
5969
5970 /* read global logging flag */
5971 size = sizeof(BOOL);
5972 write_data = TRUE;
5973 db_get_value(hDB, 0, "/Logger/Write data", &write_data, &size, TID_BOOL, TRUE);
5974
5975 /* read tape message flag */
5976 size = sizeof(tape_message);
5977 db_get_value(hDB, 0, "/Logger/Tape message", &tape_message, &size, TID_BOOL, TRUE);
5978
5979 /* reset next subrun flag */
5980 status = FALSE;
5981 db_set_value(hDB, 0, "/Logger/Next subrun", &status, sizeof(status), 1, TID_BOOL);
5982
5983 /* loop over all channels */
5984 status = db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot);
5985 if (status != DB_SUCCESS) {
5986 /* if no channels are defined, define at least one */
5987 status = db_create_record(hDB, 0, "/Logger/Channels/0/", strcomb1(chn_tree_str).c_str());
5988 if (status != DB_SUCCESS) {
5989 strcpy(error, "Cannot create channel entry in database");
5990 cm_msg(MERROR, "tr_start", "%s", error);
5991 return 0;
5992 }
5993
5994 status = db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot);
5995 if (status != DB_SUCCESS) {
5996 strcpy(error, "Cannot create channel entry in database");
5997 cm_msg(MERROR, "tr_start", "%s", error);
5998 return 0;
5999 }
6000 }
6001
6002 // after close_buffers() all log channels are closed and deleted
6003 assert(log_channels.size() == 0);
6004
6005 for (unsigned index = 0; ; index++) {
6008 break;
6009
6010 /* correct channel record */
6013 if (status != DB_SUCCESS && status != DB_OPEN_RECORD) {
6014 cm_msg(MERROR, "tr_start", "Cannot create/check channel record, status %d", status);
6015 break;
6016 }
6017
6018 if (status == DB_SUCCESS || status == DB_OPEN_RECORD) {
6020
6021 log_channels.push_back(chn);
6022
6023 /* save settings key */
6024 status = db_find_key(hDB, hKeyChannel, "Settings", &chn->settings_hkey);
6025 if (status != DB_SUCCESS) {
6026 strcpy(error, "Cannot find channel settings info");
6027 cm_msg(MERROR, "tr_start", "%s", error);
6028 return 0;
6029 }
6030
6031 /* save statistics key */
6032 status = db_find_key(hDB, hKeyChannel, "Statistics", &chn->stats_hkey);
6033 if (status != DB_SUCCESS) {
6034 strcpy(error, "Cannot find channel statistics info");
6035 cm_msg(MERROR, "tr_start", "%s", error);
6036 return 0;
6037 }
6038
6039 /* clear statistics */
6040 size = sizeof(CHN_STATISTICS);
6041 db_get_record1(hDB, chn->stats_hkey, &chn->statistics, &size, 0, strcomb1(chn_statistics_str).c_str());
6042
6043 chn->statistics.events_written = 0;
6044 chn->statistics.bytes_written = 0;
6045 chn->statistics.bytes_written_uncompressed = 0;
6046 chn->statistics.bytes_written_subrun = 0;
6047
6048 db_set_record(hDB, chn->stats_hkey, &chn->statistics, size, 0);
6049
6050 /* get channel info structure */
6051 chn_settings = &chn->settings;
6052 size = sizeof(CHN_SETTINGS);
6053 status = db_get_record1(hDB, chn->settings_hkey, chn_settings, &size, 0, strcomb1(chn_settings_str).c_str());
6054 if (status != DB_SUCCESS) {
6055 strcpy(error, "Cannot read channel info");
6056 cm_msg(MERROR, "tr_start", "%s", error);
6057 return 0;
6058 }
6059
6060 chn->pre_checksum_module = select_checksum_module(hDB, chn->settings_hkey, "data checksum");
6061 chn->post_checksum_module = select_checksum_module(hDB, chn->settings_hkey, "file checksum");
6062 chn->compression_module = select_compression_module(hDB, chn->settings_hkey, "compress");
6063 chn->output_module = select_output_module(hDB, chn->settings_hkey, "output");
6064
6065 //printf("channel settings pre [%d] compress [%d] post [%d] output [%d]\n", chn->pre_checksum_module, chn->compression_module, chn->post_checksum_module, chn->output_module);
6066
6067 /* check if active */
6068 if (!chn_settings->active || !write_data)
6069 continue;
6070
6071#ifdef OBSOLETE
6072 /* check for type */
6073 if (equal_ustring(chn_settings->type, "FTP"))
6074 chn->type = LOG_TYPE_FTP;
6075 else if (equal_ustring(chn_settings->type, "Disk"))
6076 chn->type = LOG_TYPE_DISK;
6077 else {
6078 sprintf(error, "Invalid channel type \"%s\", pease use \"Tape\", \"FTP\" or \"Disk\"", chn_settings->type);
6079 cm_msg(MERROR, "tr_start", "%s", error);
6080 return 0;
6081 }
6082#endif
6083
6084#ifdef OBSOLETE
6085 /* set compression level */
6086 chn->compression = 0;
6087 size = sizeof(chn->compression);
6088 status = db_get_value(hDB, chn->settings_hkey, "Compression", &chn->compression, &size, TID_INT32, FALSE);
6089#endif
6090
6091 /* initialize subrun number */
6092 chn->subrun_number = 0;
6093
6096
6097 /* open logging channel */
6099
6100 /* return if logging channel couldn't be opened */
6101 if (status != SS_SUCCESS) {
6102 if (status == SS_FILE_ERROR)
6103 sprintf(error, "Cannot open file \'%s\' (See messages)", chn->path.c_str());
6104 if (status == SS_FILE_EXISTS)
6105 sprintf(error, "File \'%s\' exists already, run start aborted", chn->path.c_str());
6106 if (status == SS_NO_TAPE)
6107 sprintf(error, "No tape in device \'%s\'", chn->path.c_str());
6108 if (status == SS_TAPE_ERROR)
6109 sprintf(error, "Tape error, cannot start run");
6110 if (status == SS_DEV_BUSY)
6111 sprintf(error, "Device \'%s\' used by someone else", chn->path.c_str());
6113 sprintf(error, "Cannot open FTP channel to \'%s\'", chn->path.c_str());
6114 if (status == SS_NO_ROOT)
6115 sprintf(error, "No ROOT support compiled into mlogger, please compile with -DHAVE_ROOT flag");
6116
6118 sprintf(error, "Invalid data format, please use \"MIDAS\", \"ASCII\", \"DUMP\" or \"ROOT\"");
6119
6120 cm_msg(MERROR, "tr_start", "%s", error);
6121 return 0;
6122 }
6123
6124 /* close records if open from previous run start with abort */
6125 if (chn->stats_hkey)
6126 db_close_record(hDB, chn->stats_hkey);
6127 if (chn->settings_hkey)
6128 db_close_record(hDB, chn->settings_hkey);
6129
6130 /* open hot link to statistics tree */
6131 status = db_open_record1(hDB, chn->stats_hkey, &chn->statistics, sizeof(CHN_STATISTICS), MODE_WRITE, NULL, NULL, strcomb1(chn_statistics_str).c_str());
6132 if (status == DB_NO_ACCESS) {
6133 /* record is probably still in exclusive access by dead logger, so reset it */
6135 if (status != DB_SUCCESS)
6136 cm_msg(MERROR, "tr_start", "Cannot change access mode for statistics record, error %d", status);
6137 else
6138 cm_msg(MINFO, "tr_start", "Recovered access mode for statistics record of channel \"%s\"", chn->name.c_str());
6139 status = db_open_record1(hDB, chn->stats_hkey, &chn->statistics, sizeof(CHN_STATISTICS), MODE_WRITE, NULL, NULL, strcomb1(chn_statistics_str).c_str());
6140 }
6141
6142 if (status != DB_SUCCESS)
6143 cm_msg(MERROR, "tr_start", "Cannot open statistics record for channel \"%s\", error %d", chn->name.c_str(), status);
6144
6145 /* open hot link to settings tree */
6146 status = db_watch(hDB, chn->settings_hkey, watch_settings, chn);
6147 if (status != DB_SUCCESS)
6148 cm_msg(MERROR, "tr_start", "db_watch() status %d, cannot open channel settings record, probably other logger is using it", status);
6149
6150#ifndef FAL_MAIN
6151 /* open buffer */
6152 status = bm_open_buffer(chn_settings->buffer, DEFAULT_BUFFER_SIZE, &chn->buffer_handle);
6153 if (status != BM_SUCCESS && status != BM_CREATED) {
6154 sprintf(error, "Cannot open buffer %s", chn_settings->buffer);
6155 cm_msg(MERROR, "tr_start", "%s", error);
6156 return 0;
6157 }
6158 bm_set_cache_size(chn->buffer_handle, 100000, 0);
6159
6160 /* place event request */
6161 status = bm_request_event(chn->buffer_handle, (short) chn_settings->event_id, (short) chn_settings->trigger_mask, GET_ALL, &chn->request_id, receive_event);
6162
6163 if (status != BM_SUCCESS) {
6164 sprintf(error, "Cannot place event request");
6165 cm_msg(MERROR, "tr_start", "%s", error);
6166 return 0;
6167 }
6168
6169 /* open message buffer if requested */
6170 if (chn_settings->log_messages) {
6171 status = bm_open_buffer((char*)MESSAGE_BUFFER_NAME, MESSAGE_BUFFER_SIZE, &chn->msg_buffer_handle);
6172 if (status != BM_SUCCESS && status != BM_CREATED) {
6173 sprintf(error, "Cannot open buffer %s", MESSAGE_BUFFER_NAME);
6174 cm_msg(MERROR, "tr_start", "%s", error);
6175 return 0;
6176 }
6177
6178 /* place event request */
6179 status = bm_request_event(chn->msg_buffer_handle, (short) EVENTID_MESSAGE, (short) chn_settings->log_messages, GET_ALL, &chn->msg_request_id, receive_event);
6180
6181 if (status != BM_SUCCESS) {
6182 sprintf(error, "Cannot place event request");
6183 cm_msg(MERROR, "tr_start", "%s", error);
6184 return 0;
6185 }
6186 }
6187#endif
6188 }
6189 }
6190
6191 DWORD t3 = ss_millitime();
6192
6193 if (tape_flag && tape_message)
6194 cm_msg(MTALK, "tr_start", "tape mounting finished");
6195
6196 /* reopen history channels if event definition has changed */
6197 close_history();
6198 status = open_history();
6199 if (status != CM_SUCCESS) {
6200 sprintf(error, "Error in history system, aborting run start");
6201 cm_msg(MERROR, "tr_start", "%s", error);
6202 return 0;
6203 }
6204
6205 /* write transition event into history */
6207
6208 DWORD t4 = ss_millitime();
6209
6210#ifdef HAVE_MYSQL
6211 /* write to SQL database if requested */
6213#endif
6214
6215 /* write to runlog file(s) if requested */
6218
6219 DWORD t5 = ss_millitime();
6220 DWORD te = t5;
6221
6222 if (verbose)
6223 printf("tr_start: run %d started in %d ms: odb dump %d ms, close channels %d ms, configure channels %d ms, configure history %d ms, write runlog %d ms\n",
6224 run_number,
6225 te-t0,
6226 t1-t0,
6227 t2-t1,
6228 t3-t2,
6229 t4-t3,
6230 t5-t4
6231 );
6232
6235
6237
6238 return CM_SUCCESS;
6239}
6240
6241/*-- -------- ------------------------------------------------------*/
6242
6244{
6245 if (verbose)
6246 printf("tr_start_abort: run %d\n", run_number);
6247
6249
6250 for (unsigned i = 0; i < log_channels.size(); i++) {
6252 if (chn->handle && chn->type == LOG_TYPE_DISK) {
6253 cm_msg(MINFO, "tr_start_abort", "Deleting previous file \"%s\"", chn->path.c_str());
6254 unlink(chn->path.c_str());
6255 }
6256 }
6257
6259 close_buffers();
6260
6262
6264
6266
6267 return CM_SUCCESS;
6268}
6269
6270/*-- poststop ------------------------------------------------------*/
6271
6273/********************************************************************\
6274
6275 Poststop:
6276
6277 Wait until buffers are empty, then close logging channels
6278
6279\********************************************************************/
6280{
6281 INT size;
6283 char filename[256];
6284 char str[256];
6285
6286 if (verbose)
6287 printf("tr_stop: run %d\n", run_number);
6288
6290 return CM_SUCCESS;
6291
6292 DWORD t0 = ss_millitime();
6293
6295
6297 close_buffers();
6298
6299 DWORD t1 = ss_millitime();
6300
6301 /* ODB dump if requested */
6302 size = sizeof(flag);
6303 flag = 0;
6304 db_get_value(hDB, 0, "/Logger/ODB Dump", &flag, &size, TID_BOOL, TRUE);
6305 if (flag) {
6306 strcpy(str, "run%d.json");
6307 size = sizeof(str);
6308 str[0] = 0;
6309 db_get_value(hDB, 0, "/Logger/ODB Dump File", str, &size, TID_STRING, TRUE);
6310 if (str[0] == 0)
6311 strcpy(str, "run%d.json");
6312
6313 /* substitue "%d" by current run number */
6314 if (strchr(str, '%'))
6315 sprintf(filename, str, run_number);
6316 else
6317 strcpy(filename, str);
6318
6319 odb_save(filename, true);
6320 }
6321
6322 DWORD t2 = ss_millitime();
6323
6324#ifdef HAVE_MYSQL
6325 /* write to SQL database if requested */
6327#endif
6328
6329 /* write to ASCII file(s) if requested */
6332
6333 DWORD t3 = ss_millitime();
6334
6336
6337 if (tape_flag & tape_message)
6338 cm_msg(MTALK, "tr_stop", "all tape channels closed");
6339
6340 /* write transition event into history */
6342
6343 DWORD t4 = ss_millitime();
6344
6345 /* clear flag */
6347 stop_try_later = 0;
6348
6349 if (start_requested) {
6350 int delay = 0;
6351 size = sizeof(delay);
6352 db_get_value(hDB, 0, "/Logger/Auto restart delay", &delay, &size, TID_INT32, TRUE);
6353 auto_restart = ss_time() + delay; /* start after specified delay */
6355 }
6356
6357 DWORD te = t4;
6358
6359 if (verbose)
6360 printf("tr_stop: run %d stopped in %d ms: close channels %d ms, odb dump %d ms, write run log %d ms, write history %d ms\n",
6361 run_number,
6362 te-t0,
6363 t1-t0,
6364 t2-t1,
6365 t3-t2,
6366 t4-t3);
6367
6368
6370
6372
6373 return CM_SUCCESS;
6374}
6375
6376/*== common code FAL/MLOGGER end ===================================*/
6377
6378/*----- pause/resume -----------------------------------------------*/
6379
6381{
6382 /* write transition event into history */
6384
6386
6388
6389 return CM_SUCCESS;
6390}
6391
6393{
6394 /* write transition event into history */
6396
6398
6400
6401 return CM_SUCCESS;
6402}
6403
6404/*----- receive_event ----------------------------------------------*/
6405
6406void receive_event(HNDLE hBuf, HNDLE request_id, EVENT_HEADER * pheader, void *pevent)
6407{
6408 if (verbose)
6409 printf("write data event: req %d, evid %d, timestamp %d, size %d\n", request_id, pheader->event_id, pheader->time_stamp, pheader->data_size);
6410
6411 /* find logging channel for this request id */
6412 for (unsigned i = 0; i < log_channels.size(); i++) {
6414 if (chn->handle == 0 && chn->ftp_con == NULL)
6415 continue;
6416
6417 /* write normal events */
6418 if (chn->request_id == request_id) {
6419 log_write(chn, pheader);
6420 break;
6421 }
6422
6423 /* write messages */
6424 if (chn->msg_request_id == request_id) {
6425 log_write(chn, pheader);
6426 break;
6427 }
6428 }
6429}
6430
6431/*------------------------ main ------------------------------------*/
6432
6433int main(int argc, char *argv[])
6434{
6435 INT status, msg, i, size, ch = 0;
6438 DWORD last_time_kb = 0;
6441
6442#ifdef HAVE_ROOT
6443 char **rargv;
6444 int rargc;
6445
6446 /* copy first argument */
6447 rargc = 0;
6448 rargv = (char **) malloc(sizeof(char *) * 2);
6449 rargv[rargc] = (char *) malloc(strlen(argv[rargc]) + 1);
6450 strcpy(rargv[rargc], argv[rargc]);
6451 rargc++;
6452
6453 /* append argument "-b" for batch mode without graphics */
6454 rargv[rargc++] = (char *)"-b";
6455
6456 TApplication theApp("mlogger", &rargc, rargv);
6457
6458 /* free argument memory */
6459 free(rargv[0]);
6460 rargv[0] = NULL;
6461 free(rargv);
6462 rargv = NULL;
6463
6464#endif
6465
6466#ifdef SIGPIPE
6467 // undo ROOT overwrites SIGPIPE
6469#endif
6470
6471 setbuf(stdout, NULL);
6472 setbuf(stderr, NULL);
6473
6474 /* get default from environment */
6476
6478
6479 /* parse command line parameters */
6480 for (i = 1; i < argc; i++) {
6481 if (argv[i][0] == '-' && argv[i][1] == 'd')
6482 debug = TRUE;
6483 else if (argv[i][0] == '-' && argv[i][1] == 'D')
6484 daemon = TRUE;
6485 else if (argv[i][0] == '-' && argv[i][1] == 's')
6486 save_mode = TRUE;
6487 else if (argv[i][0] == '-' && argv[i][1] == 'v')
6488 verbose = TRUE;
6489 else if (argv[i][0] == '-') {
6490 if (i + 1 >= argc || argv[i + 1][0] == '-')
6491 goto usage;
6492 if (argv[i][1] == 'e')
6493 strcpy(exp_name, argv[++i]);
6494 else {
6495 usage:
6496 printf("usage: mlogger [-e Experiment] [-d] [-D] [-s] [-v]\n\n");
6497 return 1;
6498 }
6499 }
6500 }
6501
6502 if (daemon) {
6503 printf("Becoming a daemon...\n");
6505 }
6506
6508 if (status != CM_SUCCESS)
6509 return 1;
6510
6511 /* check if logger already running */
6512 status = cm_exist("Logger", FALSE);
6513 if (status == CM_SUCCESS) {
6514 printf("Logger runs already.\n");
6516 return 1;
6517 }
6518
6520
6521 /* turn off watchdog if in debug mode */
6522 if (debug)
6524
6525 /* turn on save mode */
6526 if (save_mode) {
6529 }
6530
6531 /* register transition callbacks */
6533 cm_msg(MERROR, "main", "cannot register callbacks");
6534 return 1;
6535 }
6536
6541
6542 /* initialize ODB */
6543 logger_init();
6544
6545 /* obtain current state */
6547 size = sizeof(local_state);
6548 status = db_get_value(hDB, 0, "/Runinfo/State", &local_state, &size, TID_INT32, true);
6549
6550 /* open history logging */
6551 if (open_history() != CM_SUCCESS) {
6552 printf("Error in history system, aborting startup.\n");
6554 return 1;
6555 }
6556
6557 /* print startup message */
6558 std::string data_dir;
6559 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &data_dir, TRUE);
6560 if (data_dir.length() <= 0)
6562 printf("Data directory is \"%s\" unless specified under /Logger/channels/\n", data_dir.c_str());
6563
6564 /* Alternate message path */
6565 std::string message_dir;
6566 db_get_value_string(hDB, 0, "/Logger/Message dir", 0, &message_dir, TRUE);
6567 if (message_dir.empty()) {
6569 printf("Message directory is \"%s\" unless specified in /Logger/Message dir\n", message_dir.c_str());
6570 } else
6571 printf("Message directory is \"%s\"\n", message_dir.c_str());
6572
6573 /* Alternate History and Elog path */
6574 std::string history_dir;
6575 db_get_value_string(hDB, 0, "/Logger/History dir", 0, &history_dir, TRUE);
6576 if (history_dir.empty()) {
6578 printf("History directory is \"%s\" unless specified under /Logger/history/\n", history_dir.c_str());
6579 } else
6580 printf("History directory is \"%s\"\n", history_dir.c_str());
6581
6582#ifdef HAVE_MYSQL
6583 {
6584 std::string sql_host;
6585 std::string sql_db;
6586 std::string sql_table;
6587
6588 HNDLE hktemp;
6589 status = db_find_key(hDB, 0, "/Logger/Runlog/SQL/Hostname", &hktemp);
6590 if (status == DB_SUCCESS) {
6591 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Hostname", 0, &sql_host, FALSE);
6592 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Database", 0, &sql_db, FALSE);
6593 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Table", 0, &sql_table, FALSE);
6594 printf("SQL database is %s/%s/%s", sql_host.c_str(), sql_db.c_str(), sql_table.c_str());
6595 }
6596 }
6597#endif
6598
6599 printf("\nMIDAS logger started. Stop with \"!\"\n");
6600
6601 /* initialize ss_getchar() */
6602 ss_getchar(0);
6603
6604 /* start image history threads */
6606
6607 do {
6608 msg = cm_yield(100);
6609
6610 /* maybe update channel disk levels */
6612
6613 /* update channel statistics once every second */
6614 if (ss_millitime() - last_time_stat > 1000) {
6616 /*
6617 printf("update statistics!\n");
6618 //LOG_CHN* log_chn = log_chn[0];
6619 printf("events %.0f, subrun %.0f, written %.0f, total %.0f\n", log_chn->statistics.events_written,
6620 log_chn->statistics.bytes_written_subrun,
6621 log_chn->statistics.bytes_written,
6622 log_chn->statistics.bytes_written_total);
6623 */
6625 }
6626
6627 /* check for auto restart */
6628 if (auto_restart && ss_time() > auto_restart) {
6630 }
6631
6632 /* check if time is reached to stop run */
6633 duration = 0;
6634 size = sizeof(duration);
6635 db_get_value(hDB, 0, "/Logger/Run duration", &duration, &size, TID_UINT32, true);
6637 duration > 0 && ss_time() >= run_start_time + duration) {
6638 cm_msg(MTALK, "main", "stopping run after %d seconds", duration);
6639 status = stop_the_run(1);
6640 }
6641
6642 /* stop the run if previous attempt failed */
6643 if (stop_try_later) {
6644 if (ss_time_sec() > stop_try_later) {
6645 cm_msg(MTALK, "main", "another attempt to stop the run");
6646 status = stop_the_run(0);
6647 }
6648 }
6649
6650 /* check keyboard once every 100 ms */
6651 if (ss_millitime() - last_time_kb > 100) {
6653
6654 ch = 0;
6655 while (ss_kbhit()) {
6656 ch = ss_getchar(0);
6657 if (ch == -1)
6658 ch = getchar();
6659
6660 if ((char) ch == '!')
6661 break;
6662 }
6663 }
6664
6665 } while (msg != RPC_SHUTDOWN && msg != SS_ABORT && ch != '!');
6666
6667 /* reset terminal */
6669
6670 /* close history logging */
6671 close_history();
6672
6673 /* stop image history threads */
6675 printf("Stopping image history threads...");
6676 fflush(stdout);
6678 printf("ok\n");
6679 }
6680
6682
6683 return 0;
6684}
6685
6686/* emacs
6687 * Local Variables:
6688 * tab-width: 8
6689 * c-basic-offset: 3
6690 * indent-tabs-mode: nil
6691 * End:
6692 */
#define FALSE
Definition cfortran.h:309
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:1071
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1090
uint32_t fCrc32
Definition mlogger.cxx:1135
std::string wr_get_file_ext()
Definition mlogger.cxx:1124
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1048
std::string wr_get_chain()
Definition mlogger.cxx:1128
WriterCRC32C(LOG_CHN *log_chn, int level, WriterInterface *wr)
Definition mlogger.cxx:1029
WriterInterface * fWr
Definition mlogger.cxx:1134
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:974
std::string wr_get_file_ext()
Definition mlogger.cxx:1008
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:955
WriterCRC32Zlib(LOG_CHN *log_chn, int level, WriterInterface *wr)
Definition mlogger.cxx:913
WriterInterface * fWr
Definition mlogger.cxx:1018
std::string wr_get_chain()
Definition mlogger.cxx:1012
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:932
std::string fFilename
Definition mlogger.cxx:600
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:572
WriterFile(LOG_CHN *log_chn)
Definition mlogger.cxx:504
std::string wr_get_chain()
Definition mlogger.cxx:594
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:547
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:518
FTP_CON * fFtp
Definition mlogger.cxx:3008
std::string wr_get_file_ext()
Definition mlogger.cxx:2997
WriterFtp(LOG_CHN *log_chn)
Definition mlogger.cxx:2914
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:2933
std::string wr_get_chain()
Definition mlogger.cxx:3002
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:2954
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:2981
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:681
std::string wr_get_chain()
Definition mlogger.cxx:751
WriterGzip(LOG_CHN *log_chn, int compress)
Definition mlogger.cxx:611
std::string wr_get_file_ext()
Definition mlogger.cxx:746
int fCompress
Definition mlogger.cxx:759
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:715
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:631
std::string fFilename
Definition mlogger.cxx:757
time_t fLastCheckTime
Definition mlogger.cxx:760
gzFile fGzfp
Definition mlogger.cxx:758
virtual ~WriterInterface()
Definition mlogger.cxx:413
virtual int wr_close(LOG_CHN *log_chn, int run_number)=0
virtual int wr_open(LOG_CHN *log_chn, int run_number)=0
virtual std::string wr_get_chain()=0
virtual std::string wr_get_file_ext()
Definition mlogger.cxx:414
virtual int wr_write(LOG_CHN *log_chn, const void *data, const int size)=0
std::string wr_get_file_ext()
Definition mlogger.cxx:1599
int fBlockSize
Definition mlogger.cxx:1613
MLZ4F_compressionContext_t fContext
Definition mlogger.cxx:1609
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:1505
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1447
MLZ4F_preferences_t fPrefs
Definition mlogger.cxx:1610
WriterInterface * fWr
Definition mlogger.cxx:1608
int fBufferSize
Definition mlogger.cxx:1612
WriterLZ4(LOG_CHN *log_chn, WriterInterface *wr)
Definition mlogger.cxx:1425
char * fBuffer
Definition mlogger.cxx:1611
std::string wr_get_chain()
Definition mlogger.cxx:1603
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1545
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:451
std::string wr_get_file_ext()
Definition mlogger.cxx:485
bool fSimulateCompression
Definition mlogger.cxx:496
WriterNull(LOG_CHN *log_chn)
Definition mlogger.cxx:438
std::string wr_get_chain()
Definition mlogger.cxx:490
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:475
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:463
std::string fCommand
Definition mlogger.cxx:901
std::string wr_get_file_ext()
Definition mlogger.cxx:888
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:787
time_t fLastCheckTime
Definition mlogger.cxx:903
FILE * fFp
Definition mlogger.cxx:899
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:857
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:818
WriterPopen(LOG_CHN *log_chn, const char *pipe_command, const char *file_ext)
Definition mlogger.cxx:768
std::string fFileExt
Definition mlogger.cxx:902
std::string wr_get_chain()
Definition mlogger.cxx:893
std::string fPipeCommand
Definition mlogger.cxx:900
std::string toHex(unsigned char c)
Definition mlogger.cxx:1209
std::string wr_get_chain()
Definition mlogger.cxx:1268
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1224
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1167
WriterSHA256(LOG_CHN *log_chn, int level, WriterInterface *wr)
Definition mlogger.cxx:1145
std::string toString(const unsigned char sha256sum[32])
Definition mlogger.cxx:1216
mbedtls_sha256_context fCtx
Definition mlogger.cxx:1275
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:1190
std::string wr_get_file_ext()
Definition mlogger.cxx:1264
WriterInterface * fWr
Definition mlogger.cxx:1274
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:1330
std::string toString(const unsigned char sha512sum[64])
Definition mlogger.cxx:1356
mbedtls_sha512_context fCtx
Definition mlogger.cxx:1415
std::string toHex(unsigned char c)
Definition mlogger.cxx:1349
std::string wr_get_file_ext()
Definition mlogger.cxx:1404
std::string wr_get_chain()
Definition mlogger.cxx:1408
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1364
WriterSHA512(LOG_CHN *log_chn, int level, WriterInterface *wr)
Definition mlogger.cxx:1285
WriterInterface * fWr
Definition mlogger.cxx:1414
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1307
INT transition(INT run_number, char *error)
Definition consume.cxx:35
uint32_t crc32c(uint32_t crc, const void *buf, size_t len)
Definition crc32c.cxx:391
static void usage()
TRIGGER_SETTINGS ts
int ftp_login(FTP_CON **con, const char *host, unsigned short port, const char *user, const char *password, const char *account)
Definition ftplib.cxx:388
int ftp_close(FTP_CON *con)
Definition ftplib.cxx:334
int ftp_command(FTP_CON *con, const char *command, const char *param,...)
Definition ftplib.cxx:146
#define FTP_RESPONSE_ERROR
Definition ftplib.cxx:22
void ftp_debug(int(*debug_func)(const char *message), int(*error_func)(const char *message))
Definition ftplib.cxx:32
int ftp_send(int sock, const char *buffer, int n_bytes_to_write)
Definition ftplib.cxx:346
#define FTP_NET_ERROR
Definition ftplib.cxx:20
int ftp_bye(FTP_CON *con)
Definition ftplib.cxx:422
#define ftp_chdir(ftp, dir)
Definition ftplib.h:35
#define ftp_binary(ftp)
Definition ftplib.h:39
#define ftp_open_write(ftp, file)
Definition ftplib.h:41
INT bk_iterate32a(const void *event, BANK32A **pbk32a, void *pdata)
Definition midas.cxx:17103
INT bk_swap(void *event, BOOL force)
Definition midas.cxx:17157
BOOL bk_is32a(const void *event)
Definition midas.cxx:16437
BOOL bk_is32(const void *event)
Definition midas.cxx:16415
INT bk_iterate32(const void *event, BANK32 **pbk, void *pdata)
Definition midas.cxx:17067
INT bk_iterate(const void *event, BANK **pbk, void *pdata)
Definition midas.cxx:17046
INT bm_open_buffer(const char *buffer_name, INT buffer_size, INT *buffer_handle)
Definition midas.cxx:6717
INT bm_delete_request(INT request_id)
Definition midas.cxx:8584
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:8465
INT bm_set_cache_size(INT buffer_handle, size_t read_size, size_t write_size)
Definition midas.cxx:8140
INT bm_close_buffer(INT buffer_handle)
Definition midas.cxx:7096
INT bm_compose_event(EVENT_HEADER *event_header, short int event_id, short int trigger_mask, DWORD data_size, DWORD serial)
Definition midas.cxx:8281
INT cm_register_transition(INT transition, INT(*func)(INT, char *), INT sequence_number)
Definition midas.cxx:3593
INT cm_yield(INT millisec)
Definition midas.cxx:5642
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3011
INT cm_connect_experiment(const char *host_name, const char *exp_name, const char *client_name, void(*func)(char *))
Definition midas.cxx:2278
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5286
INT cm_disconnect_experiment(void)
Definition midas.cxx:2846
std::string cm_get_path()
Definition midas.cxx:1537
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2134
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3283
INT cm_exist(const char *name, BOOL bUnique)
Definition midas.cxx:7520
static void xwrite(const char *filename, int fd, const void *data, int size)
Definition elog.cxx:68
#define CM_SUCCESS
Definition midas.h:582
#define CM_TRANSITION_IN_PROGRESS
Definition midas.h:592
#define BM_SUCCESS
Definition midas.h:605
#define BM_CREATED
Definition midas.h:606
#define DB_NO_ACCESS
Definition midas.h:648
#define DB_SUCCESS
Definition midas.h:631
#define DB_NO_KEY
Definition midas.h:642
#define DB_OPEN_RECORD
Definition midas.h:650
#define DB_NO_MORE_SUBKEYS
Definition midas.h:646
#define DB_TRUNCATED
Definition midas.h:644
#define SS_SUCCESS
Definition midas.h:663
#define SS_TAPE_ERROR
Definition midas.h:682
#define SS_ABORT
Definition midas.h:677
#define SS_FILE_EXISTS
Definition midas.h:686
#define SS_FILE_ERROR
Definition midas.h:669
#define SS_NO_MEMORY
Definition midas.h:665
#define SS_NO_TAPE
Definition midas.h:679
#define SS_INVALID_FORMAT
Definition midas.h:688
#define SS_DEV_BUSY
Definition midas.h:680
#define SS_NO_ROOT
Definition midas.h:689
#define RPC_SHUTDOWN
Definition midas.h:707
#define HS_SUCCESS
Definition midas.h:727
static INT hs_write_event(DWORD event_id, const void *data, DWORD size)
Definition history.cxx:656
unsigned short int WORD
Definition mcstd.h:49
unsigned int DWORD
Definition mcstd.h:51
#define SUCCESS
Definition mcstd.h:54
#define TR_RESUME
Definition midas.h:408
#define TR_PAUSE
Definition midas.h:407
#define TID_DOUBLE
Definition midas.h:343
#define TID_KEY
Definition midas.h:349
#define GET_ALL
Definition midas.h:321
#define TID_BOOL
Definition midas.h:340
#define TR_START
Definition midas.h:405
#define TID_UINT64
Definition midas.h:352
#define FORMAT_FIXED
Definition midas.h:314
#define TID_INT64
Definition midas.h:351
#define TR_MTHREAD
Definition midas.h:361
#define TR_STARTABORT
Definition midas.h:409
#define STATE_STOPPED
Definition midas.h:305
#define MINFO
Definition midas.h:560
#define MODE_DELETE
Definition midas.h:372
#define TID_STRUCT
Definition midas.h:348
#define MLOG
Definition midas.h:563
#define FORMAT_ROOT
Definition midas.h:317
#define TID_INT32
Definition midas.h:339
#define TR_DETACH
Definition midas.h:360
#define TID_UINT8
Definition midas.h:328
#define TID_LINK
Definition midas.h:350
#define STATE_PAUSED
Definition midas.h:306
#define TID_STRING
Definition midas.h:346
#define MODE_WRITE
Definition midas.h:371
#define MERROR
Definition midas.h:559
#define STATE_RUNNING
Definition midas.h:307
#define MODE_READ
Definition midas.h:370
#define TID_INT8
Definition midas.h:330
#define FORMAT_MIDAS
Definition midas.h:311
#define TID_CHAR
Definition midas.h:331
#define MTALK
Definition midas.h:564
#define TID_UINT32
Definition midas.h:337
#define TID_UINT16
Definition midas.h:333
#define TR_STOP
Definition midas.h:406
#define TID_INT16
Definition midas.h:335
#define TID_FLOAT
Definition midas.h:341
#define LOG_TYPE_DISK
Definition msystem.h:493
#define O_BINARY
Definition msystem.h:219
#define MESSAGE_BUFFER_NAME
Definition msystem.h:111
#define MAX_STRING_LENGTH
Definition msystem.h:113
#define MESSAGE_BUFFER_SIZE
Definition msystem.h:110
#define LOG_TYPE_FTP
Definition msystem.h:495
BOOL ss_kbhit()
Definition system.cxx:3664
double ss_disk_size(const char *path)
Definition system.cxx:7048
time_t ss_mktime(struct tm *tms)
Definition system.cxx:3365
DWORD ss_millitime()
Definition system.cxx:3393
INT ss_getchar(BOOL reset)
Definition system.cxx:7503
double ss_disk_free(const char *path)
Definition system.cxx:6620
double ss_file_size(const char *path)
Definition system.cxx:6972
void ss_tzset()
Definition system.cxx:3355
INT ss_daemon_init(BOOL keep_stdout)
Definition system.cxx:2001
DWORD ss_time()
Definition system.cxx:3462
double ss_time_sec()
Definition system.cxx:3467
INT cm_msg_flush_buffer()
Definition midas.cxx:865
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:915
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3201
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6893
INT db_send_changed_records()
Definition odb.cxx:13777
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5415
INT db_save_json(HNDLE hDB, HNDLE hKey, const char *filename, int flags)
Definition odb.cxx:10527
INT db_open_record(HNDLE hDB, HNDLE hKey, void *ptr, INT rec_size, WORD access_mode, void(*dispatcher)(INT, INT, void *), void *info)
Definition odb.cxx:13291
INT db_lock_database(HNDLE hDB)
Definition odb.cxx:2455
std::string strcomb1(const char **list)
Definition odb.cxx:598
INT db_save_xml(HNDLE hDB, HNDLE hKey, const char *filename)
Definition odb.cxx:9480
INT db_get_path(HNDLE hDB, HNDLE hKey, char *path, INT buf_size)
Definition odb.cxx:4990
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition odb.cxx:11805
INT db_copy(HNDLE hDB, HNDLE hKey, char *buffer, INT *buffer_size, const char *path)
Definition odb.cxx:8217
INT db_get_record_size(HNDLE hDB, HNDLE hKey, INT align, INT *buf_size)
Definition odb.cxx:11615
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6539
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3308
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:12972
INT db_copy_json_save(HNDLE hDB, HNDLE hKey, char **buffer, int *buffer_size, int *buffer_end)
Definition odb.cxx:10475
INT db_copy_xml(HNDLE hDB, HNDLE hKey, char *buffer, int *buffer_size, bool header)
Definition odb.cxx:9037
INT db_unlock_database(HNDLE hDB)
Definition odb.cxx:2577
INT db_unwatch(HNDLE hDB, HNDLE hKey)
Definition odb.cxx:13887
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition odb.cxx:8027
INT db_save(HNDLE hDB, HNDLE hKey, const char *filename, BOOL bRemote)
Definition odb.cxx:9245
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6019
INT db_get_link(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6072
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:13934
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13813
INT db_enum_link(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5725
int EXPRT json_write_anything(HNDLE hDB, HNDLE hKey, char **buffer, int *buffer_size, int *buffer_end, int level, int must_be_subdir, int flags, time_t timestamp)
Definition odb.cxx:10384
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10843
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
Definition odb.cxx:5261
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4079
BOOL ends_with_ustring(const char *str, const char *suffix)
Definition odb.cxx:3222
void json_write(char **buffer, int *buffer_size, int *buffer_end, int level, const char *s, int quoted)
Definition odb.cxx:9527
INT db_open_record1(HNDLE hDB, HNDLE hKey, void *ptr, INT rec_size, WORD access_mode, void(*dispatcher)(INT, INT, void *), void *info, const char *rec_str)
Definition odb.cxx:13441
INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size, INT align)
Definition odb.cxx:12291
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5586
INT db_close_record(HNDLE hDB, HNDLE hKey)
Definition odb.cxx:13473
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12800
INT db_create_link(HNDLE hDB, HNDLE hKey, const char *link_name, const char *destination)
Definition odb.cxx:3601
INT db_protect_database(HNDLE hDB)
Definition odb.cxx:3167
bool rpc_is_remote(void)
Definition midas.cxx:12761
const char * rpc_tid_name(INT id)
Definition midas.cxx:11764
INT rpc_tid_size(INT id)
Definition midas.cxx:11757
#define HS_GET_WRITER
Definition history.h:36
int hs_save_event_list(const std::vector< std::string > *pevents)
int hs_get_history(HNDLE hDB, HNDLE hKey, int flags, int debug_flag, MidasHistoryInterface **mh)
std::string history_dir()
const double MiB
int main()
Definition hwtest.cxx:23
void ** info
Definition fesimdaq.cxx:41
HNDLE hKey
char exp_name[NAME_LENGTH]
Definition mana.cxx:243
INT run_number[2]
Definition mana.cxx:246
DWORD n[4]
Definition mana.cxx:247
INT index
Definition mana.cxx:271
void * data
Definition mana.cxx:268
BOOL debug
debug printouts
Definition mana.cxx:254
BOOL daemon
Definition mana.cxx:258
INT type
Definition mana.cxx:269
INT bor(INT run_number, char *error)
Definition mana.cxx:1675
char host_name[HOST_NAME_LENGTH]
Definition mana.cxx:242
char bank_name[4]
Definition mdump.cxx:26
KEY key
Definition mdump.cxx:34
INT i
Definition mdump.cxx:32
DWORD actual_time
Definition mfe.cxx:37
static void compress(int init_bits, gdGifBuffer *buffer, gdImagePtr im)
Definition mgd.cxx:1526
static void output(code_int code)
Definition mgd.cxx:1647
bool ends_with_char(const std::string &s, char c)
Definition midas.cxx:403
INT bm_get_buffer_level(INT buffer_handle, INT *n_bytes)
Definition midas.cxx:7838
std::string msprintf(const char *format,...)
Definition midas.cxx:410
const char * mname[]
Definition midas.cxx:144
#define JSFLAG_RECURSE
Definition midas.h:1724
#define MIDAS_MAGIC
Definition midas.h:911
#define DIR_SEPARATOR
Definition midas.h:193
INT HNDLE
Definition midas.h:132
#define O_LARGEFILE
Definition midas.h:210
#define HOST_NAME_LENGTH
Definition midas.h:273
DWORD BOOL
Definition midas.h:105
#define DIR_SEPARATOR_STR
Definition midas.h:194
int INT
Definition midas.h:129
#define JSFLAG_FOLLOW_LINKS
Definition midas.h:1723
#define JSFLAG_OMIT_LAST_WRITTEN
Definition midas.h:1727
#define EVENTID_FRAG
Definition midas.h:907
#define DEFAULT_BUFFER_SIZE
Definition midas.h:255
#define EVENTID_MESSAGE
Definition midas.h:902
#define JSFLAG_OMIT_NAMES
Definition midas.h:1726
#define EVENTID_EOR
Definition midas.h:901
#define JS_LEVEL_1
Definition midas.h:1720
#define TRUE
Definition midas.h:182
#define EVENTID_FRAG1
Definition midas.h:906
#define TAPE_BUFFER_SIZE
Definition midas.h:264
#define POINTER_T
Definition midas.h:166
#define JSFLAG_OMIT_OLD
Definition midas.h:1728
#define EVENTID_BOR
Definition midas.h:900
#define NAME_LENGTH
Definition midas.h:272
#define message(type, str)
#define event_id
#define write(n, a, f, d)
#define name(x)
Definition midas_macro.h:24
#define set(var, value)
HNDLE hBuf
Definition minife.c:23
int select_compression_module(HNDLE hDB, HNDLE hSet, const char *name)
Definition mlogger.cxx:4039
void log_history(HNDLE hDB, HNDLE hKey, void *info)
Definition mlogger.cxx:5556
#define FREE(ptr)
Definition mlogger.cxx:367
#define CHECKSUM_ZLIB
Definition mlogger.cxx:3942
void receive_event(HNDLE hBuf, HNDLE request_id, EVENT_HEADER *pheader, void *pevent)
Definition mlogger.cxx:6406
void create_runlog_json_tree()
Definition mlogger.cxx:2647
#define CHECKSUM_CRC32C
Definition mlogger.cxx:3943
INT tr_stop(INT run_number, char *error)
Definition mlogger.cxx:6272
#define DISK_CHECK_INTERVAL_MILLISEC
Definition mlogger.cxx:310
std::string get_value(HNDLE hDB, HNDLE hDir, const char *name)
Definition mlogger.cxx:3990
INT tr_start_abort(INT run_number, char *error)
Definition mlogger.cxx:6243
static std::vector< MidasHistoryInterface * > mh
Definition mlogger.cxx:4735
EVENT_DEF * db_get_event_definition(short int event_id)
Definition mlogger.cxx:3312
#define COMPRESS_NONE
Definition mlogger.cxx:3965
void log_odb_dump_json(LOG_CHN *log_chn, short int event_id, INT run_number)
Definition mlogger.cxx:1758
void maybe_flush_history(time_t now)
Definition mlogger.cxx:5500
void log_odb_dump(LOG_CHN *log_chn, short int event_id, INT run_number)
Definition mlogger.cxx:1785
int log_create_writer(LOG_CHN *log_chn)
Definition mlogger.cxx:4073
static int hist_log_size
Definition mlogger.cxx:334
void close_history()
Definition mlogger.cxx:5518
void stop_image_history()
INT local_state
Definition mlogger.cxx:312
#define CHN_TREE_STR(_name)
Definition mlogger.cxx:98
INT tr_pause(INT run_number, char *error)
Definition mlogger.cxx:6380
static std::vector< std::string > history_events
Definition mlogger.cxx:4736
int log_generate_file_name(LOG_CHN *log_chn)
Definition mlogger.cxx:5662
static FILE * fopen_wx(const char *filename)
Definition mlogger.cxx:386
static int get_trans_flag()
Definition mlogger.cxx:4392
void log_system_history(HNDLE hDB, HNDLE hKey, void *info)
Definition mlogger.cxx:5608
int select_checksum_module(HNDLE hDB, HNDLE hSet, const char *name)
Definition mlogger.cxx:4022
INT tr_start(INT run_number, char *error)
Definition mlogger.cxx:5924
WriterInterface * NewCompression(LOG_CHN *log_chn, int code, WriterInterface *chained)
Definition mlogger.cxx:3971
#define OUTPUT_FILE
Definition mlogger.cxx:3985
INT log_open(LOG_CHN *log_chn, INT run_number)
Definition mlogger.cxx:4229
#define OUTPUT_NULL
Definition mlogger.cxx:3984
#define EVENT_DEF_CACHE_SIZE
INT ftp_error(const char *message)
Definition mlogger.cxx:2822
time_t last_history_flush
Definition mlogger.cxx:5498
INT tr_resume(INT run_number, char *error)
Definition mlogger.cxx:6392
WriterInterface * NewChecksum(LOG_CHN *log_chn, int code, int level, WriterInterface *chained)
Definition mlogger.cxx:3947
#define MEMZERO(obj)
Definition mlogger.cxx:365
WriterInterface * NewWriterBzip2(LOG_CHN *log_chn)
Definition mlogger.cxx:3907
int maybe_check_disk_level()
Definition mlogger.cxx:4367
INT log_close(LOG_CHN *log_chn, INT run_number)
Definition mlogger.cxx:4279
void create_runlog_ascii_tree()
Definition mlogger.cxx:2492
void odb_save(const char *filename, bool make_file_readonly)
Definition mlogger.cxx:1800
void log_odb_dump_xml(LOG_CHN *log_chn, short int event_id, INT run_number)
Definition mlogger.cxx:1727
void set_value(HNDLE hDB, HNDLE hDir, const char *name, const std::string &set, const std::string &def)
Definition mlogger.cxx:4001
DWORD auto_restart
Definition mlogger.cxx:318
int check_add(int v, int n, const std::string &val, const char *str, bool bdef, std::string *def, std::string *sel)
Definition mlogger.cxx:4010
int start_the_run()
Definition mlogger.cxx:4466
#define CHECKSUM_SHA256
Definition mlogger.cxx:3944
INT open_history()
Definition mlogger.cxx:4855
static std::string TimeToString(time_t t)
Definition mlogger.cxx:64
#define DELETE(ptr)
Definition mlogger.cxx:368
BOOL in_stop_transition
Definition mlogger.cxx:313
BOOL tape_message
Definition mlogger.cxx:314
#define CHN_SETTINGS_STR(_name)
Definition mlogger.cxx:202
DWORD subrun_start_time
Definition mlogger.cxx:319
INT ftp_open(const char *xdestination, FTP_CON **con)
Definition mlogger.cxx:2828
std::vector< LOG_CHN * > log_channels
Definition mlogger.cxx:322
#define OUTPUT_FTP
Definition mlogger.cxx:3986
int select_output_module(HNDLE hDB, HNDLE hSet, const char *name)
Definition mlogger.cxx:4056
#define OUTPUT_PIPE
Definition mlogger.cxx:3988
static void watch_settings(HNDLE hDB, HNDLE hKey, HNDLE index, void *info)
Definition mlogger.cxx:5906
#define CHECKSUM_NONE
Definition mlogger.cxx:3941
double stop_try_later
Definition mlogger.cxx:320
static std::string IntToString(int value)
Definition mlogger.cxx:57
int get_number_image_history_threads()
#define COMPRESS_BZIP2
Definition mlogger.cxx:3968
BOOL stop_requested
Definition mlogger.cxx:316
static HNDLE hDB
Definition mlogger.cxx:338
LOG_CHN * new_LOG_CHN(const char *name)
Definition mlogger.cxx:300
BOOL start_requested
Definition mlogger.cxx:317
static int write_history(DWORD transition, DWORD run_number)
Definition mlogger.cxx:5890
int close_buffers()
Definition mlogger.cxx:5862
DWORD run_start_time
Definition mlogger.cxx:319
static int add_event(int *indexp, time_t timestamp, int event_id, const char *event_name, HNDLE hKey, int ntags, const TAG *tags, time_t min_period, int hotlink)
Definition mlogger.cxx:4738
INT log_write(LOG_CHN *log_chn, EVENT_HEADER *pheader)
Definition mlogger.cxx:4527
static bool check_file_exists(const char *filename)
Definition mlogger.cxx:394
static struct hist_log_s * hist_log
Definition mlogger.cxx:336
void logger_init()
Definition mlogger.cxx:1618
void log_odb_dump_odb(LOG_CHN *log_chn, short int event_id, INT run_number)
Definition mlogger.cxx:1698
BOOL verbose
Definition mlogger.cxx:315
#define COMPRESS_PBZIP2
Definition mlogger.cxx:3969
#define CHN_STATISTICS_STR(_name)
Definition mlogger.cxx:242
#define OUTPUT_ROOT
Definition mlogger.cxx:3987
void start_image_history()
static std::string xpathname(const char *xpath, int level)
Definition mlogger.cxx:372
static int hist_log_max
Definition mlogger.cxx:335
void write_runlog_json(BOOL bor)
Definition mlogger.cxx:2694
#define COMPRESS_LZ4
Definition mlogger.cxx:3967
void write_runlog_ascii(BOOL bor)
Definition mlogger.cxx:2537
int log_disk_level(LOG_CHN *log_chn, double *pdisk_size, double *pdisk_free)
Definition mlogger.cxx:4338
int close_channels(int run_number, BOOL *p_tape_flag)
Definition mlogger.cxx:5817
WriterInterface * NewWriterPbzip2(LOG_CHN *log_chn)
Definition mlogger.cxx:3919
#define CHECKSUM_SHA512
Definition mlogger.cxx:3945
#define COMPRESS_ZLIB
Definition mlogger.cxx:3966
int stop_the_run(int restart)
Definition mlogger.cxx:4432
static FILE * fp
HNDLE hSet
Definition msysmon.cxx:531
int event_size
Definition msysmon.cxx:527
MUTEX_T * tm
Definition odbedit.cxx:39
INT j
Definition odbhist.cxx:40
double value[100]
Definition odbhist.cxx:42
char str[256]
Definition odbhist.cxx:33
char file_name[256]
Definition odbhist.cxx:41
DWORD status
Definition odbhist.cxx:39
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
void mbedtls_sha256_finish(mbedtls_sha256_context *ctx, unsigned char output[32])
SHA-256 final digest.
Definition sha256.cxx:289
void mbedtls_sha256_update(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen)
SHA-256 process buffer.
Definition sha256.cxx:240
void mbedtls_sha256_free(mbedtls_sha256_context *ctx)
Clear SHA-256 context.
Definition sha256.cxx:85
void mbedtls_sha256_init(mbedtls_sha256_context *ctx)
Initialize SHA-256 context.
Definition sha256.cxx:80
void mbedtls_sha256_starts(mbedtls_sha256_context *ctx, int is224)
SHA-256 context setup.
Definition sha256.cxx:102
void mbedtls_sha512_starts(mbedtls_sha512_context *ctx, int is384)
SHA-512 context setup.
Definition sha512.cxx:163
void mbedtls_sha512_update(mbedtls_sha512_context *ctx, const unsigned char *input, size_t ilen)
SHA-512 process buffer.
Definition sha512.cxx:270
void mbedtls_sha512_free(mbedtls_sha512_context *ctx)
Clear SHA-512 context.
Definition sha512.cxx:146
void mbedtls_sha512_finish(mbedtls_sha512_context *ctx, unsigned char output[64])
SHA-512 final digest.
Definition sha512.cxx:322
void mbedtls_sha512_init(mbedtls_sha512_context *ctx)
Initialize SHA-512 context.
Definition sha512.cxx:141
Definition midas.h:1215
uint32_t bzip2_compression
Definition mlogger.cxx:194
uint32_t pbzip2_num_cpu
Definition mlogger.cxx:195
double event_limit
Definition mlogger.cxx:179
INT obsolete_compression
Definition mlogger.cxx:171
double subrun_byte_limit
Definition mlogger.cxx:181
double obsolete_tape_capacity
Definition mlogger.cxx:182
double byte_limit
Definition mlogger.cxx:180
uint32_t pbzip2_compression
Definition mlogger.cxx:196
DWORD log_messages
Definition mlogger.cxx:175
uint32_t gzip_compression
Definition mlogger.cxx:193
double bytes_written_subrun
Definition mlogger.cxx:237
double bytes_written_total
Definition mlogger.cxx:236
double bytes_written_uncompressed
Definition mlogger.cxx:235
double bytes_written
Definition mlogger.cxx:234
double events_written
Definition mlogger.cxx:233
double disk_level
Definition mlogger.cxx:239
double files_written
Definition mlogger.cxx:238
short int event_id
Definition midas.h:852
DWORD data_size
Definition midas.h:856
DWORD time_stamp
Definition midas.h:855
int data
Definition ftplib.h:27
Definition midas.h:1026
INT num_values
Definition midas.h:1028
DWORD type
Definition midas.h:1027
INT total_size
Definition midas.h:1031
char name[NAME_LENGTH]
Definition midas.h:1029
INT item_size
Definition midas.h:1032
void * pfile
Definition mlogger.cxx:290
INT handle
Definition mlogger.cxx:263
std::string path
Definition mlogger.cxx:264
WriterInterface * writer
Definition mlogger.cxx:291
int post_checksum_module
Definition mlogger.cxx:296
INT msg_request_id
Definition mlogger.cxx:275
std::string name
Definition mlogger.cxx:262
DWORD last_checked
Definition mlogger.cxx:292
int output_module
Definition mlogger.cxx:297
INT subrun_number
Definition mlogger.cxx:271
void * ftp_con
Definition mlogger.cxx:289
INT msg_buffer_handle
Definition mlogger.cxx:273
CHN_STATISTICS statistics
Definition mlogger.cxx:279
INT request_id
Definition mlogger.cxx:274
int compression_module
Definition mlogger.cxx:295
BOOL do_disk_level
Definition mlogger.cxx:293
HNDLE settings_hkey
Definition mlogger.cxx:277
HNDLE stats_hkey
Definition mlogger.cxx:276
MIDAS_INFO * midas_info
Definition mlogger.cxx:280
INT type
Definition mlogger.cxx:266
INT buffer_handle
Definition mlogger.cxx:272
int pre_checksum_module
Definition mlogger.cxx:294
std::string pipe_command
Definition mlogger.cxx:265
CHN_SETTINGS settings
Definition mlogger.cxx:278
char * write_pointer
Definition mlogger.cxx:350
char * buffer
Definition mlogger.cxx:349
Definition midas.h:1234
DWORD type
Definition midas.h:1236
DWORD n_data
Definition midas.h:1237
char name[NAME_LENGTH]
Definition midas.h:1235
char * buffer
Definition mlogger.cxx:326
char event_name[256]
Definition mlogger.cxx:325
HNDLE hKeyVar
Definition mlogger.cxx:328
INT buffer_size
Definition mlogger.cxx:327
time_t min_period
Definition mlogger.cxx:330
DWORD n_var
Definition mlogger.cxx:329
time_t last_log
Definition mlogger.cxx:331
SHA-256 context structure.
Definition sha256.h:48
SHA-512 context structure.
Definition sha512.h:48
char c
Definition system.cxx:1310