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:
899 FILE* fFp;
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 assert(f != NULL);
2595
2596 // write column header line with variable names
2597 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", &hKeyRoot);
2598 for (int i = 0;; i++) {
2601 break;
2602 KEY key;
2603 db_get_key(hDB, hKey, &key);
2604 fprintf(f, "%s\t", key.name);
2605 }
2606 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", &hKeyRoot);
2607 for (int i = 0;; i++) {
2610 break;
2611 KEY key;
2612 db_get_key(hDB, hKey, &key);
2613 fprintf(f, "%s\t", key.name);
2614 }
2615 fprintf(f, "\n");
2616 fclose(f);
2617 }
2618
2619 // append data to logfile
2620 f = fopen(path, "at");
2621
2622 assert(f != NULL);
2623
2624 if (bor)
2625 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", &hKeyRoot);
2626 else
2627 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", &hKeyRoot);
2628
2629 for (int i = 0;; i++) {
2632 break;
2633 KEY key;
2634 db_get_key(hDB, hKey, &key);
2635 int size = key.total_size;
2636 char* data = (char*)malloc(size);
2637 assert(data);
2638 db_get_data(hDB, hKey, data, &size, key.type);
2639 std::string str = db_sprintf(data, size, 0, key.type);
2640 //printf("BBB key %s size %d %d [%s]\n", key.name, size, (int)strlen(str), str);
2641 free(data);
2642 fprintf(f, "%s\t", str.c_str());
2643 }
2644 if (!bor)
2645 fprintf(f, "\n");
2646 fclose(f);
2647}
2648
2649/*---- Create /Logger/Runlog/JSON tree ----------------------------*/
2650
2652{
2653 char dirname[256];
2654 int size, write_flag;
2656
2657 size = sizeof(write_flag);
2658 write_flag = 0;
2659 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Write data", &write_flag, &size, TID_BOOL, TRUE);
2660
2661 size = sizeof(dirname);
2662 strcpy(dirname, "runlogs");
2663 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Subdir", dirname, &size, TID_STRING, TRUE);
2664
2665 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", &hKeyRoot);
2666 if (!hKeyRoot) {
2667 /* create some default links */
2668 db_create_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", TID_KEY);
2669
2670 if (db_find_key(hDB, 0, "/Runinfo/Run number", &hKey) == DB_SUCCESS)
2671 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links BOR/Run number", "/Runinfo/Run number");
2672
2673 if (db_find_key(hDB, 0, "/Experiment/Run parameters/Comment", &hKey) == DB_SUCCESS)
2674 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links BOR/Comment", "/Experiment/Run parameters/Comment");
2675
2676 if (db_find_key(hDB, 0, "/Runinfo/Start time", &hKey) == DB_SUCCESS)
2677 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links BOR/Start time", "/Runinfo/Start time");
2678 }
2679
2680 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", &hKeyRoot);
2681 if (!hKeyRoot) {
2682 /* create some default links */
2683 db_create_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", TID_KEY);
2684
2685 if (db_find_key(hDB, 0, "/Runinfo/Stop time", &hKey) == DB_SUCCESS)
2686 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links EOR/Stop time", "/Runinfo/Stop time");
2687
2688 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/Events sent", &hKey) == DB_SUCCESS)
2689 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links EOR/Number of events",
2690 "/Equipment/Trigger/Statistics/Events sent");
2691
2692 }
2693}
2694
2695
2696/*---- Write ODB tree to JSON log file (one per run) -----------------*/
2697
2699 char filename[256], messagedir[256], datadir[256], dirname[256], path[256];
2700 int status, size, write_flag;
2701 int runnumber;
2702 HNDLE hKey;
2703
2704 /* do not update runlog if logger does not write data */
2705 size = sizeof(BOOL);
2706 write_flag = FALSE;
2707 db_get_value(hDB, 0, "/Logger/Write data", &write_flag, &size, TID_BOOL, TRUE);
2708 if (!write_flag)
2709 return;
2710
2711 /* get BOR or EOR list */
2712 if (bor) {
2713 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", &hKey);
2714 if (!hKey) {
2715 cm_msg(MERROR, "write_runlog_json", "Cannot find \"/Logger/Runlog/JSON/Links BOR");
2716 return;
2717 }
2718 } else {
2719 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", &hKey);
2720 if (!hKey) {
2721 cm_msg(MERROR, "write_runlog_json", "Cannot find \"/Logger/Runlog/JSON/Links EOR");
2722 return;
2723 }
2724 }
2725
2726 size = sizeof(write_flag);
2727 write_flag = 0;
2728 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Write data", &write_flag, &size, TID_BOOL, TRUE);
2729
2730 size = sizeof(datadir);
2731 strcpy(datadir, "");
2732 db_get_value(hDB, 0, "/Logger/Data Dir", datadir, &size, TID_STRING, TRUE);
2733
2734 size = sizeof(messagedir);
2735 strcpy(messagedir, "");
2736 db_get_value(hDB, 0, "/Logger/Message Dir", messagedir, &size, TID_STRING, TRUE);
2737
2738 size = sizeof(dirname);
2739 strcpy(dirname, "runlogs");
2740 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Subdir", dirname, &size, TID_STRING, TRUE);
2741
2742 size = sizeof(runnumber);
2743 db_get_value(hDB, 0, "/Runinfo/Run number", &runnumber, &size, TID_INT32, FALSE);
2744
2745 snprintf(filename, 256, "runlog_%06i.json", runnumber);
2746
2747 // use /Logger/Message dir, and if empty use /Logger/Data dir
2748 mstrlcpy(path, messagedir, sizeof(path));
2749 if (path[0] == 0)
2750 mstrlcpy(path, datadir, sizeof(path));
2751 if (path[strlen(path) - 1] != DIR_SEPARATOR)
2752 mstrlcat(path, DIR_SEPARATOR_STR, sizeof(path));
2753 mstrlcat(path, dirname, sizeof(path));
2754 if (path[strlen(path) - 1] != DIR_SEPARATOR)
2755 mstrlcat(path, DIR_SEPARATOR_STR, sizeof(path));
2756
2757 /* create directory if needed */
2758#ifdef OS_WINNT
2759 status = mkdir(path);
2760#else
2761 status = mkdir(path, 0755);
2762#endif
2763
2764 mstrlcat(path, filename, sizeof(path));
2765
2766 /* continue only if data should be written */
2767 if (!write_flag)
2768 return;
2769
2770 char fileflag[2] = "a";
2771 if (bor)
2772 strcpy(fileflag, "a");
2773
2774 FILE *file = fopen(path, fileflag);
2775 if (file == NULL) {
2776 cm_msg(MERROR, "write_runlog_json", "Cannot open file \"%s\"", path);
2777 return;
2778 }
2779
2780 if (bor)
2781 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", &hKey);
2782 else
2783 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", &hKey);
2784
2785 int buffer_size = 100000;
2786 char *buffer = (char *)malloc(buffer_size);
2787 int buffer_end = 0;
2788
2789 if (bor)
2790 json_write(&buffer, &buffer_size, &buffer_end, 0, "{\n \"BOR\": ", 0);
2791 else
2792 json_write(&buffer, &buffer_size, &buffer_end, 0, " \"EOR\": ", 0);
2793
2794 if (!rpc_is_remote())
2797 status = json_write_anything(hDB, hKey, &buffer, &buffer_size, &buffer_end, JS_LEVEL_1, 0, flags, 0);
2798 if (!rpc_is_remote())
2800
2801 if (bor)
2802 json_write(&buffer, &buffer_size, &buffer_end, 0, ",\n", 0);
2803 else
2804 json_write(&buffer, &buffer_size, &buffer_end, 0, " \n}\n", 0);
2805
2806 if (status == DB_SUCCESS) {
2807 if (buffer) {
2808 size_t wr = fwrite(buffer, 1, buffer_end, file);
2809 if (wr != (size_t) buffer_end) {
2810 cm_msg(MERROR, "write_runlog_json", "Cannot write to file \"%s\", fwrite() errno %d (%s)", filename, errno, strerror(errno));
2811 free(buffer);
2812 fclose(file);
2813 return;
2814 }
2815 }
2816 }
2817
2818 if (buffer)
2819 free(buffer);
2820
2821 fclose(file);
2822}
2823
2824/*---- open FTP channel --------------------------------------------*/
2825
2827{
2828 cm_msg(MERROR, "ftp_error", "%s", message);
2829 return 1;
2830}
2831
2833{
2834 INT status;
2835 short port = 0;
2836 char *token;
2838 char user[32], pass[32];
2839 char directory[256], file_name[256], file_mode[256];
2840 char bdestination[256]; // have to make a copy of destination because strtok() modifies it's string
2842 char* destination = bdestination;
2843
2844 // skip leading slash
2845 if (destination[0] == '/')
2846 destination += 1;
2847
2848 /*
2849 destination should have the form:
2850 host, port, user, password, directory, run%05d.mid
2851 */
2852
2853 /* break destination in components */
2854 token = strtok(destination, ",");
2855 if (token)
2856 mstrlcpy(host_name, token, sizeof(host_name));
2857
2858 token = strtok(NULL, ", ");
2859 if (token)
2860 port = atoi(token);
2861
2862 token = strtok(NULL, ", ");
2863 if (token)
2864 mstrlcpy(user, token, sizeof(user));
2865
2866 token = strtok(NULL, ", ");
2867 if (token)
2868 mstrlcpy(pass, token, sizeof(pass));
2869
2870 token = strtok(NULL, ", ");
2871 if (token)
2872 mstrlcpy(directory, token, sizeof(directory));
2873
2874 token = strtok(NULL, ", ");
2875 if (token)
2876 mstrlcpy(file_name, token, sizeof(file_name));
2877
2878 token = strtok(NULL, ", ");
2879 file_mode[0] = 0;
2880 if (token)
2881 mstrlcpy(file_mode, token, sizeof(file_mode));
2882
2883#ifdef FAL_MAIN
2885#else
2886 ftp_debug((int (*)(const char *)) puts, ftp_error);
2887#endif
2888
2889 status = ftp_login(con, host_name, port, user, pass, "");
2890 if (status >= 0)
2891 return status;
2892
2893 status = ftp_chdir(*con, directory);
2894 if (status >= 0)
2895 return status;
2896
2897 status = ftp_binary(*con);
2898 if (status >= 0)
2899 return status;
2900
2901 if (file_mode[0]) {
2902 status = ftp_command(*con, "umask %s", file_mode, 200, 250, EOF);
2903 if (status >= 0)
2904 return status;
2905 }
2906
2907 if (ftp_open_write(*con, file_name) >= 0)
2908 return (*con)->err_no;
2909
2910 return SS_SUCCESS;
2911}
2912
2913/*---- FTP writer --------------------------------------------------*/
2914
2916{
2917public:
2919 {
2920 if (fTrace)
2921 printf("WriterFtp: path [%s]\n", log_chn->path.c_str());
2922
2923 fFtp = NULL;
2924 }
2925
2926 ~WriterFtp() // dtor
2927 {
2928 if (fTrace)
2929 printf("WriterFtp: destructor\n");
2930
2931 if (fFtp) {
2932 ftp_bye(fFtp);
2933 fFtp = NULL;
2934 }
2935 }
2936
2938 {
2939 fBytesIn = 0;
2940 fBytesOut = 0;
2941
2942 if (fTrace)
2943 printf("WriterFtp: open path [%s]\n", log_chn->path.c_str());
2944
2945 assert(fFtp == NULL);
2946
2947 int status = ftp_open(log_chn->path.c_str(), &fFtp);
2948 if (status != SS_SUCCESS || fFtp == NULL) {
2949 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));
2950 return SS_FILE_ERROR;
2951 }
2952
2953 log_chn->handle = 9999;
2954
2955 return SUCCESS;
2956 }
2957
2958 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
2959 {
2960 if (fTrace)
2961 printf("WriterFtp: write path [%s], size %d\n", log_chn->path.c_str(), size);
2962
2963 if (size == 0)
2964 return SUCCESS;
2965
2966 if (fFtp == NULL) {
2967 return SS_FILE_ERROR;
2968 }
2969
2970 fBytesIn += size;
2971
2972 int wr = ftp_send(fFtp->data, (const char*)data, size);
2973
2974 if (wr > 0)
2975 fBytesOut += wr;
2976
2977 if (wr != size) {
2978 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));
2979 return SS_FILE_ERROR;
2980 }
2981
2982 return SUCCESS;
2983 }
2984
2986 {
2987 if (fTrace)
2988 printf("WriterFtp: close path [%s]\n", log_chn->path.c_str());
2989
2990 assert(fFtp != NULL);
2991
2992 ftp_close(fFtp);
2993 ftp_bye(fFtp);
2994 fFtp = NULL;
2995
2996 log_chn->handle = 0;
2997
2998 return SUCCESS;
2999 }
3000
3001 std::string wr_get_file_ext()
3002 {
3003 return "";
3004 }
3005
3006 std::string wr_get_chain()
3007 {
3008 return "FTP";
3009 }
3010
3011private:
3013};
3014
3015/*---- MIDAS format routines ---------------------------------------*/
3016
3017#ifdef OBSOLETE
3019{
3020 INT size, written = 0;
3021 off_t n;
3022
3023 MIDAS_INFO* info = log_chn->midas_info;
3024 size = (POINTER_T) info->write_pointer - (POINTER_T) info->buffer;
3025
3026 if (size == 0)
3027 return 0;
3028
3029 /* write record to device */
3030 if (log_chn->type == LOG_TYPE_FTP)
3031 written =
3032 ftp_send(((FTP_CON *) log_chn->ftp_con)->data, info->buffer,
3033 size) == size ? SS_SUCCESS : SS_FILE_ERROR;
3034 else if (log_chn->gzfile) {
3035 n = lseek(log_chn->handle, 0, SEEK_CUR);
3036 if (gzwrite((gzFile) log_chn->gzfile, info->buffer, size) != size)
3037 return -1;
3038 written = lseek(log_chn->handle, 0, SEEK_CUR) - n;
3039 } else if (log_chn->pfile) {
3040 written = fwrite(info->buffer, size, 1,log_chn->pfile);
3041 if (errno == EPIPE){
3042 cm_msg(MERROR, "midas_flush_buffer",
3043 "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",
3044 log_chn->pipe_command.c_str());
3045 log_chn->handle=0;
3046 }
3047 if (written !=1 )
3048 return -1;
3049 written = size;
3050 } else if (log_chn->handle) {
3051#ifdef OS_WINNT
3052 WriteFile((HANDLE) log_chn->handle, info->buffer, size, (unsigned long *) &written, NULL);
3053#else
3054 written = write(log_chn->handle, info->buffer, size);
3055#endif
3056 } else {
3057 /* we are writing into the void!?! */
3058 written = 0;
3059 }
3060
3061 info->write_pointer = info->buffer;
3062
3063 return written;
3064}
3065#endif
3066
3067/*------------------------------------------------------------------*/
3068
3069#ifdef OBSOLETE
3071{
3073
3074 MIDAS_INFO* info = log_chn->midas_info;
3075 written = 0;
3076
3077 /* check if event fits into buffer */
3078 size_left = TAPE_BUFFER_SIZE - ((POINTER_T) info->write_pointer - (POINTER_T) info->buffer);
3079
3080 if (size_left < evt_size) {
3081 /* copy first part of event */
3082 memcpy(info->write_pointer, pevent, size_left);
3083 info->write_pointer += size_left;
3084
3085 /* flush buffer */
3087 if (written < 0)
3088 return -1;
3089
3090 /* several writes for large events */
3091 while (evt_size - size_left >= TAPE_BUFFER_SIZE) {
3092 memcpy(info->buffer, (char *) pevent + size_left, TAPE_BUFFER_SIZE);
3093 info->write_pointer += TAPE_BUFFER_SIZE;
3095
3097 if (i < 0)
3098 return -1;
3099
3100 written += i;
3101 }
3102
3103 /* copy remaining part of event */
3104 memcpy(info->buffer, (char *) pevent + size_left, evt_size - size_left);
3105 info->write_pointer = info->buffer + (evt_size - size_left);
3106 } else {
3107 /* copy event to buffer */
3108 memcpy(info->write_pointer, pevent, evt_size);
3109 info->write_pointer += evt_size;
3110 }
3111
3112 /* update statistics */
3113 return written;
3114}
3115#endif
3116
3117/*------------------------------------------------------------------*/
3118
3119#ifdef OBSOLETE
3121{
3122 INT status;
3123
3124 /* allocate MIDAS buffer info */
3125 log_chn->midas_info = (MIDAS_INFO*) malloc(sizeof(MIDAS_INFO));
3126
3127 MIDAS_INFO* info = log_chn->midas_info;
3128 if (info == NULL) {
3129 log_chn->handle = 0;
3130 return SS_NO_MEMORY;
3131 }
3132
3133 /* allocate full ring buffer for that channel */
3134 if ((info->buffer = (char *) malloc(TAPE_BUFFER_SIZE)) == NULL) {
3135 free(info);
3136 log_chn->handle = 0;
3137 return SS_NO_MEMORY;
3138 }
3139
3140 info->write_pointer = info->buffer;
3141
3142 /* Create device channel */
3143 if (log_chn->type == LOG_TYPE_FTP) {
3144 status = ftp_open(log_chn->path.c_str(), &log_chn->ftp_con);
3145 if (status != SS_SUCCESS) {
3146 free(info->buffer);
3147 free(info);
3148 log_chn->handle = 0;
3149 return status;
3150 } else {
3151 log_chn->handle = 1;
3152 log_chn->do_disk_level = FALSE;
3153 log_chn->statistics.disk_level = -1;
3154 }
3155 } else {
3156 /* check if file exists */
3157 if (strstr(log_chn->path.c_str(), "null") == NULL) {
3158 log_chn->handle = open(log_chn->path.c_str(), O_RDONLY);
3159 if (log_chn->handle > 0) {
3160 /* check if file length is nonzero */
3161 if (lseek(log_chn->handle, 0, SEEK_END) > 0) {
3162 close(log_chn->handle);
3163 free(info->buffer);
3164 free(info);
3165 log_chn->handle = 0;
3166 return SS_FILE_EXISTS;
3167 }
3168 }
3169 }
3170
3171 log_chn->gzfile = NULL;
3172 log_chn->pfile = NULL;
3173 log_chn->handle = 0;
3174
3175 /* check that compression level and file name match each other */
3176 if (1) {
3177 const char *sufp = strstr(log_chn->path.c_str(), ".gz");
3178 int isgz = sufp && sufp[3]==0;
3179
3180 if (log_chn->compression>0 && !isgz) {
3181 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());
3182 free(info->buffer);
3183 free(info);
3184 return SS_FILE_ERROR;
3185 }
3186
3187 if (log_chn->compression==0 && isgz && log_chn->pipe_command[0] == 0) {
3188 cm_msg(MERROR, "midas_log_open",
3189 "Output file name ends with '.gz', but compression level is zero");
3190 free(info->buffer);
3191 free(info);
3192 return SS_FILE_ERROR;
3193 }
3194 }
3195
3196 if (log_chn->pipe_command[0] != 0){
3197#ifdef OS_WINNT
3198 cm_msg(MERROR, "midas_log_open", "Error: Pipe command not supported under Widnows");
3199 return SS_FILE_ERROR;
3200#else
3201 log_chn->pfile = popen(log_chn->pipe_command.c_str(), "w");
3202 log_chn->handle = 1;
3203 if (log_chn->pfile == NULL) {
3204 cm_msg(MERROR, "midas_log_open", "Error: popen() failed, cannot open pipe stream");
3205 free(info->buffer);
3206 free(info);
3207 log_chn->handle = 0;
3208 return SS_FILE_ERROR;
3209 }
3210#endif
3211 } else {
3212#ifdef OS_WINNT
3213 log_chn->handle = (int) CreateFile(log_chn->path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL,
3216#else
3217 log_chn->handle = open(log_chn->path.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_BINARY | O_LARGEFILE, 0444);
3218#endif
3219 if (log_chn->handle < 0) {
3220 free(info->buffer);
3221 free(info);
3222 log_chn->handle = 0;
3223 return SS_FILE_ERROR;
3224 }
3225
3226 log_chn->do_disk_level = TRUE;
3227
3228 if (log_chn->compression > 0) {
3229 log_chn->gzfile = gzdopen(log_chn->handle, "wb");
3230 if (log_chn->gzfile == NULL) {
3231 cm_msg(MERROR, "midas_log_open", "Error: gzdopen() failed, cannot open compression stream");
3232 free(info->buffer);
3233 free(info);
3234 log_chn->handle = 0;
3235 return SS_FILE_ERROR;
3236 }
3237
3238 gzsetparams((gzFile)log_chn->gzfile, log_chn->compression, Z_DEFAULT_STRATEGY);
3239 }
3240 }
3241 }
3242
3243 /* write ODB dump */
3244 if (log_chn->settings.odb_dump)
3246
3247 return SS_SUCCESS;
3248}
3249#endif
3250
3251/*------------------------------------------------------------------*/
3252
3253#ifdef OBSOLETE
3255{
3256 int written;
3257 off_t n;
3258
3259 /* write ODB dump */
3260 if (log_chn->settings.odb_dump)
3262
3264
3265 /* update statistics */
3266 log_chn->statistics.bytes_written += written;
3267 log_chn->statistics.bytes_written_total += written;
3268
3269 if (log_chn->type == LOG_TYPE_FTP) {
3270 ftp_close(log_chn->ftp_con);
3271 ftp_bye(log_chn->ftp_con);
3272 } else {
3273 if (log_chn->gzfile) {
3274 n = lseek(log_chn->handle, 0, SEEK_CUR);
3275 gzflush((gzFile) log_chn->gzfile, Z_FULL_FLUSH);
3276 written = lseek(log_chn->handle, 0, SEEK_CUR) - n;
3277 written += 10; // trailer? Obtained experimentally
3278 gzclose((gzFile) log_chn->gzfile);
3279 log_chn->statistics.bytes_written += written;
3280 log_chn->statistics.bytes_written_total += written;
3281 log_chn->gzfile = NULL;
3282 }
3283#ifdef OS_WINNT
3284 CloseHandle((HANDLE) log_chn->handle);
3285#else
3286 if (log_chn->pfile) {
3287 pclose(log_chn->pfile);
3288 log_chn->pfile = NULL;
3289 } else {
3290 close(log_chn->handle);
3291 }
3292#endif
3293 log_chn->handle = 0;
3294 }
3295
3296 assert(log_chn->midas_info != NULL);
3297 assert(log_chn->midas_info->buffer != NULL);
3298
3299 free(log_chn->midas_info->buffer);
3300 log_chn->midas_info->buffer = NULL;
3301 free(log_chn->midas_info);
3302 log_chn->midas_info = NULL;
3303
3304 return SS_SUCCESS;
3305}
3306#endif
3307
3308/*-- db_get_event_definition ---------------------------------------*/
3309
3310typedef struct {
3311 short int event_id;
3312 WORD format;
3313 HNDLE hDefKey;
3314} EVENT_DEF;
3315
3317{
3318 INT i, index, status, size;
3319 char str[80];
3321 WORD id;
3322
3323#define EVENT_DEF_CACHE_SIZE 30
3324 static EVENT_DEF *event_def = NULL;
3325
3326 /* allocate memory for cache */
3327 if (event_def == NULL)
3329
3330 assert(event_def != NULL);
3331
3332 /* lookup if event definition in cache */
3333 for (i = 0; event_def[i].event_id; i++)
3334 if (event_def[i].event_id == event_id)
3335 return &event_def[i];
3336
3337 /* search free cache entry */
3338 for (index = 0; index < EVENT_DEF_CACHE_SIZE; index++)
3339 if (event_def[index].event_id == 0)
3340 break;
3341
3342 if (index == EVENT_DEF_CACHE_SIZE) {
3343 cm_msg(MERROR, "db_get_event_definition", "too many event definitions");
3344 return NULL;
3345 }
3346
3347 /* check for system events */
3348 if (event_id < 0) {
3349 event_def[index].event_id = event_id;
3350 event_def[index].format = FORMAT_MIDAS;
3351 event_def[index].hDefKey = 0;
3352 return &event_def[index];
3353 }
3354
3355 status = db_find_key(hDB, 0, "/equipment", &hKeyRoot);
3356 if (status != DB_SUCCESS) {
3357 cm_msg(MERROR, "db_get_event_definition", "cannot find /equipment entry in ODB");
3358 return NULL;
3359 }
3360
3361 for (i = 0;; i++) {
3362 /* search for client with specific name */
3364 if (status == DB_NO_MORE_SUBKEYS) {
3365 cm_msg(MERROR, "db_get_event_definition", "Cannot find event id %d under /equipment", event_id);
3366 return NULL;
3367 }
3368
3369 size = sizeof(id);
3370 status = db_get_value(hDB, hKey, "Common/Event ID", &id, &size, TID_UINT16, TRUE);
3371 if (status != DB_SUCCESS)
3372 continue;
3373
3374 if (id == event_id) {
3375 /* set cache entry */
3376 event_def[index].event_id = id;
3377
3378 size = sizeof(str);
3379 str[0] = 0;
3380 db_get_value(hDB, hKey, "Common/Format", str, &size, TID_STRING, TRUE);
3381
3382 if (equal_ustring(str, "Fixed"))
3383 event_def[index].format = FORMAT_FIXED;
3384 else if (equal_ustring(str, "MIDAS"))
3385 event_def[index].format = FORMAT_MIDAS;
3386 else {
3387 cm_msg(MERROR, "db_get_event_definition", "unknown data format name \"%s\"", str);
3388 event_def[index].event_id = 0;
3389 return NULL;
3390 }
3391
3392 db_find_key(hDB, hKey, "Variables", &event_def[index].hDefKey);
3393 return &event_def[index];
3394 }
3395 }
3396}
3397
3398/*---- ROOT format routines ----------------------------------------*/
3399
3400#ifdef HAVE_ROOT
3401
3402#define MAX_BANKS 100
3403
3404typedef struct {
3405 int event_id;
3406 TTree *tree;
3407 int n_branch;
3410 int branch_len[MAX_BANKS];
3412} EVENT_TREE;
3413
3414struct TREE_STRUCT {
3415 TFile *f;
3416 int n_tree;
3418};
3419
3420/*------------------------------------------------------------------*/
3421
3423{
3424 int index, size, status;
3425 WORD id;
3426 char str[1000];
3428 KEY eqkey;
3429 EVENT_TREE *et;
3430
3431 status = db_find_key(hDB, 0, "/Equipment", &hKeyRoot);
3432 if (status != DB_SUCCESS) {
3433 cm_msg(MERROR, "root_book_trees", "cannot find \"/Equipment\" entry in ODB");
3434 return 0;
3435 }
3436
3437 tree_struct->n_tree = 0;
3438
3439 for (index = 0;; index++) {
3440 /* loop through all events under /Equipment */
3443 return 1;
3444
3446
3447 /* create tree */
3448 tree_struct->n_tree++;
3449 if (tree_struct->n_tree == 1)
3450 tree_struct->event_tree = (EVENT_TREE *) malloc(sizeof(EVENT_TREE));
3451 else
3452 tree_struct->event_tree =
3453 (EVENT_TREE *) realloc(tree_struct->event_tree, sizeof(EVENT_TREE) * tree_struct->n_tree);
3454
3455 assert(tree_struct->event_tree != NULL);
3456
3457 et = tree_struct->event_tree + (tree_struct->n_tree - 1);
3458
3459 size = sizeof(id);
3460 status = db_get_value(hDB, hKeyEq, "Common/Event ID", &id, &size, TID_UINT16, TRUE);
3461 if (status != DB_SUCCESS)
3462 continue;
3463
3464 et->event_id = id;
3465 et->n_branch = 0;
3466
3467 /* check format */
3468 size = sizeof(str);
3469 str[0] = 0;
3470 db_get_value(hDB, hKeyEq, "Common/Format", str, &size, TID_STRING, TRUE);
3471
3472 if (!equal_ustring(str, "MIDAS")) {
3473 cm_msg(MERROR, "root_book_events",
3474 "ROOT output only for MIDAS events, but %s in %s format", eqkey.name, str);
3475 return 0;
3476 }
3477
3478 /* create tree */
3479 sprintf(str, "Event \"%s\", ID %d", eqkey.name, id);
3480 et->tree = new TTree(eqkey.name, str);
3481 }
3482
3483 return 1;
3484}
3485
3486/*------------------------------------------------------------------*/
3487
3489{
3490 int i, status;
3491 char str[1000];
3492 HNDLE hKeyVar, hKeySubVar;
3494
3495 /* find definition of bank */
3496 status = db_find_key(hDB, hKeyDef, bank_name, &hKeyVar);
3497 if (status != DB_SUCCESS) {
3498 cm_msg(MERROR, "root_book_bank", "received unknown bank \"%s\" in event #%d", bank_name, event_id);
3499 return 0;
3500 }
3501
3502 if (et->n_branch + 1 == MAX_BANKS) {
3503 cm_msg(MERROR, "root_book_bank", "max number of banks (%d) exceeded in event #%d", MAX_BANKS, event_id);
3504 return 0;
3505 }
3506
3507 db_get_key(hDB, hKeyVar, &varkey);
3508
3509 if (varkey.type != TID_KEY) {
3510 /* book variable length array size */
3511
3512 sprintf(str, "n%s/I:%s[n%s]/", varkey.name, varkey.name, varkey.name);
3513
3514 switch (varkey.type) {
3515 case TID_UINT8:
3516 case TID_CHAR:
3517 strcat(str, "b");
3518 break;
3519 case TID_INT8:
3520 strcat(str, "B");
3521 break;
3522 case TID_UINT16:
3523 strcat(str, "s");
3524 break;
3525 case TID_INT16:
3526 strcat(str, "S");
3527 break;
3528 case TID_UINT32:
3529 strcat(str, "i");
3530 break;
3531 case TID_INT32:
3532 strcat(str, "I");
3533 break;
3534 case TID_BOOL:
3535 strcat(str, "I");
3536 break;
3537 case TID_FLOAT:
3538 strcat(str, "F");
3539 break;
3540 case TID_DOUBLE:
3541 strcat(str, "D");
3542 break;
3543 case TID_STRING:
3544 strcat(str, "C");
3545 break;
3546 }
3547
3548 et->branch[et->n_branch] = et->tree->Branch(bank_name, 0, (const char*)str);
3549 et->branch_name[et->n_branch] = *(DWORD *) bank_name;
3550 et->n_branch++;
3551 } else {
3552 /* book structured bank */
3553 str[0] = 0;
3554
3555 for (i = 0;; i++) {
3556 /* loop through bank variables */
3557 status = db_enum_key(hDB, hKeyVar, i, &hKeySubVar);
3559 break;
3560
3562
3563 if (i != 0)
3564 strcat(str, ":");
3565 strcat(str, subvarkey.name);
3566 strcat(str, "/");
3567 switch (subvarkey.type) {
3568 case TID_UINT8:
3569 case TID_CHAR:
3570 strcat(str, "b");
3571 break;
3572 case TID_INT8:
3573 strcat(str, "B");
3574 break;
3575 case TID_UINT16:
3576 strcat(str, "s");
3577 break;
3578 case TID_INT16:
3579 strcat(str, "S");
3580 break;
3581 case TID_UINT32:
3582 strcat(str, "i");
3583 break;
3584 case TID_INT32:
3585 strcat(str, "I");
3586 break;
3587 case TID_BOOL:
3588 strcat(str, "I");
3589 break;
3590 case TID_FLOAT:
3591 strcat(str, "F");
3592 break;
3593 case TID_DOUBLE:
3594 strcat(str, "D");
3595 break;
3596 case TID_STRING:
3597 strcat(str, "C");
3598 break;
3599 }
3600 }
3601
3602 et->branch[et->n_branch] = et->tree->Branch(bank_name, 0, (const char*)str);
3603 et->branch_name[et->n_branch] = *(DWORD *) bank_name;
3604 et->n_branch++;
3605 }
3606
3607 return 1;
3608}
3609
3610/*------------------------------------------------------------------*/
3611
3613{
3614 INT i;
3615 char bank_name[32];
3617 void *pdata;
3618 EVENT_TREE *et;
3619 BANK *pbk;
3620 BANK32 *pbk32;
3621 BANK32A *pbk32a;
3622 DWORD bklen;
3623 DWORD bkname;
3624 WORD bktype;
3625 TBranch *branch;
3626
3627 if ((pevent->event_id == EVENTID_BOR) ||
3628 (pevent->event_id == EVENTID_EOR) ||
3629 (pevent->event_id == EVENTID_MESSAGE) ||
3630 (pevent->event_id == EVENTID_FRAG1) ||
3631 (pevent->event_id == EVENTID_FRAG)) {
3632 // Cannot write system event into ROOT file
3633 return 0;
3634 }
3635
3637 if (event_def == NULL) {
3638 cm_msg(MERROR, "root_write", "Definition for event #%d not found under /Equipment", pevent->event_id);
3639 return -1;
3640 }
3641
3642 TREE_STRUCT *ts = log_chn->root_tree_struct;
3643
3644 /*---- MIDAS format ----------------------------------------------*/
3645
3646 if (event_def->format == FORMAT_MIDAS) {
3647 pbh = (BANK_HEADER *) (pevent + 1);
3648 bk_swap(pbh, FALSE);
3649
3650 /* find event in tree structure */
3651 for (i = 0; i < ts->n_tree; i++)
3652 if (ts->event_tree[i].event_id == pevent->event_id)
3653 break;
3654
3655 if (i == ts->n_tree) {
3656 cm_msg(MERROR, "root_write", "Event #%d not booked by root_book_events()", pevent->event_id);
3657 return -1;
3658 }
3659
3660 et = ts->event_tree + i;
3661
3662 /* first mark all banks non-filled */
3663 for (i = 0; i < et->n_branch; i++)
3664 et->branch_filled[i] = FALSE;
3665
3666 /* go thourgh all banks and set the address */
3667 pbk = NULL;
3668 pbk32 = NULL;
3669 pbk32a = NULL;
3670 do {
3671 /* scan all banks */
3672 if (bk_is32a(pbh)) {
3674 if (pbk32a == NULL)
3675 break;
3676 bkname = *((DWORD *) pbk32a->name);
3677 bktype = (WORD) pbk32a->type;
3678 } else if (bk_is32(pbh)) {
3680 if (pbk32 == NULL)
3681 break;
3682 bkname = *((DWORD *) pbk32->name);
3683 bktype = (WORD) pbk32->type;
3684 } else {
3685 bklen = bk_iterate(pbh, &pbk, &pdata);
3686 if (pbk == NULL)
3687 break;
3688 bkname = *((DWORD *) pbk->name);
3689 bktype = (WORD) pbk->type;
3690 }
3691
3692 if (rpc_tid_size(bktype & 0xFF))
3693 bklen /= rpc_tid_size(bktype & 0xFF);
3694
3695 *((DWORD *) bank_name) = bkname;
3696 bank_name[4] = 0;
3697
3698 for (i = 0; i < et->n_branch; i++)
3699 if (et->branch_name[i] == bkname)
3700 break;
3701
3702 if (i == et->n_branch)
3703 root_book_bank(et, event_def->hDefKey, pevent->event_id, bank_name);
3704
3705 branch = et->branch[i];
3706 et->branch_filled[i] = TRUE;
3707 et->branch_len[i] = bklen;
3708
3709 if (bktype != TID_STRUCT) {
3710 TIter next(branch->GetListOfLeaves());
3711 TLeaf *leaf = (TLeaf *) next();
3712
3713 /* varibale length array */
3714 leaf->SetAddress(&et->branch_len[i]);
3715
3716 leaf = (TLeaf *) next();
3717 leaf->SetAddress(pdata);
3718 } else {
3719 /* structured bank */
3720 branch->SetAddress(pdata);
3721 }
3722
3723 } while (1);
3724
3725 /* check if all branches have been filled */
3726 for (i = 0; i < et->n_branch; i++)
3727 if (!et->branch_filled[i])
3728 cm_msg(MERROR, "root_write", "Bank %s booked but not received, tree cannot be filled", bank_name);
3729
3730 /* fill tree */
3731 et->tree->Fill();
3732 }
3733
3734 return (INT) ts->f->GetBytesWritten();
3735}
3736
3737/*------------------------------------------------------------------*/
3738
3740{
3741 INT size, level;
3742 char str[256+100], name[256];
3744
3745 /* Create device channel */
3746 if (log_chn->type == LOG_TYPE_FTP) {
3747 cm_msg(MERROR, "root_log_open", "ROOT files can only reside on disk");
3748 log_chn->handle = 0;
3749 return -1;
3750 } else {
3751 /* check if file exists */
3752 if (strstr(log_chn->path.c_str(), "null") == NULL) {
3753 log_chn->handle = open(log_chn->path.c_str(), O_RDONLY);
3754 if (log_chn->handle > 0) {
3755 /* check if file length is nonzero */
3756 if (lseek(log_chn->handle, 0, SEEK_END) > 0) {
3757 close(log_chn->handle);
3758 log_chn->handle = 0;
3759 return SS_FILE_EXISTS;
3760 }
3761 }
3762 }
3763
3764 name[0] = 0;
3765 size = sizeof(name);
3766 db_get_value(hDB, 0, "/Experiment/Name", name, &size, TID_STRING, TRUE);
3767
3768 sprintf(str, "MIDAS exp. %s, run #%d", name, run_number);
3769
3770 TFile *f = new TFile(log_chn->path.c_str(), "create", str, 1);
3771 if (!f->IsOpen()) {
3772 delete f;
3773 log_chn->handle = 0;
3774 return SS_FILE_ERROR;
3775 }
3776 log_chn->handle = 1;
3777
3778 /* set compression level */
3779 level = 0;
3780 size = sizeof(level);
3781 db_get_value(hDB, log_chn->settings_hkey, "Compression", &level, &size, TID_INT32, FALSE);
3782 f->SetCompressionLevel(level);
3783
3784 /* create root structure with trees and branches */
3786
3787 assert(tree_struct != NULL);
3788
3789 tree_struct->f = f;
3790
3791 /* book event tree */
3793
3794 /* store file object in format_info */
3795 log_chn->root_tree_struct = tree_struct;
3796 }
3797
3798#if 0
3799 /* write ODB dump */
3800 if (log_chn->settings.odb_dump) {
3801 EVENT_HEADER event;
3802
3803 event.event_id = EVENTID_BOR;
3804 event.data_size = 0;
3805 event.serial_number = run_number;
3806
3807 //root_write(log_chn, &event, sizeof(EVENT_HEADER));
3808 }
3809#endif
3810
3811 return SS_SUCCESS;
3812}
3813
3814/*------------------------------------------------------------------*/
3815
3817{
3818 TREE_STRUCT *ts = log_chn->root_tree_struct;
3819
3820 /* flush and close file */
3821 ts->f->Write();
3822 ts->f->Close();
3823 delete ts->f; // deletes also all trees and branches!
3824
3825 /* delete event tree */
3826 free(ts->event_tree);
3827 ts->event_tree = NULL;
3828 free(ts);
3829 ts = NULL;
3830
3831 log_chn->root_tree_struct = NULL;
3832
3833 return SS_SUCCESS;
3834}
3835
3836class WriterROOT : public WriterInterface
3837{
3838public:
3839 WriterROOT(LOG_CHN* log_chn) // ctor
3840 {
3841 if (fTrace)
3842 printf("WriterROOT: path [%s]\n", log_chn->path.c_str());
3843 }
3844
3845 ~WriterROOT() // dtor
3846 {
3847 if (fTrace)
3848 printf("WriterROOT: destructor\n");
3849 }
3850
3852 {
3853 fBytesIn = 0;
3854 fBytesOut = 0;
3855
3856 if (fTrace)
3857 printf("WriterROOT: open path [%s]\n", log_chn->path.c_str());
3858
3860 if (status != SUCCESS)
3861 return status;
3862
3863 log_chn->handle = 9999;
3864
3865 return SUCCESS;
3866 }
3867
3868 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
3869 {
3870 if (fTrace)
3871 printf("WriterROOT: write path [%s], size %d\n", log_chn->path.c_str(), size);
3872
3873 if (size == 0)
3874 return SUCCESS;
3875
3876 fBytesIn += size;
3877
3878 int written = root_write(log_chn, (const EVENT_HEADER*)data, size);
3879
3880 if (written < 0) {
3881 return SS_FILE_ERROR;
3882 }
3883
3884 fBytesOut += size;
3885
3886 return SUCCESS;
3887 }
3888
3890 {
3891 if (fTrace)
3892 printf("WriterROOT: close path [%s]\n", log_chn->path.c_str());
3893
3895
3896 log_chn->handle = 0;
3897
3898 return status;
3899 }
3900
3901 std::string wr_get_file_ext()
3902 {
3903 return ".root";
3904 }
3905
3906 std::string wr_get_chain()
3907 {
3908 return "ROOT";
3909 }
3910
3911private:
3912};
3913
3914#endif /* HAVE_ROOT */
3915
3916/*------------------------------------------------------------------*/
3917
3919{
3920 std::string bzip2_command = "bzip2 -z";
3921
3922 if (log_chn->settings.bzip2_compression) {
3923 bzip2_command += " -";
3924 bzip2_command += IntToString(log_chn->settings.bzip2_compression);
3925 }
3926
3927 return new WriterPopen(log_chn, (bzip2_command + " > ").c_str(), ".bz2");
3928}
3929
3931{
3932 std::string pbzip2_command = "pbzip2 -c -z";
3933
3934 if (log_chn->settings.pbzip2_num_cpu) {
3935 pbzip2_command += " -p";
3936 pbzip2_command += IntToString(log_chn->settings.pbzip2_num_cpu);
3937 }
3938
3939 if (log_chn->settings.pbzip2_compression) {
3940 pbzip2_command += " -";
3941 pbzip2_command += IntToString(log_chn->settings.pbzip2_compression);
3942 }
3943
3944 if (strlen(log_chn->settings.pbzip2_options) > 0) {
3945 pbzip2_command += " ";
3946 pbzip2_command += log_chn->settings.pbzip2_options;
3947 }
3948
3949 return new WriterPopen(log_chn, (pbzip2_command + " > ").c_str(), ".bz2");
3950}
3951
3952#define CHECKSUM_NONE 0
3953#define CHECKSUM_ZLIB 1
3954#define CHECKSUM_CRC32C 2
3955#define CHECKSUM_SHA256 3
3956#define CHECKSUM_SHA512 4
3957
3959{
3960 if (code == CHECKSUM_NONE) {
3961 return chained;
3962 } else if (code == CHECKSUM_ZLIB) {
3963 return new WriterCRC32Zlib(log_chn, level, chained);
3964 } else if (code == CHECKSUM_CRC32C) {
3965 return new WriterCRC32C(log_chn, level, chained);
3966 } else if (code == CHECKSUM_SHA256) {
3967 return new WriterSHA256(log_chn, level, chained);
3968 } else if (code == CHECKSUM_SHA512) {
3969 return new WriterSHA512(log_chn, level, chained);
3970 } else {
3971 cm_msg(MERROR, "log_create_writer", "channel %s unknown checksum code %d", log_chn->path.c_str(), code);
3972 return chained;
3973 }
3974}
3975
3976#define COMPRESS_NONE 0
3977#define COMPRESS_ZLIB 1
3978#define COMPRESS_LZ4 2
3979#define COMPRESS_BZIP2 3
3980#define COMPRESS_PBZIP2 4
3981
3983{
3984 if (code == COMPRESS_NONE) {
3985 return chained;
3986 } else if (code == COMPRESS_LZ4) {
3987 return new WriterLZ4(log_chn, chained);
3988 } else {
3989 cm_msg(MERROR, "log_create_writer", "channel %s unknown compression code %d", log_chn->path.c_str(), code);
3990 return chained;
3991 }
3992}
3993
3994#define OUTPUT_NONE 0
3995#define OUTPUT_NULL 1
3996#define OUTPUT_FILE 2
3997#define OUTPUT_FTP 3
3998#define OUTPUT_ROOT 4
3999#define OUTPUT_PIPE 5
4000
4001std::string get_value(HNDLE hDB, HNDLE hDir, const char* name)
4002{
4004 value[0] = 0;
4005 int size = sizeof(value);
4006 int status = db_get_value(hDB, hDir, name, &value, &size, TID_STRING, FALSE);
4007 if (status != DB_SUCCESS)
4008 return "";
4009 return value;
4010}
4011
4012void set_value(HNDLE hDB, HNDLE hDir, const char* name, const std::string& set, const std::string& def)
4013{
4014 std::string s = set + " (one of:" + def + ")";
4015 int size = 256; // MUST match record definition // strlen(value);
4016 s.reserve(size);
4017 const char* value = s.c_str();
4018 db_set_value(hDB, hDir, name, value, size, 1, TID_STRING);
4019}
4020
4021int check_add(int v, int n, const std::string& val, const char* str, bool bdef, std::string* def, std::string* sel)
4022{
4023 (*def) += std::string(" ") + str;
4024 if (v)
4025 return v; // keep returning the first selection
4026 if (val.find(str) == 0) {
4027 *sel = str;
4028 return n; // if no selection yet, return the new selection
4029 }
4030 return v;
4031}
4032
4034{
4035 std::string val = get_value(hDB, hSet, name);
4036 std::string sel;
4037 std::string def;
4038 int s = 0;
4039 s = check_add(s, CHECKSUM_NONE, val, "NONE", false, &def, &sel);
4040 s = check_add(s, CHECKSUM_CRC32C, val, "CRC32C", true, &def, &sel);
4041 s = check_add(s, CHECKSUM_SHA256, val, "SHA256", false, &def, &sel);
4042 s = check_add(s, CHECKSUM_SHA512, val, "SHA512", false, &def, &sel);
4043 s = check_add(s, CHECKSUM_ZLIB, val, "ZLIB", false, &def, &sel);
4044 if (sel == "")
4045 sel = "NONE";
4046 //set_value(hDB, hSet, name, sel, def);
4047 return s;
4048}
4049
4051{
4052 std::string val = get_value(hDB, hSet, name);
4053 std::string sel;
4054 std::string def;
4055 int s = 0;
4056 s = check_add(s, COMPRESS_NONE, val, "none", false, &def, &sel);
4057 s = check_add(s, COMPRESS_ZLIB, val, "gzip", true, &def, &sel);
4058 s = check_add(s, COMPRESS_LZ4, val, "lz4", false, &def, &sel);
4059 s = check_add(s, COMPRESS_BZIP2, val, "bzip2", false, &def, &sel);
4060 s = check_add(s, COMPRESS_PBZIP2, val, "pbzip2", false, &def, &sel);
4061 if (sel == "")
4062 sel = "none";
4063 //set_value(hDB, hSet, name, sel, def);
4064 return s;
4065}
4066
4068{
4069 std::string val = get_value(hDB, hSet, name);
4070 std::string sel;
4071 std::string def;
4072 int s = 0;
4073 s = check_add(s, OUTPUT_NULL, val, "NULL", false, &def, &sel);
4074 s = check_add(s, OUTPUT_FILE, val, "FILE", true, &def, &sel);
4075 s = check_add(s, OUTPUT_FTP, val, "FTP", false, &def, &sel);
4076 s = check_add(s, OUTPUT_ROOT, val, "ROOT", false, &def, &sel);
4077 s = check_add(s, OUTPUT_PIPE, val, "PIPE", false, &def, &sel);
4078 if (sel == "")
4079 sel = "FILE";
4080 //set_value(hDB, hSet, name, sel, def);
4081 return s;
4082}
4083
4085{
4086 assert(log_chn->writer == NULL);
4087 log_chn->writer = NULL;
4088
4089 if (log_chn->output_module > 0) {
4090
4091 if (log_chn->compression_module == COMPRESS_ZLIB) {
4092
4093 if (log_chn->output_module != OUTPUT_FILE) {
4094 cm_msg(MERROR, "log_create_writer", "channel %s requested GZIP/ZLIB compression, output module must be FILE", log_chn->path.c_str());
4095 return SS_FILE_ERROR;
4096 }
4097
4098 log_chn->writer = new WriterGzip(log_chn, 0);
4099 log_chn->do_disk_level = TRUE;
4100 }
4101 else if (log_chn->compression_module == COMPRESS_BZIP2) {
4102
4103 if (log_chn->output_module != OUTPUT_FILE) {
4104 cm_msg(MERROR, "log_create_writer", "channel %s requested BZIP2 compression, output module must be FILE", log_chn->path.c_str());
4105 return SS_FILE_ERROR;
4106 }
4107
4108 log_chn->writer = NewWriterBzip2(log_chn);
4109 log_chn->do_disk_level = TRUE;
4110
4111 }
4112 else if (log_chn->compression_module == COMPRESS_PBZIP2) {
4113
4114 if (log_chn->output_module != OUTPUT_FILE) {
4115 cm_msg(MERROR, "log_create_writer", "channel %s requested PBZIP2 compression, output module must be FILE", log_chn->path.c_str());
4116 return SS_FILE_ERROR;
4117 }
4118
4119 log_chn->writer = NewWriterPbzip2(log_chn);
4120 log_chn->do_disk_level = TRUE;
4121 }
4122 else if (log_chn->output_module == OUTPUT_NULL) {
4123
4124 log_chn->writer = new WriterNull(log_chn);
4125 log_chn->do_disk_level = TRUE;
4126 }
4127 else if (log_chn->output_module == OUTPUT_FILE) {
4128
4129 log_chn->writer = NewCompression(log_chn, log_chn->compression_module, NewChecksum(log_chn, log_chn->post_checksum_module, 0, new WriterFile(log_chn)));
4130 log_chn->do_disk_level = TRUE;
4131 }
4132 else if (log_chn->output_module == OUTPUT_FTP) {
4133
4134 log_chn->writer = NewCompression(log_chn, log_chn->compression_module, NewChecksum(log_chn, log_chn->post_checksum_module, 0, new WriterFtp(log_chn)));
4135 log_chn->do_disk_level = FALSE;
4136 log_chn->statistics.disk_level = -1;
4137 }
4138 else if (log_chn->output_module == OUTPUT_ROOT) {
4139
4140#ifdef HAVE_ROOT
4141 log_chn->writer = new WriterROOT(log_chn);
4142 log_chn->do_disk_level = TRUE;
4143#else
4144 cm_msg(MERROR, "log_create_writer", "channel \"%s\" requested ROOT output, but mlogger is built without HAVE_ROOT", log_chn->name.c_str());
4145 log_chn->writer = new WriterNull(log_chn);
4146 log_chn->do_disk_level = TRUE;
4147#endif
4148 }
4149 else if (log_chn->output_module == OUTPUT_PIPE) {
4150
4151 log_chn->writer = NewCompression(log_chn, log_chn->compression_module, NewChecksum(log_chn, log_chn->post_checksum_module, 0, new WriterPopen(log_chn, "xxx", "")));
4152 log_chn->do_disk_level = FALSE;
4153 log_chn->statistics.disk_level = -1;
4154 }
4155
4156 //log_chn->writer = new WriterROOT(log_chn);
4157 //log_chn->do_disk_level = TRUE;
4158
4159 if (log_chn->pre_checksum_module) {
4160 log_chn->writer = NewChecksum(log_chn, log_chn->pre_checksum_module, 1, log_chn->writer);
4161 }
4162
4163 //cm_msg(MINFO, "log_create_writer", "channel \"%s\" writer chain: %s", log_chn->path.c_str(), log_chn->writer->wr_get_chain().c_str());
4164
4165 return SUCCESS;
4166 }
4167
4168 cm_msg(MERROR, "log_create_writer", "channel %s invalid output module value %d", log_chn->path.c_str(), log_chn->output_module);
4169 return SS_FILE_ERROR;
4170
4171#ifdef OBSOLETE
4172 int xcompress = log_chn->compression;
4173 // compression format: ABNNN
4174 // A - pre-compression checksum,
4175 // B - post-compression (file) checksum,
4176 // NNN - compression code
4177 int compression = xcompress%1000;
4178 int prechecksum = (xcompress/10000)%10;
4179 int postchecksum = (xcompress/1000)%10;
4180
4181 // 0=old file output, 1-9=old gzip output
4182 if (compression < 10)
4183 return SUCCESS;
4184
4185 if (compression==80) {
4186#ifdef HAVE_ROOT
4187 log_chn->writer = new WriterROOT(log_chn);
4188 log_chn->do_disk_level = TRUE;
4189#else
4190 log_chn->writer = new WriterNull(log_chn);
4191 log_chn->do_disk_level = TRUE;
4192#endif
4193 } else if (compression==81) {
4194 log_chn->writer = new WriterFtp(log_chn);
4195 log_chn->do_disk_level = FALSE;
4196 log_chn->statistics.disk_level = -1;
4197 } else if (compression==82) {
4199 log_chn->do_disk_level = FALSE;
4200 log_chn->statistics.disk_level = -1;
4201 } else if (compression==98) {
4202 log_chn->writer = new WriterNull(log_chn);
4203 log_chn->do_disk_level = TRUE;
4204 } else if (compression==99) {
4205 log_chn->writer = new WriterFile(log_chn);
4206 log_chn->do_disk_level = TRUE;
4207 } else if (compression==100) {
4209 log_chn->do_disk_level = TRUE;
4210 } else if (compression==200) {
4211 log_chn->writer = NewWriterBzip2(log_chn);
4212 log_chn->do_disk_level = TRUE;
4213 } else if (compression==201) {
4214 log_chn->writer = NewWriterPbzip2(log_chn);
4215 log_chn->do_disk_level = TRUE;
4216 } else if (compression==300) {
4217 log_chn->writer = new WriterGzip(log_chn, 0);
4218 log_chn->do_disk_level = TRUE;
4219 } else if (compression==301) {
4220 log_chn->writer = new WriterGzip(log_chn, 1);
4221 log_chn->do_disk_level = TRUE;
4222 } else if (compression==309) {
4223 log_chn->writer = new WriterGzip(log_chn, 9);
4224 log_chn->do_disk_level = TRUE;
4225 } else {
4226 cm_msg(MERROR, "log_create_writer", "channel %s unknown compression mode %d", log_chn->path.c_str(), log_chn->compression);
4227 return SS_FILE_ERROR;
4228 }
4229
4230 if (prechecksum) {
4231 log_chn->writer = NewChecksum(log_chn, prechecksum, 1, log_chn->writer);
4232 }
4233#endif
4234
4235 return SS_SUCCESS;
4236}
4237
4238/*---- log_open ----------------------------------------------------*/
4239
4241{
4242 INT status = SUCCESS;
4243
4244 log_chn->last_checked = ss_millitime();
4245
4246 if (log_chn->writer) {
4247 WriterInterface* wr = log_chn->writer;
4248
4250
4251 if (status != SUCCESS)
4252 return status;
4253
4254 /* write ODB dump */
4255 if (log_chn->settings.odb_dump)
4257
4258 /* update statistics */
4259 double incr = wr->fBytesOut - log_chn->statistics.bytes_written_subrun;
4260 if (incr < 0)
4261 incr = 0;
4262
4263 //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);
4264
4265 log_chn->statistics.bytes_written += incr;
4266 log_chn->statistics.bytes_written_subrun = wr->fBytesOut;
4267 log_chn->statistics.bytes_written_total += incr;
4268 } else {
4269 return SS_INVALID_FORMAT;
4270 }
4271#ifdef OBSOLETE
4272 } else if (equal_ustring(log_chn->settings.format, "ROOT")) {
4273#ifdef HAVE_ROOT
4274 log_chn->format = FORMAT_ROOT;
4276#else
4277 return SS_NO_ROOT;
4278#endif
4279 } else if (equal_ustring(log_chn->settings.format, "MIDAS")) {
4280 log_chn->format = FORMAT_MIDAS;
4282 } else
4283 return SS_INVALID_FORMAT;
4284#endif
4285 return status;
4286}
4287
4288/*---- log_close ---------------------------------------------------*/
4289
4291{
4292 if (log_chn->writer) {
4293 /* write ODB dump */
4294 if (log_chn->settings.odb_dump)
4296
4297 WriterInterface* wr = log_chn->writer;
4298
4300
4301 /* update statistics */
4302
4303 double incr = wr->fBytesOut - log_chn->statistics.bytes_written_subrun;
4304 if (incr < 0)
4305 incr = 0;
4306
4307 //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);
4308
4309 log_chn->statistics.bytes_written += incr;
4310 log_chn->statistics.bytes_written_subrun = wr->fBytesOut;
4311 log_chn->statistics.bytes_written_total += incr;
4312 }
4313#ifdef OBSOLETE
4314#ifdef HAVE_ROOT
4315 } else if (log_chn->format == FORMAT_ROOT) {
4317#endif
4318 } else if (log_chn->format == FORMAT_MIDAS) {
4320 }
4321#endif
4322
4323 /* if file name starts with '.', rename it */
4324 char str[256]; // FIXME: this will truncate the filename of the output file. K.O.
4325 mstrlcpy(str, log_chn->path.c_str(), sizeof(str));
4326 char* p = str;
4327 if (strrchr(str, DIR_SEPARATOR)) {
4328 p = strrchr(str, DIR_SEPARATOR)+1;
4329 }
4330 if (*p == '.') {
4331 mstrlcpy(p, p+1, sizeof(str));
4332 rename(log_chn->path.c_str(), str); // FIXME: must check return status. K.O.
4333 }
4334
4335 log_chn->statistics.files_written += 1;
4336 log_chn->handle = 0;
4337 log_chn->ftp_con = NULL;
4338
4339 if (log_chn->writer) {
4340 delete log_chn->writer;
4341 log_chn->writer = NULL;
4342 }
4343
4344 return SS_SUCCESS;
4345}
4346
4347/*---- log disk levels ---------------------------------------------*/
4348
4350{
4351 std::string str = log_chn->path.c_str();
4352 size_t pos = str.rfind('/');
4353 if (pos != std::string::npos) {
4354 str.erase(pos); // strip filename for bzip2
4355 }
4356
4357 //printf("log_disk_level [%s] [%s]\n", log_chn->path.c_str(), str.c_str());
4358
4359 double MiB = 1024*1024;
4360 double disk_size = ss_disk_size(str.c_str());
4361 double disk_free = ss_disk_free(str.c_str());
4362 double limit = 10E6;
4363 double level = 1.0-disk_free/disk_size;
4364
4365 if (pdisk_size)
4366 *pdisk_size = disk_size; // should be in statistics
4367 if (pdisk_free)
4368 *pdisk_free = disk_free; // should be in statistics
4369
4370 log_chn->statistics.disk_level = level;
4371
4372 if (verbose)
4373 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);
4374
4375 return SUCCESS;
4376}
4377
4379{
4381 static DWORD last_check_time = 0;
4382
4383 if (last_check_time == 0)
4385
4387 return SUCCESS;
4388
4390
4391 for (unsigned i = 0; i < log_channels.size(); i++) {
4393
4394 if (!chn->do_disk_level)
4395 continue;
4396
4398 }
4399
4400 return SUCCESS;
4401}
4402
4403static int get_trans_flag()
4404{
4405 int status, size, flag;
4406
4407 size = sizeof(BOOL);
4408 flag = FALSE;
4409 status = db_get_value(hDB, 0, "/Logger/Async transitions", &flag, &size, TID_BOOL, FALSE);
4410
4411 if (status == DB_SUCCESS) {
4412 cm_msg(MINFO, "get_trans_flag", "ODB \"/Logger/Async transitions\" is obsolete, please delete it");
4413 }
4414
4415 size = sizeof(BOOL);
4416 flag = TRUE;
4417 status = db_get_value(hDB, 0, "/Logger/Multithread transitions", &flag, &size, TID_BOOL, FALSE);
4418
4419 if (status == DB_SUCCESS) {
4420 cm_msg(MINFO, "get_trans_flag", "ODB \"/Logger/Multithread transitions\" is obsolete, please delete it");
4421 }
4422
4423 size = sizeof(BOOL);
4424 flag = FALSE;
4425 db_get_value(hDB, 0, "/Logger/Detached transitions", &flag, &size, TID_BOOL, TRUE);
4426
4427 // NB: we must use multithread or detached (via mtransition) transition
4428 // otherwise we deadlock against frontends: they are writing to the SYSTEM
4429 // buffer but we (mlogger) are not reading from it. if SYSTEM buffer is full,
4430 // clients get stuck waiting for free space and cannot not handle TR_STOP RPC.
4431 // if they could handle, it, they would still be stuck in bm_flush_cache()
4432 // because we (mlogger) are not reading the SYSTEM buffer and these last
4433 // events have nowhere to go. K.O.
4434
4435 if (flag)
4436 return TR_DETACH;
4437 else
4438 return TR_MTHREAD;
4439}
4440
4441/*---- log_write ---------------------------------------------------*/
4442
4444{
4445 int status, flag, size;
4446 char errstr[256];
4447
4448 if (restart) {
4449 size = sizeof(BOOL);
4450 flag = FALSE;
4451 db_get_value(hDB, 0, "/Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
4452
4453 if (flag) {
4455 auto_restart = 0;
4456 }
4457 }
4458
4460 stop_try_later = 0;
4461
4462 int trans_flag = get_trans_flag();
4463
4464 status = cm_transition(TR_STOP, 0, errstr, sizeof(errstr), trans_flag, verbose);
4466 cm_msg(MERROR, "stop_the_run", "another transition is in progress, will try again later");
4468 stop_try_later = ss_time_sec() + 10.0;
4469 } else if (status != CM_SUCCESS) {
4470 cm_msg(MERROR, "stop_the_run", "cannot stop the run, cm_transition() status %d, error: %s", status, errstr);
4471 return status;
4472 }
4473
4474 return status;
4475}
4476
4478{
4479 int status, size, state, run_number, flag;
4480 char errstr[256];
4481
4483 auto_restart = 0;
4484
4485 /* check if autorestart is still on */
4486 size = sizeof(BOOL);
4487 flag = FALSE;
4488 db_get_value(hDB, 0, "/Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
4489
4490 if (!flag) {
4491 cm_msg(MINFO, "start_the_run", "Run auto restart canceled");
4492 return SUCCESS;
4493 }
4494
4495 /* check if really stopped */
4496 size = sizeof(state);
4497 status = db_get_value(hDB, 0, "Runinfo/State", &state, &size, TID_INT32, TRUE);
4498 if (status != DB_SUCCESS) {
4499 cm_msg(MERROR, "start_the_run", "cannot get Runinfo/State in database, db_get_value() status %d", status);
4500 return status;
4501 }
4502
4503 static int backoff = 1;
4504
4505 if (state != STATE_STOPPED) {
4506 cm_msg(MINFO, "start_the_run", "Runinfo/State %d is not STATE_STOPPED, will try again in %d seconds", state, backoff);
4507 auto_restart = ss_time() + backoff; /* try again later */
4508 if (backoff < 1)
4509 backoff = 1;
4510 else if (backoff > 1*60)
4511 backoff = 1*60;
4512 else
4513 backoff *= 2;
4514 return SUCCESS;
4515 }
4516
4517 backoff = 1;
4518
4519 size = sizeof(run_number);
4520 status = db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
4521 assert(status == SUCCESS);
4522
4523 if (run_number <= 0) {
4524 cm_msg(MERROR, "start_the_run", "aborting on attempt to use invalid run number %d", run_number);
4525 abort();
4526 }
4527
4528 int trans_flag = get_trans_flag();
4529
4530 cm_msg(MTALK, "start_the_run", "starting new run");
4531 status = cm_transition(TR_START, run_number + 1, errstr, sizeof(errstr), trans_flag, verbose);
4532 if (status != CM_SUCCESS)
4533 cm_msg(MERROR, "start_the_run", "cannot restart run: cm_transition() status %d, error: %s", status, errstr);
4534
4535 return status;
4536}
4537
4539{
4540 INT status = 0, size;
4543
4544 //printf("log_write %d\n", pevent->data_size + sizeof(EVENT_HEADER));
4545
4546 DWORD start_time = ss_millitime();
4547 int evt_size = pevent->data_size + sizeof(EVENT_HEADER);
4548
4549 if (log_chn->writer) {
4550 WriterInterface* wr = log_chn->writer;
4551 status = wr->wr_write(log_chn, pevent, evt_size);
4552
4553 if (status == SUCCESS) {
4554 /* update statistics */
4555 log_chn->statistics.events_written++;
4556 log_chn->statistics.bytes_written_uncompressed += evt_size;
4557 }
4558
4559 double incr = wr->fBytesOut - log_chn->statistics.bytes_written_subrun;
4560 if (incr < 0)
4561 incr = 0;
4562
4563 //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);
4564
4565 log_chn->statistics.bytes_written += incr;
4566 log_chn->statistics.bytes_written_subrun = wr->fBytesOut;
4567 log_chn->statistics.bytes_written_total += incr;
4568 }
4569#ifdef OBSOLETE
4570 } else {
4571 int written = 0;
4572
4573 if (log_chn->format == FORMAT_MIDAS) {
4574 written = midas_write(log_chn, pevent, pevent->data_size + sizeof(EVENT_HEADER));
4575#ifdef HAVE_ROOT
4576 } else if (log_chn->format == FORMAT_ROOT) {
4577 written = root_write(log_chn, pevent, pevent->data_size + sizeof(EVENT_HEADER));
4578#endif
4579 }
4580
4581 /* update statistics */
4582 if (written > 0) {
4583 log_chn->statistics.events_written++;
4584 log_chn->statistics.bytes_written_uncompressed += evt_size;
4585 log_chn->statistics.bytes_written += written;
4586 log_chn->statistics.bytes_written_total += written;
4587 log_chn->statistics.bytes_written_subrun += written;
4588 }
4589
4590 if (written < 0)
4592 else
4594 }
4595#endif
4596
4598 if (actual_time - start_time > 3000)
4599 cm_msg(MINFO, "log_write", "Write operation on \'%s\' took %d ms", log_chn->path.c_str(), actual_time - start_time);
4600
4601 if (status != SS_SUCCESS && !stop_requested) {
4602 cm_msg(MTALK, "log_write", "Error writing output file, stopping run");
4603 cm_msg(MERROR, "log_write", "Cannot write \'%s\', error %d, stopping run", log_chn->path.c_str(), status);
4604 stop_the_run(0);
4605
4606 return status;
4607 }
4608
4609 /* check if event limit is reached to stop run */
4611 log_chn->settings.event_limit > 0 &&
4612 log_chn->statistics.events_written >= log_chn->settings.event_limit) {
4614
4615 cm_msg(MTALK, "log_write", "stopping run after having received %1.0lf events",
4616 log_chn->settings.event_limit);
4617
4618 status = stop_the_run(1);
4619 return status;
4620 }
4621
4622 /* check if duration is reached for subrun */
4623 duration = 0;
4624 size = sizeof(duration);
4625 db_get_value(hDB, 0, "/Logger/Subrun duration", &duration, &size, TID_UINT32, TRUE);
4627 int run_number;
4628
4629 // cm_msg(MTALK, "main", "stopping subrun after %d seconds", duration);
4630
4631 size = sizeof(run_number);
4632 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
4633 assert(status == SUCCESS);
4634
4635 stop_requested = TRUE; // avoid recursive call thourgh log_odb_dump
4637 log_chn->subrun_number++;
4638 log_chn->statistics.bytes_written_subrun = 0;
4644 }
4645
4646 /* check if byte limit is reached for subrun */
4647 if (!stop_requested && log_chn->settings.subrun_byte_limit > 0 &&
4648 log_chn->statistics.bytes_written_subrun >= log_chn->settings.subrun_byte_limit) {
4649 int run_number;
4650
4651 // cm_msg(MTALK, "main", "stopping subrun after %1.0lf bytes", log_chn->settings.subrun_byte_limit);
4652
4653 size = sizeof(run_number);
4654 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
4655 assert(status == SUCCESS);
4656
4657 stop_requested = TRUE; // avoid recursive call thourgh log_odb_dump
4659 log_chn->subrun_number++;
4660 log_chn->statistics.bytes_written_subrun = 0;
4666 }
4667
4668 /* check if new subrun is requested manually */
4670 size = sizeof(next_subrun);
4671 db_get_value(hDB, 0, "/Logger/Next subrun", &next_subrun, &size, TID_BOOL, true);
4672 if (!stop_requested && next_subrun) {
4673 int run_number;
4674
4675 // cm_msg(MTALK, "main", "stopping subrun by user request");
4676
4677 size = sizeof(run_number);
4678 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
4679 assert(status == SUCCESS);
4680
4681 stop_requested = TRUE; // avoid recursive call thourgh log_odb_dump
4683 log_chn->subrun_number++;
4684 log_chn->statistics.bytes_written_subrun = 0;
4690
4692 db_set_value(hDB, 0, "/Logger/Next subrun", &next_subrun, sizeof(next_subrun), 1, TID_BOOL);
4693 }
4694
4695 /* check if byte limit is reached to stop run */
4697 log_chn->settings.byte_limit > 0 &&
4698 log_chn->statistics.bytes_written >= log_chn->settings.byte_limit) {
4700
4701 cm_msg(MTALK, "log_write", "stopping run after having received %1.0lf mega bytes",
4702 log_chn->statistics.bytes_written / 1E6);
4703
4704 status = stop_the_run(1);
4705
4706 return status;
4707 }
4708
4709 /* stop run if less than 10MB free disk space */
4711 if (log_chn->type == LOG_TYPE_DISK && log_chn->do_disk_level && actual_time - log_chn->last_checked > DISK_CHECK_INTERVAL_MILLISEC) {
4712 log_chn->last_checked = actual_time;
4713
4714 const double MiB = 1024*1024;
4715 double disk_size = 0;
4716 double disk_free = 0;
4717
4719
4720 double limit = 10E6;
4721
4722 if (disk_size > 100E9) {
4723 limit = 1000E6;
4724 } else if (disk_size > 10E9) {
4725 limit = 100E6;
4726 }
4727
4728 if (disk_free < limit) {
4730 cm_msg(MTALK, "log_write", "disk nearly full, stopping the run");
4731 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);
4732
4733 status = stop_the_run(0);
4734 }
4735 }
4736
4737 return status;
4738}
4739
4740/*---- open_history ------------------------------------------------*/
4741
4742void log_history(HNDLE hDB, HNDLE hKey, void *info);
4743
4744#include "history.h"
4745
4746static std::vector<MidasHistoryInterface*> mh;
4747static std::vector<std::string> history_events;
4748
4749static 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)
4750{
4751 int status;
4752 int size, i;
4753 int index = *indexp;
4754
4755#if 0
4756 {
4757 /* print the tags */
4758 printf("add_event: event %d, name \"%s\", ntags %d\n", event_id, event_name, ntags);
4759 for (i=0; i<ntags; i++) {
4760 printf("tag %d: name \"%s\", type %d, n_data %d\n", i, tags[i].name, tags[i].type, tags[i].n_data);
4761 }
4762 }
4763#endif
4764
4765 /* check for duplicate event id's */
4766 for (i=0; i<index; i++) {
4767 if (strcmp(hist_log[i].event_name, event_name) == 0) {
4768 cm_msg(MERROR, "add_event", "Duplicate event name \'%s\' with event id %d", event_name, event_id);
4769 return 0;
4770 }
4771 }
4772
4773 while (index >= hist_log_size) {
4774 int new_size = 2*hist_log_size;
4775
4776 if (hist_log_size == 0)
4777 new_size = 10;
4778
4780 assert(hist_log!=NULL);
4781
4783 }
4784
4785 if (index >= hist_log_max)
4786 hist_log_max = index + 1;
4787
4788 /* check for invalid history tags */
4789 for (i=0; i<ntags; i++) {
4790 if (tags[i].type == TID_STRING) {
4791 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);
4792 return 0;
4793 }
4794 if (tags[i].type == TID_INT64) {
4795 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);
4796 return 0;
4797 }
4798 if (tags[i].type == TID_UINT64) {
4799 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);
4800 return 0;
4801 }
4802 if (rpc_tid_size(tags[i].type) == 0) {
4803 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);
4804 return 0;
4805 }
4806 }
4807
4808 /* check for trailing spaces in tag names */
4809 for (i=0; i<ntags; i++) {
4810 if (isspace(tags[i].name[strlen(tags[i].name)-1])) {
4811 cm_msg(MERROR, "add_event", "Invalid tag %d \'%s\' in event %d \'%s\': has trailing spaces", i, tags[i].name, event_id, event_name);
4812 return 0;
4813 }
4814 }
4815
4816 for (unsigned i=0; i<mh.size(); i++) {
4817 status = mh[i]->hs_define_event(event_name, timestamp, ntags, tags);
4818 if (status != HS_SUCCESS) {
4819 cm_msg(MERROR, "add_event", "Cannot define event \"%s\", hs_define_event() status %d", event_name, status);
4820 return 0;
4821 }
4822 }
4823
4824 status = db_get_record_size(hDB, hKey, 0, &size);
4825
4826 if (status != DB_SUCCESS) {
4827 cm_msg(MERROR, "add_event", "Cannot define event \"%s\", db_get_record_size() status %d", event_name, status);
4828 return 0;
4829 }
4830
4831 /* setup hist_log structure for this event */
4832 mstrlcpy(hist_log[index].event_name, event_name, sizeof(hist_log[index].event_name));
4835 hist_log[index].buffer_size = size;
4836 hist_log[index].buffer = (char*)malloc(size);
4837 hist_log[index].min_period = min_period;
4838 hist_log[index].last_log = 0;
4839
4840 if (hist_log[index].buffer == NULL) {
4841 cm_msg(MERROR, "add_event", "Cannot allocate data buffer for event \"%s\" size %d", event_name, size);
4842 return 0;
4843 }
4844
4845 /* open hot link to variables */
4846 if (hotlink) {
4848 if (status != DB_SUCCESS) {
4849 cm_msg(MERROR, "add_event",
4850 "Cannot hotlink event %d \"%s\" for history logging, db_open_record() status %d",
4851 event_id, event_name, status);
4852 return status;
4853 }
4854 }
4855
4856 history_events.push_back(event_name);
4857
4858 if (verbose)
4859 printf("Created event %d for equipment \"%s\", %d tags, size %d\n", event_id, event_name, ntags, size);
4860
4861 *indexp = index+1;
4862
4863 return SUCCESS;
4864}
4865
4867{
4868 INT size, index, i_tag, status, i, j, li, max_event_id;
4869 int ieq;
4870 INT n_var, n_tags, n_names = 0;
4873 TAG *tag = NULL;
4875 WORD eq_id;
4878
4879 time_t now = time(NULL);
4880
4881 double tstart = ss_time_sec();
4882
4883 // delete old history channels
4884
4885 for (unsigned i=0; i<mh.size(); i++)
4886 delete mh[i];
4887 mh.clear();
4888
4889 history_events.clear();
4890
4891 // create and initialize the history channels tree
4892
4893 status = db_find_key(hDB, 0, "/Logger/History", &hKeyHist);
4894
4895 if (status == DB_NO_KEY) {
4896 int active;
4897 std::string type;
4898 int debug;
4899
4900 // create entry for FILE history
4901
4902 type = "FILE";
4903 status = db_get_value_string(hDB, 0, "/Logger/History/FILE/Type", 0, &type, TRUE);
4904 assert(status==DB_SUCCESS);
4905
4906 active = 1;
4907 size = sizeof(active);
4908 status = db_get_value(hDB, 0, "/Logger/History/FILE/Active", &active, &size, TID_BOOL, TRUE);
4909 assert(status==DB_SUCCESS);
4910
4911 debug = 0;
4912 size = sizeof(debug);
4913 status = db_get_value(hDB, 0, "/Logger/History/FILE/Debug", &debug, &size, TID_INT32, TRUE);
4914 assert(status==DB_SUCCESS);
4915
4916 int per_variable = 1;
4917 size = sizeof(per_variable);
4918 status = db_get_value(hDB, 0, "/Logger/History/FILE/PerVariableHistory", &per_variable, &size, TID_INT32, TRUE);
4919 assert(status==DB_SUCCESS);
4920
4921 // create entry for the MIDAS history
4922
4923 type = "MIDAS";
4924 status = db_get_value_string(hDB, 0, "/Logger/History/MIDAS/Type", 0, &type, TRUE);
4925 assert(status==DB_SUCCESS);
4926
4927 active = 0;
4928 size = sizeof(active);
4929 status = db_get_value(hDB, 0, "/Logger/History/MIDAS/Active", &active, &size, TID_BOOL, TRUE);
4930 assert(status==DB_SUCCESS);
4931
4932 debug = 0;
4933 size = sizeof(debug);
4934 status = db_get_value(hDB, 0, "/Logger/History/MIDAS/Debug", &debug, &size, TID_INT32, TRUE);
4935 assert(status==DB_SUCCESS);
4936
4937 // create entry for ODBC (MySQL) history
4938
4939 type = "ODBC";
4940 status = db_get_value_string(hDB, 0, "/Logger/History/ODBC/Type", 0, &type, TRUE);
4941 assert(status==DB_SUCCESS);
4942
4943 active = 0;
4944 size = sizeof(active);
4945 status = db_get_value(hDB, 0, "/Logger/History/ODBC/Active", &active, &size, TID_BOOL, TRUE);
4946 assert(status==DB_SUCCESS);
4947
4948 debug = 0;
4949 size = sizeof(debug);
4950 status = db_get_value(hDB, 0, "/Logger/History/ODBC/Debug", &debug, &size, TID_INT32, TRUE);
4951 assert(status==DB_SUCCESS);
4952
4953 // create entry for SQLITE history
4954
4955 type = "SQLITE";
4956 status = db_get_value_string(hDB, 0, "/Logger/History/SQLITE/Type", 0, &type, TRUE);
4957 assert(status==DB_SUCCESS);
4958
4959 active = 0;
4960 size = sizeof(active);
4961 status = db_get_value(hDB, 0, "/Logger/History/SQLITE/Active", &active, &size, TID_BOOL, TRUE);
4962 assert(status==DB_SUCCESS);
4963
4964 debug = 0;
4965 size = sizeof(debug);
4966 status = db_get_value(hDB, 0, "/Logger/History/SQLITE/Debug", &debug, &size, TID_INT32, TRUE);
4967 assert(status==DB_SUCCESS);
4968
4969 // create entry for MYSQL history writer
4970
4971 type = "MYSQL";
4972 status = db_get_value_string(hDB, 0, "/Logger/History/MYSQL/Type", 0, &type, TRUE);
4973 assert(status==DB_SUCCESS);
4974
4975 active = 0;
4976 size = sizeof(active);
4977 status = db_get_value(hDB, 0, "/Logger/History/MYSQL/Active", &active, &size, TID_BOOL, TRUE);
4978 assert(status==DB_SUCCESS);
4979
4980 debug = 0;
4981 size = sizeof(debug);
4982 status = db_get_value(hDB, 0, "/Logger/History/MYSQL/Debug", &debug, &size, TID_INT32, TRUE);
4983 assert(status==DB_SUCCESS);
4984
4985 // create entry for PGSQL history writer
4986
4987 type = "PGSQL";
4988 status = db_get_value_string(hDB, 0, "/Logger/History/PGSQL/Type", 0, &type, TRUE);
4989 assert(status==DB_SUCCESS);
4990
4991 active = 0;
4992 size = sizeof(active);
4993 status = db_get_value(hDB, 0, "/Logger/History/PGSQL/Active", &active, &size, TID_BOOL, TRUE);
4994 assert(status==DB_SUCCESS);
4995
4996 debug = 0;
4997 size = sizeof(debug);
4998 status = db_get_value(hDB, 0, "/Logger/History/PGSQL/Debug", &debug, &size, TID_INT32, TRUE);
4999 assert(status==DB_SUCCESS);
5000
5001 // get newly created /Logger/History
5002
5003 status = db_find_key(hDB, 0, "/Logger/History", &hKeyHist);
5004 }
5005
5006 if (status != DB_SUCCESS) {
5007 cm_msg(MERROR, "open_history", "Something is wrong with /Logger/History, db_find_key() status %d", status);
5008 return status;
5009 }
5010
5011 // loop over history channels
5012
5013 for (int ichan = 0; ; ichan++) {
5015 if (status != DB_SUCCESS)
5016 break;
5017
5019
5021
5022 if (status==HS_SUCCESS && hi) {
5023 if (strcasecmp(hi->type, "MIDAS")==0) {
5024 i = 0;
5025 size = sizeof(i);
5026 status = db_get_value(hDB, hKey, "PerVariableHistory", &i, &size, TID_INT32, TRUE);
5027 assert(status==DB_SUCCESS);
5028
5029 if (i)
5031 } else if (strcasecmp(hi->type, "FILE")==0) {
5032 i = 0;
5033 size = sizeof(i);
5034 status = db_get_value(hDB, hKey, "PerVariableHistory", &i, &size, TID_INT32, TRUE);
5035 assert(status==DB_SUCCESS);
5036
5037 if (i)
5039 } else if (strcasecmp(hi->type, "ODBC")==0) {
5041 } else if (strcasecmp(hi->type, "SQLITE")==0) {
5043 } else if (strcasecmp(hi->type, "MYSQL")==0) {
5045 } else if (strcasecmp(hi->type, "PGSQL")==0) {
5047 }
5048
5049 if (verbose)
5050 cm_msg(MINFO, "open_history", "Writing history to channel \'%s\' type \'%s\'", hi->name, hi->type);
5051
5052 mh.push_back(hi);
5053 }
5054 }
5055
5056 // prepare history channels
5057
5058 for (unsigned i=0; i<mh.size(); i++) {
5059 status = mh[i]->hs_clear_cache();
5060 assert(status == HS_SUCCESS);
5061 }
5062
5063 // check global per-variable history settings
5064
5065 i = 0;
5066 size = sizeof(i);
5067 status = db_get_value(hDB, 0, "/History/PerVariableHistory", &i, &size, TID_INT32, FALSE);
5068 if (status==DB_SUCCESS) {
5069 cm_msg(MERROR, "open_history", "mlogger ODB setting /History/PerVariableHistory is obsolete, please delete it. Use /Logger/History/MIDAS/PerVariableHistory instead");
5070 if (i)
5072 }
5073
5075 static int previous = -1;
5078 cm_msg(MINFO, "open_history", "Per-variable history is enabled");
5079 else
5080 ;//cm_msg(MINFO, "open_history", "Per-variable history is disabled");
5081 }
5083 }
5084
5085 // setup history links
5086
5087 if (db_find_key(hDB, 0, "/History/Links", &hKeyRoot) != DB_SUCCESS ||
5088 db_find_key(hDB, 0, "/History/Links/System", &hKeyRoot) != DB_SUCCESS) {
5089 /* create default history keys */
5090 db_create_key(hDB, 0, "/History/Links", TID_KEY);
5091
5092 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/Events per sec.", &hKeyEq) == DB_SUCCESS)
5093 db_create_link(hDB, 0, "/History/Links/System/Trigger per sec.",
5094 "/Equipment/Trigger/Statistics/Events per sec.");
5095
5096 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/kBytes per sec.", &hKeyEq) == DB_SUCCESS)
5097 db_create_link(hDB, 0, "/History/Links/System/Trigger kB per sec.",
5098 "/Equipment/Trigger/Statistics/kBytes per sec.");
5099 }
5100
5101 /*---- define equipment events as history ------------------------*/
5102
5103 max_event_id = 0;
5104
5105 status = db_find_key(hDB, 0, "/Equipment", &hKeyRoot);
5106 if (status == DB_NO_KEY) {
5107 cm_msg(MINFO, "open_history", "Cannot find /Equipment entry in database, history system is inactive");
5108 return CM_SUCCESS;
5109 }
5110
5111 if (status != DB_SUCCESS) {
5112 cm_msg(MERROR, "open_history", "Cannot find /Equipment entry in database, db_find_key() status %d", status);
5113 return status;
5114 }
5115
5116 /* loop over equipment */
5117 index = 0;
5118 for (ieq = 0; ; ieq++) {
5120 if (status != DB_SUCCESS)
5121 break;
5122
5123 int32_t min_period = 0; // in seconds
5124
5125 /* retrieve min period for history logging */
5126 size = sizeof(min_period);
5127 db_get_value(hDB, hKeyEq, "Common/Log history", &min_period, &size, TID_INT32, TRUE);
5128
5129 /* define history tags only if log history flag is on */
5130 if (min_period > 0) {
5132
5133 /* get equipment name */
5135 strcpy(eq_name, key.name);
5136
5137 if (strchr(eq_name, ':'))
5138 cm_msg(MERROR, "open_history", "Equipment name \'%s\' contains characters \':\', this may break the history system", eq_name);
5139
5140 status = db_find_key(hDB, hKeyEq, "Variables", &hKeyVar);
5141 if (status != DB_SUCCESS) {
5142 cm_msg(MERROR, "open_history", "Cannot find /Equipment/%s/Variables entry in database", eq_name);
5143 return 0;
5144 }
5145
5146 size = sizeof(eq_id);
5147 status = db_get_value(hDB, hKeyEq, "Common/Event ID", &eq_id, &size, TID_UINT16, TRUE);
5148 assert(status == DB_SUCCESS);
5149
5150 size = sizeof(int);
5151 status = db_get_value(hDB, hKeyEq, "Settings/PerVariableHistory", &per_variable_history, &size, TID_INT32, FALSE);
5152 assert(status == DB_SUCCESS || status == DB_NO_KEY);
5153
5154 if (verbose)
5155 printf
5156 ("\n==================== Equipment \"%s\", ID %d =======================\n",
5157 eq_name, eq_id);
5158
5159 /* count keys in variables tree */
5160 for (n_var = 0, n_tags = 0;; n_var++) {
5161 status = db_enum_key(hDB, hKeyVar, n_var, &hKey);
5163 break;
5164 db_get_key(hDB, hKey, &key);
5165 if (key.type != TID_KEY) {
5167 }
5168 else {
5169 int ii;
5170 for (ii=0;; ii++) {
5171 KEY vvarkey;
5172 HNDLE hhKey;
5173
5176 break;
5177
5178 /* get variable key */
5180
5181 n_tags += vvarkey.num_values;
5182 }
5183 }
5184 }
5185
5186 if (n_var == 0)
5187 cm_msg(MINFO, "open_history", "Equipment \"%s\" history is enabled, but there are no Variables in ODB", eq_name);
5188
5189 /* create tag array */
5190 tag = (TAG *) calloc(sizeof(TAG), n_tags);
5191
5192 i_tag = 0;
5193 for (i=0; ; i++) {
5194 status = db_enum_key(hDB, hKeyVar, i, &hKey);
5196 break;
5197
5198 /* get variable key */
5200
5201
5202 HNDLE hKeyNames = 0;
5203 BOOL single_names = false;
5204
5205 /* look for names */
5206
5207 if (!hKeyNames) {
5208 sprintf(str, "Settings/Names %s", varkey.name);
5210 if (hKeyNames) {
5211 if (verbose)
5212 printf("Using \"/Equipment/%s/Settings/Names %s\" for variable \"%s\"\n", eq_name, varkey.name, varkey.name);
5213
5214 /* define tags from names list */
5217 }
5218 }
5219
5220 if (!hKeyNames) {
5221 db_find_key(hDB, hKeyEq, "Settings/Names", &hKeyNames);
5222 single_names = (hKeyNames > 0);
5223
5224 if (hKeyNames) {
5225 if (verbose)
5226 printf("Using \"/Equipment/%s/Settings/Names\" for variable \"%s\"\n", eq_name, varkey.name);
5227
5228 /* define tags from names list */
5231 }
5232 }
5233
5234 if (hKeyNames && n_names < varkey.num_values) {
5235 cm_msg(MERROR, "open_history",
5236 "Array size mismatch: \"/Equipment/%s/Settings/%s\" has %d entries while \"/Equipment/%s/Variables/%s\" has %d entries",
5238 eq_name, varkey.name, varkey.num_values);
5239 free(tag);
5240 return 0;
5241 }
5242
5243 if (hKeyNames) {
5244 /* loop over array elements */
5245 for (j = 0; j < varkey.num_values; j++) {
5246 char xname[256];
5247
5248 tag[i_tag].name[0] = 0;
5249
5250 /* get name #j */
5251 size = sizeof(xname);
5253 if (status == DB_SUCCESS)
5254 mstrlcpy(tag[i_tag].name, xname, sizeof(tag[i_tag].name));
5255
5256 if (strlen(tag[i_tag].name) < 1) {
5257 char buf[256];
5258 sprintf(buf, "%d", j);
5260 mstrlcat(tag[i_tag].name, "_", NAME_LENGTH);
5261 mstrlcat(tag[i_tag].name, buf, NAME_LENGTH);
5262 }
5263
5264 /* append variable key name for single name array */
5265 if (single_names) {
5266 if (strlen(tag[i_tag].name) + 1 + strlen(varkey.name) >= NAME_LENGTH) {
5267 cm_msg(MERROR, "open_history",
5268 "Name for history entry \"%s %s\" too long", tag[i_tag].name, varkey.name);
5269 free(tag);
5270 return 0;
5271 }
5272 mstrlcat(tag[i_tag].name, " ", NAME_LENGTH);
5274 }
5275
5276 tag[i_tag].type = varkey.type;
5277 tag[i_tag].n_data = 1;
5278
5279 if (verbose)
5280 printf("Defined tag %d, name \"%s\", type %d, num_values %d\n",
5281 i_tag, tag[i_tag].name, tag[i_tag].type, tag[i_tag].n_data);
5282
5283 i_tag++;
5284 }
5285 } else if (varkey.type == TID_KEY) {
5286 int ii;
5287 for (ii=0;; ii++) {
5288 KEY vvarkey;
5289 HNDLE hhKey;
5290
5293 break;
5294
5295 /* get variable key */
5297
5299 mstrlcat(tag[i_tag].name, "_", NAME_LENGTH);
5301 tag[i_tag].type = vvarkey.type;
5302 tag[i_tag].n_data = vvarkey.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 } else {
5312 tag[i_tag].type = varkey.type;
5313 tag[i_tag].n_data = varkey.num_values;
5314
5315 if (verbose)
5316 printf("Defined tag %d, name \"%s\", type %d, num_values %d\n", i_tag, tag[i_tag].name,
5317 tag[i_tag].type, tag[i_tag].n_data);
5318
5319 i_tag++;
5320 }
5321
5322 if (per_variable_history && i_tag>0) {
5323 WORD event_id = 0;
5324 char event_name[NAME_LENGTH];
5325
5326 mstrlcpy(event_name, eq_name, NAME_LENGTH);
5327 mstrlcat(event_name, "/", NAME_LENGTH);
5328 mstrlcat(event_name, varkey.name, NAME_LENGTH);
5329
5330 assert(i_tag <= n_tags);
5331
5332 status = add_event(&index, now, event_id, event_name, hKey, i_tag, tag, min_period, 1);
5333 if (status != DB_SUCCESS)
5334 return status;
5335
5336 i_tag = 0;
5337 } /* if per-variable history */
5338
5339 } /* loop over variables */
5340
5341 if (!per_variable_history && i_tag>0) {
5342 assert(i_tag <= n_tags);
5343
5344 status = add_event(&index, now, eq_id, eq_name, hKeyVar, i_tag, tag, min_period, 1);
5345 if (status != DB_SUCCESS)
5346 return status;
5347
5348 }
5349
5350 if (tag) {
5351 free(tag);
5352 tag = NULL;
5353 }
5354
5355 /* remember maximum event id for later use with system events */
5356 if (eq_id > max_event_id)
5358 }
5359 } /* loop over equipments */
5360
5361 /*---- define linked trees --------------------------------------*/
5362
5363 /* round up event id */
5364 max_event_id = ((int) ((max_event_id + 1) / 10) + 1) * 10;
5365
5366 status = db_find_key(hDB, 0, "/History/Links", &hKeyRoot);
5367 if (status == DB_SUCCESS) {
5368 for (li = 0;; li++) {
5371 break;
5372
5374 strcpy(hist_name, histkey.name);
5376
5378 if (key.type != TID_KEY) {
5379 cm_msg(MERROR, "open_history", "Only subkeys allows in /History/Links, key \"%s\"", key.name);
5380 continue;
5381 }
5382
5383 if (verbose)
5384 printf("\n==================== History link \"%s\", ID %d =======================\n",
5386
5387 /* count subkeys in link */
5388 for (i = n_var = 0;; i++) {
5391 break;
5392
5393 if (status == DB_SUCCESS && db_get_key(hDB, hKey, &key) == DB_SUCCESS) {
5394 if (key.type != TID_KEY)
5395 n_var++;
5396 } else {
5398 db_get_key(hDB, hKey, &key);
5399 cm_msg(MERROR, "open_history",
5400 "History link /History/Links/%s/%s is invalid", hist_name, key.name);
5401 return 0;
5402 }
5403 }
5404
5405 if (n_var == 0)
5406 cm_msg(MERROR, "open_history", "History event %s has no variables in ODB", hist_name);
5407 else {
5408 /* create tag array */
5409 tag = (TAG *) calloc(sizeof(TAG), n_var);
5410
5411 assert(tag != NULL);
5412
5413 for (i = 0, size = 0, n_var = 0;; i++) {
5416 break;
5417
5418 /* get link key */
5420
5421 if (linkkey.type == TID_KEY)
5422 continue;
5423
5424 /* get link target */
5426 if (db_get_key(hDB, hVarKey, &varkey) == DB_SUCCESS) {
5427 /* hot-link individual values */
5428 if (histkey.type == TID_KEY) {
5429 db_close_record(hDB, hVarKey); // close previously opened record
5431 (void *) (POINTER_T) index);
5432 }
5433
5434 strcpy(tag[n_var].name, linkkey.name);
5435 tag[n_var].type = varkey.type;
5436 tag[n_var].n_data = varkey.num_values;
5437
5438 if (verbose)
5439 printf("Defined tag \"%s\", type %d, num_values %d\n",
5440 tag[n_var].name, tag[n_var].type, tag[n_var].n_data);
5441
5442 size += varkey.total_size;
5443 n_var++;
5444 }
5445 }
5446
5447 /* hot-link whole subtree */
5448 if (histkey.type == TID_LINK) {
5449 db_close_record(hDB, hHistKey); // close previously opened record
5451 }
5452
5453 status = add_event(&index, now, max_event_id, hist_name, hHistKey, n_var, tag, 0, 0);
5454 if (status != DB_SUCCESS)
5455 return status;
5456
5457 free(tag);
5458 tag = NULL;
5459
5460 max_event_id++;
5461 }
5462 }
5463 }
5464
5465 /*---- define run start/stop event ------------------------------*/
5466
5467 tag = (TAG *) calloc(sizeof(TAG), 2);
5468
5469 assert(tag != NULL);
5470
5471 strcpy(tag[0].name, "State");
5472 tag[0].type = TID_UINT32;
5473 tag[0].n_data = 1;
5474
5475 strcpy(tag[1].name, "Run number");
5476 tag[1].type = TID_UINT32;
5477 tag[1].n_data = 1;
5478
5479 const char* event_name = "Run transitions";
5480
5481 for (unsigned i=0; i<mh.size(); i++) {
5482 status = mh[i]->hs_define_event(event_name, now, 2, tag);
5483 if (status != HS_SUCCESS) {
5484 cm_msg(MERROR, "add_event", "Cannot define event \"%s\", hs_define_event() status %d", event_name, status);
5485 return 0;
5486 }
5487 }
5488
5489 history_events.push_back(event_name);
5490
5491 free(tag);
5492 tag = NULL;
5493
5494 /* outcommented not to produce a log entry on every run
5495 cm_msg(MINFO, "open_history", "Configured history with %d events", count_events);
5496 */
5497
5499 if (status != HS_SUCCESS)
5500 return status;
5501
5502 double tend = ss_time_sec();
5503 double telapsed = tend - tstart;
5504 if (telapsed > 10.0) {
5505 cm_msg(MERROR, "open_history", "open_history() took %.3f seconds", telapsed);
5506 }
5507
5508 return CM_SUCCESS;
5509}
5510
5511/*---- periodically flush history buffers---------------------------*/
5512
5514
5516{
5517 time_t flush_period_sec = 1; // flush once every 1 seconds
5518
5520
5521 if (verbose)
5522 printf("flush history buffers!\n");
5523
5524 for (unsigned h = 0; h < mh.size(); h++)
5525 mh[h]->hs_flush_buffers();
5526
5528 }
5529}
5530
5531/*---- close_history -----------------------------------------------*/
5532
5534{
5535 INT status;
5537
5538 /* close system history */
5539 status = db_find_key(hDB, 0, "/History/Links", &hKeyRoot);
5540 if (status == DB_SUCCESS) {
5541 for (int i = 0;; i++) {
5542 HNDLE hKey;
5545 break;
5547 }
5548 }
5549
5550 /* close event history */
5551 for (int i = 0; i < hist_log_max; i++)
5552 if (hist_log[i].hKeyVar) {
5553 db_close_record(hDB, hist_log[i].hKeyVar);
5554 hist_log[i].hKeyVar = 0;
5555 if (hist_log[i].buffer)
5556 free(hist_log[i].buffer);
5557 hist_log[i].buffer = NULL;
5558 }
5559
5560 for (unsigned h=0; h<mh.size(); h++) {
5561 mh[h]->hs_disconnect();
5562 delete mh[h];
5563 mh[h] = NULL;
5564 }
5565
5566 mh.clear();
5567}
5568
5569/*---- log_history -------------------------------------------------*/
5570
5572{
5573 INT i, size, status;
5575
5576 time_t now = time(NULL);
5577
5578 for (i = 0; i < hist_log_max; i++)
5579 if (hist_log[i].hKeyVar == hKey)
5580 break;
5581
5582 if (i == hist_log_max)
5583 return;
5584
5585 /* check if over minimum period */
5586 if (now - hist_log[i].last_log < hist_log[i].min_period)
5587 return;
5588
5589 /* check if event size has changed */
5590 db_get_record_size(hDB, hKey, 0, &size);
5591 if (size != hist_log[i].buffer_size) {
5592 close_history();
5593 status = open_history();
5594 if (status != CM_SUCCESS) {
5595 printf("Error in history system, aborting.\n");
5597 exit(1);
5598 }
5599 return;
5600 }
5601
5603
5604 if (verbose)
5605 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);
5606
5607 for (unsigned h=0; h<mh.size(); h++) {
5608 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);
5609 if (verbose)
5610 if (status != HS_SUCCESS)
5611 printf("write_history_event: \'%s\', channel \'%s\' hs_write_event() status %d\n", hist_log[i].event_name, mh[h]->name, status);
5612 }
5613
5615
5617 if (end_millitime - start_millitime > 3000)
5618 cm_msg(MINFO, "log_history", "History write operation took %d ms", end_millitime - start_millitime);
5619}
5620
5621/*------------------------------------------------------------------*/
5622
5624{
5625 INT size, total_size, status, index;
5626 DWORD i;
5627 KEY key;
5629
5630 index = (INT) (POINTER_T) info;
5631
5632 time_t now = time(NULL);
5633
5634 /* check if over period */
5635 if (now - hist_log[index].last_log < hist_log[index].min_period)
5636 return;
5637
5638 for (i = 0, total_size = 0;; i++) {
5639 status = db_enum_key(hDB, hist_log[index].hKeyVar, i, &hKey);
5641 break;
5642
5643 db_get_key(hDB, hKey, &key);
5644 size = key.total_size;
5645 db_get_data(hDB, hKey, (char *) hist_log[index].buffer + total_size, &size, key.type);
5646 total_size += size;
5647 }
5648
5649 if (i != hist_log[index].n_var) {
5650 close_history();
5651 status = open_history();
5652 if (status != CM_SUCCESS) {
5653 printf("Error in history system, aborting.\n");
5655 exit(1);
5656 }
5657 return;
5658 }
5659
5661
5662 if (verbose)
5663 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);
5664
5665 for (unsigned h=0; h<mh.size(); h++)
5666 mh[h]->hs_write_event(hist_log[index].event_name, hist_log[index].last_log, total_size, hist_log[index].buffer);
5667
5669
5671 if (end_millitime - start_millitime > 3000)
5672 cm_msg(MINFO, "log_system_history", "History write operation took %d ms", end_millitime - start_millitime);
5673}
5674
5675/*------------------------------------------------------------------*/
5676
5678{
5679 INT size, status, run_number = 0;
5680 std::string path;
5681 std::string data_dir;
5683
5684 chn_settings = &log_chn->settings;
5685 size = sizeof(run_number);
5686 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
5687 assert(status == SUCCESS);
5688
5689 std::string filename = chn_settings->filename;
5690 /* Check if data stream are throw pipe command */
5691 log_chn->pipe_command = "";
5692 bool ispipe = false;
5693 if (log_chn->type == LOG_TYPE_DISK) {
5694 char* p = strchr(chn_settings->filename, '>');
5695 if (chn_settings->filename[0] == '|' && p) {
5696 /* skip second arrow in ">>" */
5697 while (*p == '>')
5698 p++;
5699 /* skip spaces after '>' */
5700 while (*p == ' ')
5701 p++;
5702 filename = p;
5703 ispipe = true;
5704 // pipe_command is contents of chn_settings->filename without the leading "|" and trailing ">"
5705 log_chn->pipe_command = "";
5706 const char*s = chn_settings->filename;
5707 /* skip leading pipe */
5708 if (*s == '|')
5709 s++;
5710 /* skip spaces */
5711 while (*s == ' ')
5712 s++;
5713 /* copy up to ">" */
5714 while (*s != '>') {
5715 log_chn->pipe_command += *s++;
5716 }
5717 /* copy as many ">" as they put there */
5718 while (*s == '>') {
5719 log_chn->pipe_command += *s++;
5720 }
5721 }
5722 }
5723
5724 std::string str;
5725
5726 /* if disk, precede filename with directory if not already there */
5727 if (log_chn->type == LOG_TYPE_DISK && filename[0] != DIR_SEPARATOR) {
5728 db_get_value_string(hDB, 0, "/Logger/Data Dir", 0, &data_dir, TRUE);
5729 if (data_dir.empty()) {
5731 } else {
5732 if (data_dir.back() != DIR_SEPARATOR)
5734 }
5735 str = data_dir;
5736
5737 /* append subdirectory if requested */
5738 if (chn_settings->subdir_format[0]) {
5739 ss_tzset(); // required for localtime_r()
5740 time_t now;
5741 time(&now);
5742 struct tm tms;
5743 localtime_r(&now, &tms);
5744
5745 char dir[256];
5746 strftime(dir, sizeof(dir), chn_settings->subdir_format, &tms);
5747 str += dir;
5749 }
5750
5751 /* create directory if needed */
5752#ifdef OS_WINNT
5753 status = mkdir(str.c_str());
5754#else
5755 status = mkdir(str.c_str(), 0755);
5756#endif
5757#if defined(EEXIST)
5758 if (status == -1 && errno != EEXIST)
5759 cm_msg(MERROR, "log_generate_file_name", "Cannot create subdirectory \"%s\", mkdir() errno %d (%s)", str.c_str(), errno, strerror(errno));
5760#endif
5761
5762 str += filename;
5763 } else {
5764 str = filename;
5765 }
5766
5767 /* check if two "%" are present in filename */
5768 if (strchr(str.c_str(), '%')) {
5769 if (strchr(strchr(str.c_str(), '%')+1, '%')) {
5770 /* substitude first "%d" by current run number, second "%d" by subrun number */
5771 path = msprintf(str.c_str(), run_number, log_chn->subrun_number);
5772 } else {
5773 /* substitue "%d" by current run number */
5774 path = msprintf(str.c_str(), run_number);
5775 }
5776 } else {
5777 path = str;
5778 }
5779
5780 /* add required file extension */
5781 if (log_chn->writer) {
5782 path += log_chn->writer->wr_get_file_ext();
5783 }
5784
5785 log_chn->path = path;
5786
5787 /* write back current file name to ODB */
5788 std::string tmpstr;
5789 if (strncmp(path.c_str(), data_dir.c_str(), data_dir.length()) == 0)
5790 tmpstr = path.c_str() + data_dir.length();
5791 else
5792 tmpstr = path;
5793 char cstr[256];
5794 mstrlcpy(cstr, tmpstr.c_str(), sizeof(cstr));
5795 db_set_value(hDB, log_chn->settings_hkey, "Current filename", cstr, 256, 1, TID_STRING);
5796
5797 /* construct full pipe command */
5798 if (ispipe) {
5799 /* check if %d must be substitude by current run number in pipe command options */
5800 if (strchr(log_chn->pipe_command.c_str(), '%')) {
5801 std::string str = log_chn->pipe_command;
5802 if (strchr(strchr(str.c_str(), '%')+1, '%')) {
5803 /* substitude first "%d" by current run number, second "%d" by subrun number */
5804 log_chn->pipe_command = msprintf(str.c_str(), run_number, log_chn->subrun_number);
5805 } else {
5806 /* substitue "%d" by current run number */
5807 log_chn->pipe_command = msprintf(str.c_str(), run_number);
5808 }
5809 } else {
5810 }
5811 /* add a space */
5812 if (log_chn->pipe_command.back() != ' ')
5813 log_chn->pipe_command += " ";
5814 /* add generated filename to pipe command */
5815 log_chn->pipe_command += path;
5816 //printf("pipe command [%s]\n", log_chn->pipe_command.c_str());
5817 }
5818
5819 return CM_SUCCESS;
5820}
5821
5822/*------------------------------------------------------------------*/
5823
5824/********************************************************************\
5825
5826 transition callbacks
5827
5828\********************************************************************/
5829
5830/*------------------------------------------------------------------*/
5831
5833{
5835
5836 for (unsigned i = 0; i < log_channels.size(); i++) {
5838 if (chn->handle || chn->ftp_con|| chn->pfile) {
5839 /* generate MTALK message */
5840#ifndef FAL_MAIN
5841 /* wait until buffer is empty */
5842 if (chn->buffer_handle) {
5843#ifdef DELAYED_STOP
5844 DWORD start_time = ss_millitime();
5845 do {
5846 cm_yield(100);
5847 } while (ss_millitime() - start_time < DELAYED_STOP);
5848#else
5849 INT n_bytes;
5850 do {
5851 bm_get_buffer_level(chn->buffer_handle, &n_bytes);
5852 if (n_bytes > 0)
5853 cm_yield(100);
5854 } while (n_bytes > 0);
5855#endif
5856 }
5857#endif /* FAL_MAIN */
5858
5859 /* close logging channel */
5861
5862 /* close statistics record */
5863 db_set_record(hDB, chn->stats_hkey, &chn->statistics, sizeof(CHN_STATISTICS), 0);
5864 db_close_record(hDB, chn->stats_hkey);
5865 db_unwatch(hDB, chn->settings_hkey);
5866 chn->stats_hkey = 0;
5867 chn->settings_hkey = 0;
5868 }
5869 }
5870
5871 if (p_tape_flag)
5873
5874 return SUCCESS;
5875}
5876
5878{
5879 /* close buffers */
5880 for (unsigned i = 0; i < log_channels.size(); i++) {
5882#ifndef FAL_MAIN
5883 if (chn->buffer_handle) {
5884 bm_close_buffer(chn->buffer_handle);
5885 for (unsigned j = i + 1; j < log_channels.size(); j++)
5886 if (log_channels[j]->buffer_handle == chn->buffer_handle)
5887 log_channels[j]->buffer_handle = 0;
5888 }
5889
5890 if (chn->msg_request_id)
5891 bm_delete_request(chn->msg_request_id);
5892#endif
5893
5894 delete chn;
5895 log_channels[i] = NULL;
5896 }
5897
5898 log_channels.clear();
5899
5900 return SUCCESS;
5901}
5902
5903/*------------------------------------------------------------------*/
5904
5906{
5907 DWORD eb[2];
5908 eb[0] = transition;
5909 eb[1] = run_number;
5910
5911 time_t now = time(NULL);
5912
5913 for (unsigned h=0; h<mh.size(); h++)
5914 mh[h]->hs_write_event("Run transitions", now, sizeof(eb), (const char*)eb);
5915
5916 return SUCCESS;
5917}
5918
5919/*------------------------------------------------------------------*/
5920
5922{
5923 int status;
5924 assert(info != NULL);
5926 int size = sizeof(CHN_SETTINGS);
5927 status = db_get_record1(hDB, log_chn->settings_hkey, &log_chn->settings, &size, 0, strcomb1(chn_settings_str).c_str());
5928 if (status != DB_SUCCESS) {
5929 cm_msg(MINFO, "watch_settings", "db_get_record(%s) status %d", log_chn->name.c_str(), status);
5930 return;
5931 }
5932
5933 if (verbose)
5934 printf("Channel %s settings updated\n", log_chn->name.c_str());
5935}
5936
5937/*------------------------------------------------------------------*/
5938
5940/********************************************************************\
5941
5942 Prestart:
5943
5944 Loop through channels defined in /logger/channels.
5945 Neglect channels with are not active.
5946 If "filename" contains a "%", substitute it by the
5947 current run number. Open logging channel and
5948 corresponding buffer. Place a event request
5949 into the buffer.
5950
5951\********************************************************************/
5952{
5953 INT size, status;
5956 KEY key;
5958 HNDLE hDB;
5959
5960 if (verbose)
5961 printf("tr_start: run %d\n", run_number);
5962
5963 DWORD t0 = ss_millitime();
5964
5966
5967 /* save current ODB */
5968 std::string str = "last.json";
5969 db_get_value_string(hDB, 0, "/Logger/ODB Last Dump File", 0, &str, TRUE);
5970 odb_save(str.c_str(), false);
5971
5972 DWORD t1 = ss_millitime();
5973
5975
5977 close_buffers();
5978
5979 DWORD t2 = ss_millitime();
5980
5982
5984
5985 /* read global logging flag */
5986 size = sizeof(BOOL);
5987 write_data = TRUE;
5988 db_get_value(hDB, 0, "/Logger/Write data", &write_data, &size, TID_BOOL, TRUE);
5989
5990 /* read tape message flag */
5991 size = sizeof(tape_message);
5992 db_get_value(hDB, 0, "/Logger/Tape message", &tape_message, &size, TID_BOOL, TRUE);
5993
5994 /* reset next subrun flag */
5995 status = FALSE;
5996 db_set_value(hDB, 0, "/Logger/Next subrun", &status, sizeof(status), 1, TID_BOOL);
5997
5998 /* loop over all channels */
5999 status = db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot);
6000 if (status != DB_SUCCESS) {
6001 /* if no channels are defined, define at least one */
6002 status = db_create_record(hDB, 0, "/Logger/Channels/0/", strcomb1(chn_tree_str).c_str());
6003 if (status != DB_SUCCESS) {
6004 strcpy(error, "Cannot create channel entry in database");
6005 cm_msg(MERROR, "tr_start", "%s", error);
6006 return 0;
6007 }
6008
6009 status = db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot);
6010 if (status != DB_SUCCESS) {
6011 strcpy(error, "Cannot create channel entry in database");
6012 cm_msg(MERROR, "tr_start", "%s", error);
6013 return 0;
6014 }
6015 }
6016
6017 // after close_buffers() all log channels are closed and deleted
6018 assert(log_channels.size() == 0);
6019
6020 for (unsigned index = 0; ; index++) {
6023 break;
6024
6025 /* correct channel record */
6028 if (status != DB_SUCCESS && status != DB_OPEN_RECORD) {
6029 cm_msg(MERROR, "tr_start", "Cannot create/check channel record, status %d", status);
6030 break;
6031 }
6032
6033 if (status == DB_SUCCESS || status == DB_OPEN_RECORD) {
6035
6036 log_channels.push_back(chn);
6037
6038 /* save settings key */
6039 status = db_find_key(hDB, hKeyChannel, "Settings", &chn->settings_hkey);
6040 if (status != DB_SUCCESS) {
6041 strcpy(error, "Cannot find channel settings info");
6042 cm_msg(MERROR, "tr_start", "%s", error);
6043 return 0;
6044 }
6045
6046 /* save statistics key */
6047 status = db_find_key(hDB, hKeyChannel, "Statistics", &chn->stats_hkey);
6048 if (status != DB_SUCCESS) {
6049 strcpy(error, "Cannot find channel statistics info");
6050 cm_msg(MERROR, "tr_start", "%s", error);
6051 return 0;
6052 }
6053
6054 /* clear statistics */
6055 size = sizeof(CHN_STATISTICS);
6056 db_get_record1(hDB, chn->stats_hkey, &chn->statistics, &size, 0, strcomb1(chn_statistics_str).c_str());
6057
6058 chn->statistics.events_written = 0;
6059 chn->statistics.bytes_written = 0;
6060 chn->statistics.bytes_written_uncompressed = 0;
6061 chn->statistics.bytes_written_subrun = 0;
6062
6063 db_set_record(hDB, chn->stats_hkey, &chn->statistics, size, 0);
6064
6065 /* get channel info structure */
6066 chn_settings = &chn->settings;
6067 size = sizeof(CHN_SETTINGS);
6068 status = db_get_record1(hDB, chn->settings_hkey, chn_settings, &size, 0, strcomb1(chn_settings_str).c_str());
6069 if (status != DB_SUCCESS) {
6070 strcpy(error, "Cannot read channel info");
6071 cm_msg(MERROR, "tr_start", "%s", error);
6072 return 0;
6073 }
6074
6075 chn->pre_checksum_module = select_checksum_module(hDB, chn->settings_hkey, "data checksum");
6076 chn->post_checksum_module = select_checksum_module(hDB, chn->settings_hkey, "file checksum");
6077 chn->compression_module = select_compression_module(hDB, chn->settings_hkey, "compress");
6078 chn->output_module = select_output_module(hDB, chn->settings_hkey, "output");
6079
6080 //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);
6081
6082 /* check if active */
6083 if (!chn_settings->active || !write_data)
6084 continue;
6085
6086#ifdef OBSOLETE
6087 /* check for type */
6088 if (equal_ustring(chn_settings->type, "FTP"))
6089 chn->type = LOG_TYPE_FTP;
6090 else if (equal_ustring(chn_settings->type, "Disk"))
6091 chn->type = LOG_TYPE_DISK;
6092 else {
6093 sprintf(error, "Invalid channel type \"%s\", pease use \"Tape\", \"FTP\" or \"Disk\"", chn_settings->type);
6094 cm_msg(MERROR, "tr_start", "%s", error);
6095 return 0;
6096 }
6097#endif
6098
6099#ifdef OBSOLETE
6100 /* set compression level */
6101 chn->compression = 0;
6102 size = sizeof(chn->compression);
6103 status = db_get_value(hDB, chn->settings_hkey, "Compression", &chn->compression, &size, TID_INT32, FALSE);
6104#endif
6105
6106 /* initialize subrun number */
6107 chn->subrun_number = 0;
6108
6111
6112 /* open logging channel */
6114
6115 /* return if logging channel couldn't be opened */
6116 if (status != SS_SUCCESS) {
6117 if (status == SS_FILE_ERROR)
6118 sprintf(error, "Cannot open file \'%s\' (See messages)", chn->path.c_str());
6119 if (status == SS_FILE_EXISTS)
6120 sprintf(error, "File \'%s\' exists already, run start aborted", chn->path.c_str());
6121 if (status == SS_NO_TAPE)
6122 sprintf(error, "No tape in device \'%s\'", chn->path.c_str());
6123 if (status == SS_TAPE_ERROR)
6124 sprintf(error, "Tape error, cannot start run");
6125 if (status == SS_DEV_BUSY)
6126 sprintf(error, "Device \'%s\' used by someone else", chn->path.c_str());
6128 sprintf(error, "Cannot open FTP channel to \'%s\'", chn->path.c_str());
6129 if (status == SS_NO_ROOT)
6130 sprintf(error, "No ROOT support compiled into mlogger, please compile with -DHAVE_ROOT flag");
6131
6133 sprintf(error, "Invalid data format, please use \"MIDAS\", \"ASCII\", \"DUMP\" or \"ROOT\"");
6134
6135 cm_msg(MERROR, "tr_start", "%s", error);
6136 return 0;
6137 }
6138
6139 /* close records if open from previous run start with abort */
6140 if (chn->stats_hkey)
6141 db_close_record(hDB, chn->stats_hkey);
6142 if (chn->settings_hkey)
6143 db_close_record(hDB, chn->settings_hkey);
6144
6145 /* open hot link to statistics tree */
6146 status = db_open_record1(hDB, chn->stats_hkey, &chn->statistics, sizeof(CHN_STATISTICS), MODE_WRITE, NULL, NULL, strcomb1(chn_statistics_str).c_str());
6147 if (status == DB_NO_ACCESS) {
6148 /* record is probably still in exclusive access by dead logger, so reset it */
6150 if (status != DB_SUCCESS)
6151 cm_msg(MERROR, "tr_start", "Cannot change access mode for statistics record, error %d", status);
6152 else
6153 cm_msg(MINFO, "tr_start", "Recovered access mode for statistics record of channel \"%s\"", chn->name.c_str());
6154 status = db_open_record1(hDB, chn->stats_hkey, &chn->statistics, sizeof(CHN_STATISTICS), MODE_WRITE, NULL, NULL, strcomb1(chn_statistics_str).c_str());
6155 }
6156
6157 if (status != DB_SUCCESS)
6158 cm_msg(MERROR, "tr_start", "Cannot open statistics record for channel \"%s\", error %d", chn->name.c_str(), status);
6159
6160 /* open hot link to settings tree */
6161 status = db_watch(hDB, chn->settings_hkey, watch_settings, chn);
6162 if (status != DB_SUCCESS)
6163 cm_msg(MERROR, "tr_start", "db_watch() status %d, cannot open channel settings record, probably other logger is using it", status);
6164
6165#ifndef FAL_MAIN
6166 /* open buffer */
6167 status = bm_open_buffer(chn_settings->buffer, DEFAULT_BUFFER_SIZE, &chn->buffer_handle);
6168 if (status != BM_SUCCESS && status != BM_CREATED) {
6169 sprintf(error, "Cannot open buffer %s", chn_settings->buffer);
6170 cm_msg(MERROR, "tr_start", "%s", error);
6171 return 0;
6172 }
6173 bm_set_cache_size(chn->buffer_handle, 1000000, 0);
6174
6175 /* place event request */
6176 status = bm_request_event(chn->buffer_handle, (short) chn_settings->event_id, (short) chn_settings->trigger_mask, GET_ALL, &chn->request_id, receive_event);
6177
6178 if (status != BM_SUCCESS) {
6179 sprintf(error, "Cannot place event request");
6180 cm_msg(MERROR, "tr_start", "%s", error);
6181 return 0;
6182 }
6183
6184 /* open message buffer if requested */
6185 if (chn_settings->log_messages) {
6186 status = bm_open_buffer((char*)MESSAGE_BUFFER_NAME, MESSAGE_BUFFER_SIZE, &chn->msg_buffer_handle);
6187 if (status != BM_SUCCESS && status != BM_CREATED) {
6188 sprintf(error, "Cannot open buffer %s", MESSAGE_BUFFER_NAME);
6189 cm_msg(MERROR, "tr_start", "%s", error);
6190 return 0;
6191 }
6192
6193 /* place event request */
6194 status = bm_request_event(chn->msg_buffer_handle, (short) EVENTID_MESSAGE, (short) chn_settings->log_messages, GET_ALL, &chn->msg_request_id, receive_event);
6195
6196 if (status != BM_SUCCESS) {
6197 sprintf(error, "Cannot place event request");
6198 cm_msg(MERROR, "tr_start", "%s", error);
6199 return 0;
6200 }
6201 }
6202#endif
6203 }
6204 }
6205
6206 DWORD t3 = ss_millitime();
6207
6208 if (tape_flag && tape_message)
6209 cm_msg(MTALK, "tr_start", "tape mounting finished");
6210
6211 /* write transition event into history */
6213
6214 DWORD t4 = ss_millitime();
6215
6216#ifdef HAVE_MYSQL
6217 /* write to SQL database if requested */
6219#endif
6220
6221 /* write to runlog file(s) if requested */
6224
6225 DWORD t5 = ss_millitime();
6226 DWORD te = t5;
6227
6228 if (verbose)
6229 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",
6230 run_number,
6231 te-t0,
6232 t1-t0,
6233 t2-t1,
6234 t3-t2,
6235 t4-t3,
6236 t5-t4
6237 );
6238
6241
6243
6244 return CM_SUCCESS;
6245}
6246
6247/*-- -------- ------------------------------------------------------*/
6248
6250{
6251 if (verbose)
6252 printf("tr_start_abort: run %d\n", run_number);
6253
6255
6256 for (unsigned i = 0; i < log_channels.size(); i++) {
6258 if (chn->handle && chn->type == LOG_TYPE_DISK) {
6259 cm_msg(MINFO, "tr_start_abort", "Deleting previous file \"%s\"", chn->path.c_str());
6260 unlink(chn->path.c_str());
6261 }
6262 }
6263
6265 close_buffers();
6266
6268
6270
6272
6273 return CM_SUCCESS;
6274}
6275
6276/*-- poststop ------------------------------------------------------*/
6277
6279/********************************************************************\
6280
6281 Poststop:
6282
6283 Wait until buffers are empty, then close logging channels
6284
6285\********************************************************************/
6286{
6287 INT size;
6289 char filename[256];
6290 char str[256];
6291
6292 if (verbose)
6293 printf("tr_stop: run %d\n", run_number);
6294
6296 return CM_SUCCESS;
6297
6298 DWORD t0 = ss_millitime();
6299
6301
6303 close_buffers();
6304
6305 DWORD t1 = ss_millitime();
6306
6307 /* ODB dump if requested */
6308 size = sizeof(flag);
6309 flag = 0;
6310 db_get_value(hDB, 0, "/Logger/ODB Dump", &flag, &size, TID_BOOL, TRUE);
6311 if (flag) {
6312 strcpy(str, "run%d.json");
6313 size = sizeof(str);
6314 str[0] = 0;
6315 db_get_value(hDB, 0, "/Logger/ODB Dump File", str, &size, TID_STRING, TRUE);
6316 if (str[0] == 0)
6317 strcpy(str, "run%d.json");
6318
6319 /* substitue "%d" by current run number */
6320 if (strchr(str, '%'))
6321 sprintf(filename, str, run_number);
6322 else
6323 strcpy(filename, str);
6324
6325 odb_save(filename, true);
6326 }
6327
6328 DWORD t2 = ss_millitime();
6329
6330#ifdef HAVE_MYSQL
6331 /* write to SQL database if requested */
6333#endif
6334
6335 /* write to ASCII file(s) if requested */
6338
6339 DWORD t3 = ss_millitime();
6340
6342
6343 if (tape_flag & tape_message)
6344 cm_msg(MTALK, "tr_stop", "all tape channels closed");
6345
6346 /* write transition event into history */
6348
6349 DWORD t4 = ss_millitime();
6350
6351 /* clear flag */
6353 stop_try_later = 0;
6354
6355 if (start_requested) {
6356 int delay = 0;
6357 size = sizeof(delay);
6358 db_get_value(hDB, 0, "/Logger/Auto restart delay", &delay, &size, TID_INT32, TRUE);
6359 auto_restart = ss_time() + delay; /* start after specified delay */
6361 }
6362
6363 DWORD te = t4;
6364
6365 if (verbose)
6366 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",
6367 run_number,
6368 te-t0,
6369 t1-t0,
6370 t2-t1,
6371 t3-t2,
6372 t4-t3);
6373
6374
6376
6378
6379 return CM_SUCCESS;
6380}
6381
6382/*== common code FAL/MLOGGER end ===================================*/
6383
6384/*----- pause/resume -----------------------------------------------*/
6385
6387{
6388 /* write transition event into history */
6390
6392
6394
6395 return CM_SUCCESS;
6396}
6397
6399{
6400 /* write transition event into history */
6402
6404
6406
6407 return CM_SUCCESS;
6408}
6409
6410/*----- receive_event ----------------------------------------------*/
6411
6412void receive_event(HNDLE hBuf, HNDLE request_id, EVENT_HEADER * pheader, void *pevent)
6413{
6414 if (verbose)
6415 printf("write data event: req %d, evid %d, timestamp %d, size %d\n", request_id, pheader->event_id, pheader->time_stamp, pheader->data_size);
6416
6417 /* find logging channel for this request id */
6418 for (unsigned i = 0; i < log_channels.size(); i++) {
6420 if (chn->handle == 0 && chn->ftp_con == NULL)
6421 continue;
6422
6423 /* write normal events */
6424 if (chn->request_id == request_id) {
6425 log_write(chn, pheader);
6426 break;
6427 }
6428
6429 /* write messages */
6430 if (chn->msg_request_id == request_id) {
6431 log_write(chn, pheader);
6432 break;
6433 }
6434 }
6435}
6436
6437/*------------------------ main ------------------------------------*/
6438
6439int main(int argc, char *argv[])
6440{
6441 INT status, msg, i, size, ch = 0;
6444 DWORD last_time_kb = 0;
6447
6448#ifdef HAVE_ROOT
6449 char **rargv;
6450 int rargc;
6451
6452 /* copy first argument */
6453 rargc = 0;
6454 rargv = (char **) malloc(sizeof(char *) * 2);
6455 assert(rargv != NULL);
6456 rargv[rargc] = (char *) malloc(strlen(argv[rargc]) + 1);
6457 assert(rargv[rargc] != NULL);
6458 strcpy(rargv[rargc], argv[rargc]);
6459 rargc++;
6460
6461 /* append argument "-b" for batch mode without graphics */
6462 rargv[rargc++] = (char *)"-b";
6463
6464 TApplication theApp("mlogger", &rargc, rargv);
6465
6466 /* free argument memory */
6467 free(rargv[0]);
6468 rargv[0] = NULL;
6469 free(rargv);
6470 rargv = NULL;
6471
6472#endif
6473
6474#ifdef SIGPIPE
6475 // undo ROOT overwrites SIGPIPE
6477#endif
6478
6479 setbuf(stdout, NULL);
6480 setbuf(stderr, NULL);
6481
6482 /* get default from environment */
6484
6486
6487 /* parse command line parameters */
6488 for (i = 1; i < argc; i++) {
6489 if (argv[i][0] == '-' && argv[i][1] == 'd')
6490 debug = TRUE;
6491 else if (argv[i][0] == '-' && argv[i][1] == 'D')
6492 daemon = TRUE;
6493 else if (argv[i][0] == '-' && argv[i][1] == 's')
6494 save_mode = TRUE;
6495 else if (argv[i][0] == '-' && argv[i][1] == 'v')
6496 verbose = TRUE;
6497 else if (argv[i][0] == '-') {
6498 if (i + 1 >= argc || argv[i + 1][0] == '-')
6499 goto usage;
6500 if (argv[i][1] == 'e')
6501 strcpy(exp_name, argv[++i]);
6502 else {
6503 usage:
6504 printf("usage: mlogger [-e Experiment] [-d] [-D] [-s] [-v]\n\n");
6505 return 1;
6506 }
6507 }
6508 }
6509
6510 if (daemon) {
6511 printf("Becoming a daemon...\n");
6513 }
6514
6516 if (status != CM_SUCCESS)
6517 return 1;
6518
6519 /* check if logger already running */
6520 status = cm_exist("Logger", FALSE);
6521 if (status == CM_SUCCESS) {
6522 printf("Logger runs already.\n");
6524 return 1;
6525 }
6526
6528
6529 /* turn off watchdog if in debug mode */
6530 if (debug)
6532
6533 /* turn on save mode */
6534 if (save_mode) {
6537 }
6538
6539 /* register transition callbacks */
6541 cm_msg(MERROR, "main", "cannot register callbacks");
6542 return 1;
6543 }
6544
6549
6550 /* initialize ODB */
6551 logger_init();
6552
6553 /* obtain current state */
6555 size = sizeof(local_state);
6556 status = db_get_value(hDB, 0, "/Runinfo/State", &local_state, &size, TID_INT32, true);
6557
6558 /* open history logging */
6559 if (open_history() != CM_SUCCESS) {
6560 printf("Error in history system, aborting startup.\n");
6562 return 1;
6563 }
6564
6565 /* print startup message */
6566 std::string data_dir;
6567 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &data_dir, TRUE);
6568 if (data_dir.length() <= 0)
6570 printf("Data directory is \"%s\" unless specified under /Logger/channels/\n", data_dir.c_str());
6571
6572 /* Alternate message path */
6573 std::string message_dir;
6574 db_get_value_string(hDB, 0, "/Logger/Message dir", 0, &message_dir, TRUE);
6575 if (message_dir.empty()) {
6577 printf("Message directory is \"%s\" unless specified in /Logger/Message dir\n", message_dir.c_str());
6578 } else
6579 printf("Message directory is \"%s\"\n", message_dir.c_str());
6580
6581 /* Alternate History and Elog path */
6582 std::string history_dir;
6583 db_get_value_string(hDB, 0, "/Logger/History dir", 0, &history_dir, TRUE);
6584 if (history_dir.empty()) {
6586 printf("History directory is \"%s\" unless specified under /Logger/history/\n", history_dir.c_str());
6587 } else
6588 printf("History directory is \"%s\"\n", history_dir.c_str());
6589
6590#ifdef HAVE_MYSQL
6591 {
6592 std::string sql_host;
6593 std::string sql_db;
6594 std::string sql_table;
6595
6596 HNDLE hktemp;
6597 status = db_find_key(hDB, 0, "/Logger/Runlog/SQL/Hostname", &hktemp);
6598 if (status == DB_SUCCESS) {
6599 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Hostname", 0, &sql_host, FALSE);
6600 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Database", 0, &sql_db, FALSE);
6601 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Table", 0, &sql_table, FALSE);
6602 printf("SQL database is %s/%s/%s", sql_host.c_str(), sql_db.c_str(), sql_table.c_str());
6603 }
6604 }
6605#endif
6606
6607 printf("\nMIDAS logger started. Stop with \"!\"\n");
6608
6609 /* initialize ss_getchar() */
6610 ss_getchar(0);
6611
6612 /* start image history threads */
6614
6615 do {
6616 msg = cm_yield(100);
6617
6618 /* maybe update channel disk levels */
6620
6621 /* update channel statistics once every second */
6622 if (ss_millitime() - last_time_stat > 1000) {
6624 /*
6625 printf("update statistics!\n");
6626 //LOG_CHN* log_chn = log_chn[0];
6627 printf("events %.0f, subrun %.0f, written %.0f, total %.0f\n", log_chn->statistics.events_written,
6628 log_chn->statistics.bytes_written_subrun,
6629 log_chn->statistics.bytes_written,
6630 log_chn->statistics.bytes_written_total);
6631 */
6633 }
6634
6635 /* check for auto restart */
6636 if (auto_restart && ss_time() > auto_restart) {
6638 }
6639
6640 /* check if time is reached to stop run */
6641 duration = 0;
6642 size = sizeof(duration);
6643 db_get_value(hDB, 0, "/Logger/Run duration", &duration, &size, TID_UINT32, true);
6645 duration > 0 && ss_time() >= run_start_time + duration) {
6646 cm_msg(MTALK, "main", "stopping run after %d seconds", duration);
6647 status = stop_the_run(1);
6648 }
6649
6650 /* stop the run if previous attempt failed */
6651 if (stop_try_later) {
6652 if (ss_time_sec() > stop_try_later) {
6653 cm_msg(MTALK, "main", "another attempt to stop the run");
6654 status = stop_the_run(0);
6655 }
6656 }
6657
6658 /* check keyboard once every 100 ms */
6659 if (ss_millitime() - last_time_kb > 100) {
6661
6662 ch = 0;
6663 while (ss_kbhit()) {
6664 ch = ss_getchar(0);
6665 if (ch == -1)
6666 ch = getchar();
6667
6668 if ((char) ch == '!')
6669 break;
6670 }
6671 }
6672
6673 } while (msg != RPC_SHUTDOWN && msg != SS_ABORT && ch != '!');
6674
6675 /* reset terminal */
6677
6678 /* close history logging */
6679 close_history();
6680
6681 /* stop image history threads */
6683 printf("Stopping image history threads...");
6684 fflush(stdout);
6686 printf("ok\n");
6687 }
6688
6690
6691 return 0;
6692}
6693
6694/* emacs
6695 * Local Variables:
6696 * tab-width: 8
6697 * c-basic-offset: 3
6698 * indent-tabs-mode: nil
6699 * End:
6700 */
#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:3012
std::string wr_get_file_ext()
Definition mlogger.cxx:3001
WriterFtp(LOG_CHN *log_chn)
Definition mlogger.cxx:2918
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:2937
std::string wr_get_chain()
Definition mlogger.cxx:3006
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:2958
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:2985
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:17125
INT bk_swap(void *event, BOOL force)
Definition midas.cxx:17179
BOOL bk_is32a(const void *event)
Definition midas.cxx:16459
BOOL bk_is32(const void *event)
Definition midas.cxx:16437
INT bk_iterate32(const void *event, BANK32 **pbk, void *pdata)
Definition midas.cxx:17089
INT bk_iterate(const void *event, BANK **pbk, void *pdata)
Definition midas.cxx:17068
INT bm_open_buffer(const char *buffer_name, INT buffer_size, INT *buffer_handle)
Definition midas.cxx:6739
INT bm_delete_request(INT request_id)
Definition midas.cxx:8606
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:8487
INT bm_set_cache_size(INT buffer_handle, size_t read_size, size_t write_size)
Definition midas.cxx:8162
INT bm_close_buffer(INT buffer_handle)
Definition midas.cxx:7118
INT bm_compose_event(EVENT_HEADER *event_header, short int event_id, short int trigger_mask, DWORD data_size, DWORD serial)
Definition midas.cxx:8303
INT cm_register_transition(INT transition, INT(*func)(INT, char *), INT sequence_number)
Definition midas.cxx:3615
INT cm_yield(INT millisec)
Definition midas.cxx:5664
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3025
INT cm_connect_experiment(const char *host_name, const char *exp_name, const char *client_name, void(*func)(char *))
Definition midas.cxx:2292
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5308
INT cm_disconnect_experiment(void)
Definition midas.cxx:2860
std::string cm_get_path()
Definition midas.cxx:1551
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2148
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3297
INT cm_exist(const char *name, BOOL bUnique)
Definition midas.cxx:7542
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:500
#define O_BINARY
Definition msystem.h:226
#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:502
BOOL ss_kbhit()
Definition system.cxx:3736
double ss_disk_size(const char *path)
Definition system.cxx:7126
time_t ss_mktime(struct tm *tms)
Definition system.cxx:3437
DWORD ss_millitime()
Definition system.cxx:3465
INT ss_getchar(BOOL reset)
Definition system.cxx:7581
double ss_disk_free(const char *path)
Definition system.cxx:6698
double ss_file_size(const char *path)
Definition system.cxx:7050
void ss_tzset()
Definition system.cxx:3427
INT ss_daemon_init(BOOL keep_stdout)
Definition system.cxx:2073
DWORD ss_time()
Definition system.cxx:3534
double ss_time_sec()
Definition system.cxx:3539
INT cm_msg_flush_buffer()
Definition midas.cxx:879
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:929
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3206
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6898
INT db_send_changed_records()
Definition odb.cxx:13787
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5420
INT db_save_json(HNDLE hDB, HNDLE hKey, const char *filename, int flags)
Definition odb.cxx:10532
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:13300
INT db_lock_database(HNDLE hDB)
Definition odb.cxx:2460
std::string strcomb1(const char **list)
Definition odb.cxx:600
INT db_save_xml(HNDLE hDB, HNDLE hKey, const char *filename)
Definition odb.cxx:9485
INT db_get_path(HNDLE hDB, HNDLE hKey, char *path, INT buf_size)
Definition odb.cxx:4995
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition odb.cxx:11812
INT db_copy(HNDLE hDB, HNDLE hKey, char *buffer, INT *buffer_size, const char *path)
Definition odb.cxx:8222
INT db_get_record_size(HNDLE hDB, HNDLE hKey, INT align, INT *buf_size)
Definition odb.cxx:11621
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6544
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3313
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:12981
INT db_copy_json_save(HNDLE hDB, HNDLE hKey, char **buffer, int *buffer_size, int *buffer_end)
Definition odb.cxx:10480
INT db_copy_xml(HNDLE hDB, HNDLE hKey, char *buffer, int *buffer_size, bool header)
Definition odb.cxx:9042
INT db_unlock_database(HNDLE hDB)
Definition odb.cxx:2582
INT db_unwatch(HNDLE hDB, HNDLE hKey)
Definition odb.cxx:13898
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition odb.cxx:8032
INT db_save(HNDLE hDB, HNDLE hKey, const char *filename, BOOL bRemote)
Definition odb.cxx:9250
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6024
INT db_get_link(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6077
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:13945
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13823
INT db_enum_link(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5730
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:10389
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10849
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:5266
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4084
BOOL ends_with_ustring(const char *str, const char *suffix)
Definition odb.cxx:3227
void json_write(char **buffer, int *buffer_size, int *buffer_end, int level, const char *s, int quoted)
Definition odb.cxx:9532
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:13451
INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size, INT align)
Definition odb.cxx:12299
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5591
INT db_close_record(HNDLE hDB, HNDLE hKey)
Definition odb.cxx:13483
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12808
INT db_create_link(HNDLE hDB, HNDLE hKey, const char *link_name, const char *destination)
Definition odb.cxx:3606
INT db_protect_database(HNDLE hDB)
Definition odb.cxx:3172
bool rpc_is_remote(void)
Definition midas.cxx:12783
const char * rpc_tid_name(INT id)
Definition midas.cxx:11786
INT rpc_tid_size(INT id)
Definition midas.cxx:11779
#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:412
INT bm_get_buffer_level(INT buffer_handle, INT *n_bytes)
Definition midas.cxx:7860
std::string msprintf(const char *format,...)
Definition midas.cxx:419
const char * mname[]
Definition midas.cxx:144
#define JSFLAG_RECURSE
Definition midas.h:1722
#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:1721
#define JSFLAG_OMIT_LAST_WRITTEN
Definition midas.h:1725
#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:1724
#define EVENTID_EOR
Definition midas.h:901
#define JS_LEVEL_1
Definition midas.h:1718
#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:1726
#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:4050
void log_history(HNDLE hDB, HNDLE hKey, void *info)
Definition mlogger.cxx:5571
#define FREE(ptr)
Definition mlogger.cxx:367
#define CHECKSUM_ZLIB
Definition mlogger.cxx:3953
void receive_event(HNDLE hBuf, HNDLE request_id, EVENT_HEADER *pheader, void *pevent)
Definition mlogger.cxx:6412
void create_runlog_json_tree()
Definition mlogger.cxx:2651
#define CHECKSUM_CRC32C
Definition mlogger.cxx:3954
INT tr_stop(INT run_number, char *error)
Definition mlogger.cxx:6278
#define DISK_CHECK_INTERVAL_MILLISEC
Definition mlogger.cxx:310
std::string get_value(HNDLE hDB, HNDLE hDir, const char *name)
Definition mlogger.cxx:4001
INT tr_start_abort(INT run_number, char *error)
Definition mlogger.cxx:6249
static std::vector< MidasHistoryInterface * > mh
Definition mlogger.cxx:4746
EVENT_DEF * db_get_event_definition(short int event_id)
Definition mlogger.cxx:3316
#define COMPRESS_NONE
Definition mlogger.cxx:3976
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:5515
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:4084
static int hist_log_size
Definition mlogger.cxx:334
void close_history()
Definition mlogger.cxx:5533
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:6386
static std::vector< std::string > history_events
Definition mlogger.cxx:4747
int log_generate_file_name(LOG_CHN *log_chn)
Definition mlogger.cxx:5677
static FILE * fopen_wx(const char *filename)
Definition mlogger.cxx:386
static int get_trans_flag()
Definition mlogger.cxx:4403
void log_system_history(HNDLE hDB, HNDLE hKey, void *info)
Definition mlogger.cxx:5623
int select_checksum_module(HNDLE hDB, HNDLE hSet, const char *name)
Definition mlogger.cxx:4033
INT tr_start(INT run_number, char *error)
Definition mlogger.cxx:5939
WriterInterface * NewCompression(LOG_CHN *log_chn, int code, WriterInterface *chained)
Definition mlogger.cxx:3982
#define OUTPUT_FILE
Definition mlogger.cxx:3996
INT log_open(LOG_CHN *log_chn, INT run_number)
Definition mlogger.cxx:4240
#define OUTPUT_NULL
Definition mlogger.cxx:3995
#define EVENT_DEF_CACHE_SIZE
INT ftp_error(const char *message)
Definition mlogger.cxx:2826
time_t last_history_flush
Definition mlogger.cxx:5513
INT tr_resume(INT run_number, char *error)
Definition mlogger.cxx:6398
WriterInterface * NewChecksum(LOG_CHN *log_chn, int code, int level, WriterInterface *chained)
Definition mlogger.cxx:3958
#define MEMZERO(obj)
Definition mlogger.cxx:365
WriterInterface * NewWriterBzip2(LOG_CHN *log_chn)
Definition mlogger.cxx:3918
int maybe_check_disk_level()
Definition mlogger.cxx:4378
INT log_close(LOG_CHN *log_chn, INT run_number)
Definition mlogger.cxx:4290
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:4012
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:4021
int start_the_run()
Definition mlogger.cxx:4477
#define CHECKSUM_SHA256
Definition mlogger.cxx:3955
INT open_history()
Definition mlogger.cxx:4866
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:2832
std::vector< LOG_CHN * > log_channels
Definition mlogger.cxx:322
#define OUTPUT_FTP
Definition mlogger.cxx:3997
int select_output_module(HNDLE hDB, HNDLE hSet, const char *name)
Definition mlogger.cxx:4067
#define OUTPUT_PIPE
Definition mlogger.cxx:3999
static void watch_settings(HNDLE hDB, HNDLE hKey, HNDLE index, void *info)
Definition mlogger.cxx:5921
#define CHECKSUM_NONE
Definition mlogger.cxx:3952
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:3979
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:5905
int close_buffers()
Definition mlogger.cxx:5877
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:4749
INT log_write(LOG_CHN *log_chn, EVENT_HEADER *pheader)
Definition mlogger.cxx:4538
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:3980
#define CHN_STATISTICS_STR(_name)
Definition mlogger.cxx:242
#define OUTPUT_ROOT
Definition mlogger.cxx:3998
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:2698
#define COMPRESS_LZ4
Definition mlogger.cxx:3978
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:4349
int close_channels(int run_number, BOOL *p_tape_flag)
Definition mlogger.cxx:5832
WriterInterface * NewWriterPbzip2(LOG_CHN *log_chn)
Definition mlogger.cxx:3930
#define CHECKSUM_SHA512
Definition mlogger.cxx:3956
#define COMPRESS_ZLIB
Definition mlogger.cxx:3977
int stop_the_run(int restart)
Definition mlogger.cxx:4443
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:1213
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:1232
DWORD type
Definition midas.h:1234
DWORD n_data
Definition midas.h:1235
char name[NAME_LENGTH]
Definition midas.h:1233
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:1312