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 OS_WINNT
26#define ZLIB_WINAPI
27#endif
28#include <zlib.h>
29
30#ifdef HAVE_MYSQL
31#ifdef OS_UNIX
32#include <mysql.h>
33#include <mysqld_error.h>
34#endif
35#ifdef OS_WINNT
36#include <mysql.h>
37#include <mysqld_error.h>
38int errno; // under NT, "ignore libcd" is required, so errno has to be defined here
39#endif
40void create_runlog_sql_tree();
41#endif
42
45
46static std::string IntToString(int value)
47{
48 char buf[256];
49 sprintf(buf, "%d", value);
50 return buf;
51}
52
53static std::string TimeToString(time_t t)
54{
55 const char* sign = "";
56
57 if (t == 0)
58 return "0";
59
60 time_t tt = t;
61
62 if (t < 0) {
63 sign = "-";
64 tt = -t;
65 }
66
67 assert(tt > 0);
68
69 std::string v;
70 while (tt) {
71 char c = '0' + tt%10;
72 tt /= 10;
73 v = c + v;
74 }
75
76 v = sign + v;
77
78 //printf("time %.0f -> %s\n", (double)t, v.c_str());
79
80 return v;
81}
82
83/*---- Logging channel information ---------------------------------*/
84
85// NOTE: [Settings] here MUST be exactly same as CHN_SETTINGS_STR below
86
87#define CHN_TREE_STR(_name) const char *_name[] = {\
88"[Settings]",\
89"Active = BOOL : 1",\
90"Type = STRING : [8] Disk",\
91"Filename = STRING : [256] run%05d.mid",\
92"Format = STRING : [8] MIDAS",\
93"Compression = INT32 : 0",\
94"ODB dump = BOOL : 1",\
95"ODB dump format = STRING : [32] json",\
96"Options ODB dump format = STRING[3] :",\
97"[32] odb",\
98"[32] xml",\
99"[32] json",\
100"Log messages = UINT32 : 0",\
101"Buffer = STRING : [32] SYSTEM",\
102"Event ID = INT32 : -1",\
103"Trigger mask = INT32 : -1",\
104"Event limit = DOUBLE : 0",\
105"Byte limit = DOUBLE : 0",\
106"Subrun Byte limit = DOUBLE : 0",\
107"Tape capacity = DOUBLE : 0",\
108"Subdir format = STRING : [32]",\
109"Current filename = STRING : [256]",\
110"Data checksum = STRING : [256] CRC32C",\
111"Options Data checksum = STRING[5] :",\
112"[32] NONE",\
113"[32] CRC32C",\
114"[32] SHA256",\
115"[32] SHA512",\
116"[32] ZLIB",\
117"File checksum = STRING : [256] CRC32C",\
118"Options File checksum = STRING[5] :",\
119"[32] NONE",\
120"[32] CRC32C",\
121"[32] SHA256",\
122"[32] SHA512",\
123"[32] ZLIB",\
124"Compress = STRING : [256] lz4",\
125"Options Compress = STRING[5] :",\
126"[32] none",\
127"[32] gzip",\
128"[32] lz4",\
129"[32] bzip2",\
130"[32] pbzip2",\
131"Output = STRING : [256] FILE",\
132"Options Output = STRING[5] :",\
133"[32] NULL",\
134"[32] FILE",\
135"[32] FTP",\
136"[32] ROOT",\
137"[32] PIPE",\
138"Gzip compression = UINT32 : 0",\
139"Bzip2 compression = UINT32 : 0",\
140"Pbzip2 num cpu = UINT32 : 0",\
141"Pbzip2 compression = UINT32 : 0",\
142"Pbzip2 options = STRING : [256]",\
143"",\
144"[Statistics]",\
145"Events written = DOUBLE : 0",\
146"Bytes written = DOUBLE : 0",\
147"Bytes written uncompressed = DOUBLE : 0",\
148"Bytes written total = DOUBLE : 0",\
149"Bytes written subrun = DOUBLE : 0",\
150"Files written = DOUBLE : 0",\
151"Disk level = DOUBLE : 0",\
152"",\
153NULL}
154
155typedef struct {
157 char obsolete_type[8];
158 char filename[256];
159 char obsolete_format[8];
162 char odb_dump_format[32];
163 char options_odb_dump_format[3][32];
165 char buffer[32];
172 char subdir_format[32];
173 char current_filename[256];
174 char data_checksum[256];
175 char options_data_checksum[5][32];
176 char file_checksum[256];
177 char options_file_checksum[5][32];
178 char compress[256];
179 char options_compress[5][32];
180 char output[256];
181 char options_output[5][32];
186 char pbzip2_options[256];
188
189// NOTE: CHN_SETTINGS here MUST be exactly same as [Settings] in CHN_TREE_STR above.
190
191#define CHN_SETTINGS_STR(_name) const char *_name[] = { \
192"Active = BOOL : 1",\
193"Type = STRING : [8] Disk",\
194"Filename = STRING : [256] run%05d.mid",\
195"Format = STRING : [8] MIDAS",\
196"Compression = INT32 : 0",\
197"ODB dump = BOOL : 1",\
198"ODB dump format = STRING : [32] json",\
199"Log messages = UINT32 : 0",\
200"Buffer = STRING : [32] SYSTEM",\
201"Event ID = INT32 : -1",\
202"Trigger mask = INT32 : -1",\
203"Event limit = DOUBLE : 0",\
204"Byte limit = DOUBLE : 0",\
205"Subrun Byte limit = DOUBLE : 0",\
206"Tape capacity = DOUBLE : 0",\
207"Subdir format = STRING : [32]",\
208"Current filename = STRING : [256]",\
209"Data checksum = STRING : [256]",\
210"File checksum = STRING : [256]",\
211"Compress = STRING : [256]",\
212"Output = STRING : [256]",\
213"Gzip compression = UINT32 : 0",\
214"Bzip2 compression = UINT32 : 0",\
215"Pbzip2 num cpu = UINT32 : 0",\
216"Pbzip2 compression = UINT32 : 0",\
217"Pbzip2 options = STRING : [256]",\
218"",\
219NULL}
220
222 double events_written = 0; /* count events, reset in tr_start() */
223 double bytes_written = 0; /* count bytes written out (compressed), reset in tr_start() */
224 double bytes_written_uncompressed = 0; /* count bytes before compression, reset in tr_start() */
225 double bytes_written_total = 0; /* count bytes written out (compressed), reset in log_callback(RPC_LOG_REWIND) */
226 double bytes_written_subrun = 0; /* count bytes written out (compressed), reset in tr_start() and on subrun increment */
227 double files_written = 0; /* incremented in log_close(), reset in log_callback(RPC_LOG_REWIND) */
228 double disk_level = 0;
229};
230
231#define CHN_STATISTICS_STR(_name) const char *_name[] = {\
232"Events written = DOUBLE : 0",\
233"Bytes written = DOUBLE : 0",\
234"Bytes written uncompressed = DOUBLE : 0",\
235"Bytes written total = DOUBLE : 0",\
236"Bytes written subrun = DOUBLE : 0",\
237"Files written = DOUBLE : 0",\
238"Disk level = DOUBLE : 0",\
239"",\
240NULL}
241
242/*---- logger channel definition---------------------------------------*/
243
244class WriterInterface;
245struct MIDAS_INFO;
246
273
275{
276 LOG_CHN* chn = new LOG_CHN;
277 chn->name = name;
278 // chn->settings clear settings
279 return chn;
280};
281
282/*---- globals -----------------------------------------------------*/
283
284#define DISK_CHECK_INTERVAL_MILLISEC 10000
285
294double stop_try_later = 0;
295
296std::vector<LOG_CHN*> log_channels;
297
307
308static int hist_log_size = 0;
309static int hist_log_max = 0;
310static struct hist_log_s *hist_log = NULL;
311
312static HNDLE hDB;
313
314/*---- ODB records -------------------------------------------------*/
315
316static CHN_SETTINGS_STR(chn_settings_str);
317static CHN_STATISTICS_STR(chn_statistics_str);
318static CHN_TREE_STR(chn_tree_str);
319
320/*---- data structures for MIDAS format ----------------------------*/
321
323 char *buffer;
325};
326
327/*---- forward declarations ----------------------------------------*/
328
329void receive_event(HNDLE hBuf, HNDLE request_id, EVENT_HEADER * pheader, void *pevent);
330INT log_write(LOG_CHN * log_chn, EVENT_HEADER * pheader);
332int log_generate_file_name(LOG_CHN *log_chn);
333extern void start_image_history();
334extern void stop_image_history();
336
337/*== common code FAL/MLOGGER start =================================*/
338
339#define MEMZERO(obj) memset(&(obj), 0, sizeof(obj))
340
341#define FREE(ptr) if (ptr) free(ptr); (ptr)=NULL;
342#define DELETE(ptr) if (ptr) delete (ptr); (ptr)=NULL;
343
344/*---- writer helper --------------------------------------------*/
345
346static std::string xpathname(const char* xpath, int level)
347{
348 std::string path = xpath;
349 while (level > 0) {
350 size_t p = path.rfind(".");
351 //printf("level %d, path [%s], pos %d\n", level, path.c_str(), (int)p);
352 if (p == std::string::npos)
353 break;
354 path = path.substr(0, p);
355 level--;
356 }
357 return path;
358}
359
360static FILE* fopen_wx(const char* filename)
361{
362 int fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IRGRP|S_IROTH);
363 if (fd == -1)
364 return NULL;
365 return fdopen(fd, "w");
366}
367
368static bool check_file_exists(const char* filename)
369{
370 struct stat st;
371 int status = stat(filename, &st);
372 if (status == -1) {
373 return false;
374 }
375 return true;
376}
377
378/*---- writer interface --------------------------------------------*/
379
381{
382public:
383 virtual int wr_open(LOG_CHN* log_chn, int run_number) = 0;
384 virtual int wr_write(LOG_CHN* log_chn, const void* data, const int size) = 0;
385 virtual int wr_close(LOG_CHN* log_chn, int run_number) = 0;
386 WriterInterface(); // base ctor
387 virtual ~WriterInterface() {}; // dtor
388 virtual std::string wr_get_file_ext() { return ""; }
389 virtual std::string wr_get_chain() = 0;
390public:
391 bool fTrace; // enable tracing printout
392 double fBytesIn; // count bytes in (before compression)
393 double fBytesOut; // count bytes out (after compression)
394};
395
397{
398 //fTrace = true; // <------ to enable (disable) tracing printout, set to "true" ("false")
399 fTrace = false; // <------ to enable (disable) tracing printout, set to "true" ("false")
400 fBytesIn = 0;
401 fBytesOut = 0;
402
403 if (fTrace)
404 printf("WriterInterface: default constructor!\n");
405}
406
407/*---- Null writer ------------------------------------------------*/
408
410{
411public:
412 WriterNull(LOG_CHN* log_chn) // ctor
413 {
414 if (fTrace)
415 printf("WriterNull: path [%s]\n", log_chn->path.c_str());
416 fSimulateCompression = false;
417 }
418
419 ~WriterNull() // dtor
420 {
421 if (fTrace)
422 printf("WriterNull: destructor\n");
423 }
424
425 int wr_open(LOG_CHN* log_chn, int run_number)
426 {
427 if (fTrace)
428 printf("WriterNull: open path [%s]\n", log_chn->path.c_str());
429 fBytesIn = 0;
430 fBytesOut = 0;
431 log_chn->handle = 9999;
433 fBytesOut += 10; // simulate compression header
434 return SUCCESS;
435 }
436
437 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
438 {
439 if (fTrace)
440 printf("WriterNull: write path [%s], size %d\n", log_chn->path.c_str(), size);
441 fBytesIn += size;
443 fBytesOut += size/3; // simulate compression
444 else
445 fBytesOut += size;
446 return SUCCESS;
447 }
448
449 int wr_close(LOG_CHN* log_chn, int run_number)
450 {
451 if (fTrace)
452 printf("WriterNull: close path [%s]\n", log_chn->path.c_str());
454 fBytesOut += 20; // simulate compression footer
455 log_chn->handle = 0;
456 return SUCCESS;
457 }
458
459 std::string wr_get_file_ext()
460 {
461 return ".null";
462 }
463
464 std::string wr_get_chain()
465 {
466 return "NULL";
467 }
468
469private:
471};
472
473/*---- file writer -------------------------------------------------*/
474
476{
477public:
478 WriterFile(LOG_CHN* log_chn) // ctor
479 {
480 if (fTrace)
481 printf("WriterFile: path [%s]\n", log_chn->path.c_str());
482 fFileno = -1;
483 }
484
485 ~WriterFile() // dtor
486 {
487 if (fTrace)
488 printf("WriterFile: destructor\n");
489 fFileno = -1;
490 }
491
492 int wr_open(LOG_CHN* log_chn, int run_number)
493 {
494 fBytesIn = 0;
495 fBytesOut = 0;
496
497 if (fTrace)
498 printf("WriterFile: open path [%s]\n", log_chn->path.c_str());
499
500 assert(fFileno < 0);
501
502 if (check_file_exists(log_chn->path.c_str()))
503 return SS_FILE_EXISTS;
504
505#ifdef OS_WINNT
506 fFileno = (int) CreateFile(log_chn->path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_SEQUENTIAL_SCAN, 0);
507#else
508 fFileno = open(log_chn->path.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_BINARY | O_LARGEFILE, 0444);
509#endif
510 if (fFileno < 0) {
511 cm_msg(MERROR, "WriterFile::wr_open", "Cannot write to file \'%s\', open() errno %d (%s)", log_chn->path.c_str(), errno, strerror(errno));
512 return SS_FILE_ERROR;
513 }
514
515 log_chn->handle = fFileno;
516
517 fFilename = log_chn->path;
518 return SUCCESS;
519 }
520
521 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
522 {
523 if (fTrace)
524 printf("WriterFile: write path [%s], size %d\n", log_chn->path.c_str(), size);
525
526 if (size == 0)
527 return SUCCESS;
528
529 assert(fFileno >= 0);
530
531 fBytesIn += size;
532
533 int wr = write(fFileno, data, size);
534
535 if (wr > 0)
536 fBytesOut += wr;
537
538 if (wr != size) {
539 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));
540 return SS_FILE_ERROR;
541 }
542
543 return SUCCESS;
544 }
545
546 int wr_close(LOG_CHN* log_chn, int run_number)
547 {
548 int err;
549
550 if (fTrace)
551 printf("WriterFile: close path [%s]\n", log_chn->path.c_str());
552
553 assert(fFileno >= 0);
554
555 log_chn->handle = 0;
556
557 err = close(fFileno);
558 fFileno = -1;
559
560 if (err != 0) {
561 cm_msg(MERROR, "WriterFile::wr_close", "Cannot write to file \'%s\', close() errno %d (%s)", log_chn->path.c_str(), errno, strerror(errno));
562 return SS_FILE_ERROR;
563 }
564
565 return SUCCESS;
566 }
567
568 std::string wr_get_chain()
569 {
570 return ">" + fFilename;
571 }
572
573private:
574 std::string fFilename;
576};
577
578/*---- gzip writer -------------------------------------------------*/
579
580#include <zlib.h>
581
583{
584public:
585 WriterGzip(LOG_CHN* log_chn, int compress) // ctor
586 {
587 if (fTrace)
588 printf("WriterGzip: path [%s]\n", log_chn->path.c_str());
589 fGzfp = 0;
590 if (log_chn->settings.gzip_compression) {
592 } else {
594 }
595 fLastCheckTime = time(NULL);
596 }
597
598 ~WriterGzip() // dtor
599 {
600 if (fTrace)
601 printf("WriterGzip: destructor\n");
602 assert(fGzfp == 0);
603 }
604
605 int wr_open(LOG_CHN* log_chn, int run_number)
606 {
607 int zerror;
608
609 fBytesIn = 0;
610 fBytesOut = 0;
611
612 if (fTrace)
613 printf("WriterGzip: open path [%s]\n", log_chn->path.c_str());
614
615 assert(fGzfp == 0);
616
617 if (check_file_exists(log_chn->path.c_str()))
618 return SS_FILE_EXISTS;
619
620 fGzfp = gzopen(log_chn->path.c_str(), "wb");
621 if (fGzfp == 0) {
622 cm_msg(MERROR, "WriterGzip::wr_open", "Cannot write to file \'%s\', gzopen() errno %d (%s)", log_chn->path.c_str(), errno, strerror(errno));
623 return SS_FILE_ERROR;
624 }
625
626 chmod(log_chn->path.c_str(), 0444);
627
628 //printf("WriterGzip::wr_open: compress %d\n", fCompress);
629
630 if (fCompress) {
631 zerror = gzsetparams(fGzfp, fCompress, Z_DEFAULT_STRATEGY);
632 if (zerror != Z_OK) {
633 cm_msg(MERROR, "WriterGzip::wr_open", "gzsetparams() zerror %d", zerror);
634 return SS_FILE_ERROR;
635 }
636 }
637
638#if ZLIB_VERNUM > 0x1235
639 // gzbuffer() added in zlib 1.2.3.5 (8 Jan 2010)
640 zerror = gzbuffer(fGzfp, 128*1024);
641 if (zerror != Z_OK) {
642 cm_msg(MERROR, "WriterGzip::wr_open", "gzbuffer() zerror %d", zerror);
643 return SS_FILE_ERROR;
644 }
645#else
646#warning Very old zlib, no gzbuffer()!
647#endif
648
649 log_chn->handle = 8888;
650
651 fFilename = log_chn->path;
652 return SUCCESS;
653 }
654
655 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
656 {
657 if (fTrace)
658 printf("WriterGzip: write path [%s], size %d\n", log_chn->path.c_str(), size);
659
660 if (size == 0)
661 return SUCCESS;
662
663 assert(fGzfp);
664
665 fBytesIn += size;
666
667 int wr = gzwrite(fGzfp, data, size);
668
669 if (wr != size) {
670 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));
671 return SS_FILE_ERROR;
672 }
673
674#if ZLIB_VERNUM > 0x1235
675 // gzoffset() added in zlib 1.2.3.5 (8 Jan 2010)
676 fBytesOut = gzoffset(fGzfp);
677#else
678#warning Very old zlib, no gzoffset()!
679 time_t now = time(NULL);
680 if (now - fLastCheckTime > 2) {
681 fLastCheckTime = now;
682 fBytesOut = ss_file_size(log_chn->path.c_str());
683 }
684#endif
685
686 return SUCCESS;
687 }
688
689 int wr_close(LOG_CHN* log_chn, int run_number)
690 {
691 int zerror;
692
693 if (fTrace)
694 printf("WriterGzip: close path [%s]\n", log_chn->path.c_str());
695
696 assert(fGzfp);
697
698 log_chn->handle = 0;
699
700 zerror = gzflush(fGzfp, Z_FINISH);
701
702 if (zerror != Z_OK) {
703 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));
704 return SS_FILE_ERROR;
705 }
706
707 zerror = gzclose(fGzfp);
708 fGzfp = 0;
709
710 if (zerror != Z_OK) {
711 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));
712 return SS_FILE_ERROR;
713 }
714
715 fBytesOut = ss_file_size(log_chn->path.c_str());
716
717 return SUCCESS;
718 }
719
720 std::string wr_get_file_ext()
721 {
722 return ".gz";
723 }
724
725 std::string wr_get_chain()
726 {
727 return "gzip > " + fFilename;
728 }
729
730private:
731 std::string fFilename;
732 gzFile fGzfp;
735};
736
737/*---- pipe writer -------------------------------------------------*/
738
740{
741public:
742 WriterPopen(LOG_CHN* log_chn, const char* pipe_command, const char* file_ext) // ctor
743 {
744 if (fTrace)
745 printf("WriterPopen: path [%s]\n", log_chn->path.c_str());
746 fFp = NULL;
747 fPipeCommand = pipe_command;
748 fFileExt = file_ext;
749 fLastCheckTime = time(NULL);
750 }
751
752 ~WriterPopen() // dtor
753 {
754 if (fTrace)
755 printf("WriterPopen: destructor\n");
756 if (fFp)
757 pclose(fFp);
758 fFp = NULL;
759 }
760
761 int wr_open(LOG_CHN* log_chn, int run_number)
762 {
763 fBytesIn = 0;
764 fBytesOut = 0;
765
766 if (fTrace)
767 printf("WriterPopen: open path [%s] pipe [%s] ext [%s]\n", log_chn->path.c_str(), fPipeCommand.c_str(), fFileExt.c_str());
768
769 assert(fFp == NULL);
770
771 if (check_file_exists(log_chn->path.c_str()))
772 return SS_FILE_EXISTS;
773
774#ifdef OS_WINNT
775 // sorry no popen?!?
776 return SS_FILE_ERROR;
777#else
778 fCommand = fPipeCommand + log_chn->path;
779
780 fFp = popen(fCommand.c_str(), "w");
781 if (fFp == NULL) {
782 cm_msg(MERROR, "WriterPopen::wr_open", "Cannot write to pipe \'%s\', popen() errno %d (%s)", fCommand.c_str(), errno, strerror(errno));
783 return SS_FILE_ERROR;
784 }
785
786 log_chn->handle = 9999;
787
788 return SUCCESS;
789#endif
790 }
791
792 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
793 {
794 if (fTrace)
795 printf("WriterPopen: write path [%s], size %d\n", log_chn->path.c_str(), size);
796
797 if (size == 0)
798 return SUCCESS;
799
800 if (fFp == NULL) {
801 return SS_FILE_ERROR;
802 }
803
804 fBytesIn += size;
805
806 int wr = fwrite(data, 1, size, fFp);
807
808 //if (wr > 0)
809 //fBytesOut += wr;
810
811 if (wr != size) {
812 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));
813
814 if (errno == EPIPE) {
815 cm_msg(MERROR, "WriterPopen::wr_write", "Cannot write to pipe \'%s\': broken pipe, closing the pipe", fCommand.c_str());
816 wr_close(log_chn, 0);
817 }
818
819 return SS_FILE_ERROR;
820 }
821
822 time_t now = time(NULL);
823 if (now - fLastCheckTime > 2) {
824 fLastCheckTime = now;
825 fBytesOut = ss_file_size(log_chn->path.c_str());
826 }
827
828 return SUCCESS;
829 }
830
831 int wr_close(LOG_CHN* log_chn, int run_number)
832 {
833 int err;
834
835 if (fTrace)
836 printf("WriterPopen: close path [%s]\n", log_chn->path.c_str());
837
838 assert(fFp != NULL);
839
840 log_chn->handle = 0;
841
842#ifdef OS_WINNT
843 // sorry no popen?!?
844 return SS_FILE_ERROR;
845#else
846 err = pclose(fFp);
847 fFp = NULL;
848
849 if (err != 0) {
850 cm_msg(MERROR, "WriterPopen::wr_close", "Cannot write to pipe \'%s\', pclose() returned %d, errno %d (%s)", fCommand.c_str(), err, errno, strerror(errno));
851 return SS_FILE_ERROR;
852 }
853
854 chmod(log_chn->path.c_str(), 0444);
855
856 fBytesOut = ss_file_size(log_chn->path.c_str());
857
858 return SUCCESS;
859#endif
860 }
861
862 std::string wr_get_file_ext()
863 {
864 return fFileExt;
865 }
866
867 std::string wr_get_chain()
868 {
869 return fPipeCommand;
870 }
871
872private:
873 FILE* fFp;
874 std::string fPipeCommand;
875 std::string fCommand;
876 std::string fFileExt;
878};
879
880/*---- CRC32-ZLIB computation --------------------------------------*/
881
882#include <zlib.h>
883
885{
886public:
887 WriterCRC32Zlib(LOG_CHN* log_chn, int level, WriterInterface* wr) // ctor
888 {
889 if (fTrace)
890 printf("WriterCRC32Zlib: path [%s], level %d\n", log_chn->path.c_str(), level);
891
892 assert(wr != NULL);
893
894 fLevel = level;
895 fWr = wr;
896 fCrc32 = 0;
897 }
898
900 {
901 if (fTrace)
902 printf("WriterCRC32Zlib: destructor\n");
903 DELETE(fWr);
904 }
905
906 int wr_open(LOG_CHN* log_chn, int run_number)
907 {
908 int status;
909
910 if (fTrace)
911 printf("WriterCRC32Zlib: open path [%s], level %d\n", log_chn->path.c_str(), fLevel);
912
913 status = fWr->wr_open(log_chn, run_number);
914
915 fBytesIn += 0;
917
918 if (status != SUCCESS) {
919 return status;
920 }
921
922 log_chn->handle = 9999;
923
924 fCrc32 = crc32(0, Z_NULL, 0);
925
926 return SUCCESS;
927 }
928
929 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
930 {
931 if (fTrace)
932 printf("WriterCRC32Zlib: write path [%s], size %d\n", log_chn->path.c_str(), size);
933
934 fCrc32 = crc32(fCrc32, (const Bytef*)data, size);
935
936 int status = fWr->wr_write(log_chn, data, size);
937
938 fBytesIn += size;
940
941 if (status != SUCCESS) {
942 return status;
943 }
944
945 return SUCCESS;
946 }
947
948 int wr_close(LOG_CHN* log_chn, int run_number)
949 {
950 std::string x = xpathname(log_chn->path.c_str(), fLevel);
951 std::string f = x + ".crc32zlib";
952
953 if (fTrace)
954 printf("WriterCRC32Zlib: close path [%s], level %d, file [%s]\n", log_chn->path.c_str(), fLevel, f.c_str());
955
956 log_chn->handle = 0;
957
958 cm_msg(MLOG, "CRC32Zlib", "File \'%s\' CRC32-zlib checksum: 0x%08lx, %.0f bytes", x.c_str(), (unsigned long)fCrc32, fBytesIn);
959
960 FILE *fp = fopen_wx(f.c_str());
961 if (!fp) {
962 cm_msg(MERROR, "WriterCRC32Zlib::wr_close", "Cannot write CRC32Zlib to file \'%s\', fopen() errno %d (%s)", f.c_str(), errno, strerror(errno));
963 } else {
964 fprintf(fp, "%08lx %.0f %s\n", (unsigned long)fCrc32, fBytesIn, x.c_str());
965 fclose(fp);
966 }
967
968 /* close downstream writer */
969
970 int status = fWr->wr_close(log_chn, run_number);
971
972 fBytesIn += 0;
974
975 if (status != SUCCESS) {
976 return status;
977 }
978
979 return SUCCESS;
980 }
981
982 std::string wr_get_file_ext() {
983 return fWr->wr_get_file_ext();
984 }
985
986 std::string wr_get_chain() {
987 return "CRC32ZLIB | " + fWr->wr_get_chain();
988 }
989
990private:
993 uLong fCrc32;
994};
995
996/*---- CRC32C computation ------------------------------------------*/
997
998#include "crc32c.h"
999
1001{
1002public:
1003 WriterCRC32C(LOG_CHN* log_chn, int level, WriterInterface* wr) // ctor
1004 {
1005 if (fTrace)
1006 printf("WriterCRC32C: path [%s], level %d\n", log_chn->path.c_str(), level);
1007
1008 assert(wr != NULL);
1009
1010 fLevel = level;
1011 fWr = wr;
1012 fCrc32 = 0;
1013 }
1014
1016 {
1017 if (fTrace)
1018 printf("WriterCRC32C: destructor\n");
1019 DELETE(fWr);
1020 }
1021
1022 int wr_open(LOG_CHN* log_chn, int run_number)
1023 {
1024 int status;
1025
1026 if (fTrace)
1027 printf("WriterCRC32C: open path [%s], level %d\n", log_chn->path.c_str(), fLevel);
1028
1029 status = fWr->wr_open(log_chn, run_number);
1030
1031 fBytesIn += 0;
1033
1034 if (status != SUCCESS) {
1035 return status;
1036 }
1037
1038 log_chn->handle = 9999;
1039
1040 fCrc32 = 0;
1041
1042 return SUCCESS;
1043 }
1044
1045 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
1046 {
1047 if (fTrace)
1048 printf("WriterCRC32C: write path [%s], size %d\n", log_chn->path.c_str(), size);
1049
1050 fCrc32 = crc32c(fCrc32, data, size);
1051
1052 int status = fWr->wr_write(log_chn, data, size);
1053
1054 fBytesIn += size;
1056
1057 if (status != SUCCESS) {
1058 return status;
1059 }
1060
1061 return SUCCESS;
1062 }
1063
1064 int wr_close(LOG_CHN* log_chn, int run_number)
1065 {
1066 std::string x = xpathname(log_chn->path.c_str(), fLevel);
1067 std::string f = x + ".crc32c";
1068
1069 if (fTrace)
1070 printf("WriterCRC32C: close path [%s], level %d, file [%s]\n", log_chn->path.c_str(), fLevel, f.c_str());
1071
1072 log_chn->handle = 0;
1073
1074 cm_msg(MLOG, "CRC32C", "File \'%s\' CRC32C checksum: 0x%08lx, %.0f bytes", x.c_str(), (unsigned long)fCrc32, fBytesIn);
1075
1076 FILE *fp = fopen_wx(f.c_str());
1077 if (!fp) {
1078 cm_msg(MERROR, "WriterCRC32C::wr_close", "Cannot write CRC32C to file \'%s\', fopen() errno %d (%s)", f.c_str(), errno, strerror(errno));
1079 } else {
1080 fprintf(fp, "%08lx %.0f %s\n", (unsigned long)fCrc32, fBytesIn, x.c_str());
1081 fclose(fp);
1082 }
1083
1084 /* close downstream writer */
1085
1086 int status = fWr->wr_close(log_chn, run_number);
1087
1088 fBytesIn += 0;
1090
1091 if (status != SUCCESS) {
1092 return status;
1093 }
1094
1095 return SUCCESS;
1096 }
1097
1098 std::string wr_get_file_ext() {
1099 return fWr->wr_get_file_ext();
1100 }
1101
1102 std::string wr_get_chain() {
1103 return "CRC32C | " + fWr->wr_get_chain();
1104 }
1105
1106private:
1109 uint32_t fCrc32;
1110};
1111
1112/*---- SHA-256 computation -----------------------------------------*/
1113
1114#include "sha256.h"
1115
1117{
1118public:
1119 WriterSHA256(LOG_CHN* log_chn, int level, WriterInterface* wr) // ctor
1120 {
1121 if (fTrace)
1122 printf("WriterSHA256: path [%s], level %d\n", log_chn->path.c_str(), level);
1123
1124 assert(wr != NULL);
1125
1126 fLevel = level;
1127 fWr = wr;
1128
1130 }
1131
1133 {
1134 if (fTrace)
1135 printf("WriterSHA256: destructor\n");
1136 DELETE(fWr);
1137
1139 }
1140
1141 int wr_open(LOG_CHN* log_chn, int run_number)
1142 {
1143 int status;
1144
1145 if (fTrace)
1146 printf("WriterSHA256: open path [%s], level %d\n", log_chn->path.c_str(), fLevel);
1147
1148 status = fWr->wr_open(log_chn, run_number);
1149
1150 fBytesIn += 0;
1152
1153 if (status != SUCCESS) {
1154 return status;
1155 }
1156
1157 log_chn->handle = 9999;
1158
1159 mbedtls_sha256_starts(&fCtx, 0); // 2nd argument selects 0=SHA-256 vs 1=SHA-224
1160
1161 return SUCCESS;
1162 }
1163
1164 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
1165 {
1166 if (fTrace)
1167 printf("WriterSHA256: write path [%s], size %d\n", log_chn->path.c_str(), size);
1168
1169 mbedtls_sha256_update(&fCtx, (const unsigned char*)data, size);
1170
1171 int status = fWr->wr_write(log_chn, data, size);
1172
1173 fBytesIn += size;
1175
1176 if (status != SUCCESS) {
1177 return status;
1178 }
1179
1180 return SUCCESS;
1181 }
1182
1183 std::string toHex(unsigned char c)
1184 {
1185 char s[3];
1186 sprintf(s, "%02x", c);
1187 return s;
1188 }
1189
1190 std::string toString(const unsigned char sha256sum[32])
1191 {
1192 std::string s;
1193 for (int i=0; i<32; i++)
1194 s += toHex(sha256sum[i]);
1195 return s;
1196 }
1197
1198 int wr_close(LOG_CHN* log_chn, int run_number)
1199 {
1200 std::string x = xpathname(log_chn->path.c_str(), fLevel);
1201 std::string f = x + ".sha256";
1202
1203 if (fTrace)
1204 printf("WriterSHA256: close path [%s], level %d, file [%s]\n", log_chn->path.c_str(), fLevel, f.c_str());
1205
1206 log_chn->handle = 0;
1207
1208 unsigned char sha256sum[32];
1209 mbedtls_sha256_finish(&fCtx, sha256sum);
1210
1211 //std::string s = toString(sha256sum);
1212 //printf("sha256 %s\n", s.c_str());
1213
1214 cm_msg(MLOG, "SHA256", "File \'%s\' SHA-256 checksum: %s, %.0f bytes", x.c_str(), toString(sha256sum).c_str(), fBytesIn);
1215
1216 FILE *fp = fopen_wx(f.c_str());
1217 if (!fp) {
1218 cm_msg(MERROR, "WriterSHA256::wr_close", "Cannot write SHA-256 checksum to file \'%s\', fopen() errno %d (%s)", f.c_str(), errno, strerror(errno));
1219 } else {
1220 fprintf(fp, "%s %.0f %s\n", toString(sha256sum).c_str(), fBytesIn, x.c_str());
1221 fclose(fp);
1222 }
1223
1224 /* close downstream writer */
1225
1226 int status = fWr->wr_close(log_chn, run_number);
1227
1228 fBytesIn += 0;
1230
1231 if (status != SUCCESS) {
1232 return status;
1233 }
1234
1235 return SUCCESS;
1236 }
1237
1238 std::string wr_get_file_ext() {
1239 return fWr->wr_get_file_ext();
1240 }
1241
1242 std::string wr_get_chain() {
1243 return "SHA256 | " + fWr->wr_get_chain();
1244 }
1245
1246private:
1250};
1251
1252/*---- SHA-512 computation -----------------------------------------*/
1253
1254#include "sha512.h"
1255
1257{
1258public:
1259 WriterSHA512(LOG_CHN* log_chn, int level, WriterInterface* wr) // ctor
1260 {
1261 if (fTrace)
1262 printf("WriterSHA512: path [%s], level %d\n", log_chn->path.c_str(), level);
1263
1264 assert(wr != NULL);
1265
1266 fLevel = level;
1267 fWr = wr;
1268
1270 }
1271
1273 {
1274 if (fTrace)
1275 printf("WriterSHA512: destructor\n");
1276 DELETE(fWr);
1277
1279 }
1280
1281 int wr_open(LOG_CHN* log_chn, int run_number)
1282 {
1283 int status;
1284
1285 if (fTrace)
1286 printf("WriterSHA512: open path [%s], level %d\n", log_chn->path.c_str(), fLevel);
1287
1288 status = fWr->wr_open(log_chn, run_number);
1289
1290 fBytesIn += 0;
1292
1293 if (status != SUCCESS) {
1294 return status;
1295 }
1296
1297 log_chn->handle = 9999;
1298
1299 mbedtls_sha512_starts(&fCtx, 0); // 2nd argument selects 0=SHA-512 vs 1=SHA-384
1300
1301 return SUCCESS;
1302 }
1303
1304 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
1305 {
1306 if (fTrace)
1307 printf("WriterSHA512: write path [%s], size %d\n", log_chn->path.c_str(), size);
1308
1309 mbedtls_sha512_update(&fCtx, (const unsigned char*)data, size);
1310
1311 int status = fWr->wr_write(log_chn, data, size);
1312
1313 fBytesIn += size;
1315
1316 if (status != SUCCESS) {
1317 return status;
1318 }
1319
1320 return SUCCESS;
1321 }
1322
1323 std::string toHex(unsigned char c)
1324 {
1325 char s[3];
1326 sprintf(s, "%02x", c);
1327 return s;
1328 }
1329
1330 std::string toString(const unsigned char sha512sum[64])
1331 {
1332 std::string s;
1333 for (int i=0; i<64; i++)
1334 s += toHex(sha512sum[i]);
1335 return s;
1336 }
1337
1338 int wr_close(LOG_CHN* log_chn, int run_number)
1339 {
1340 std::string x = xpathname(log_chn->path.c_str(), fLevel);
1341 std::string f = x + ".sha512";
1342
1343 if (fTrace)
1344 printf("WriterSHA512: close path [%s], level %d, file [%s]\n", log_chn->path.c_str(), fLevel, f.c_str());
1345
1346 log_chn->handle = 0;
1347
1348 unsigned char sha512sum[64];
1349 mbedtls_sha512_finish(&fCtx, sha512sum);
1350
1351 //std::string s = toString(sha512sum);
1352 //printf("sha512 %s\n", s.c_str());
1353
1354 cm_msg(MLOG, "SHA512", "File \'%s\' SHA-512 checksum: %s, %.0f bytes", x.c_str(), toString(sha512sum).c_str(), fBytesIn);
1355
1356 FILE *fp = fopen_wx(f.c_str());
1357 if (!fp) {
1358 cm_msg(MERROR, "WriterSHA512::wr_close", "Cannot write SHA-512 checksum to file \'%s\', fopen() errno %d (%s)", f.c_str(), errno, strerror(errno));
1359 } else {
1360 fprintf(fp, "%s %.0f %s\n", toString(sha512sum).c_str(), fBytesIn, x.c_str());
1361 fclose(fp);
1362 }
1363
1364 /* close downstream writer */
1365
1366 int status = fWr->wr_close(log_chn, run_number);
1367
1368 fBytesIn += 0;
1370
1371 if (status != SUCCESS) {
1372 return status;
1373 }
1374
1375 return SUCCESS;
1376 }
1377
1378 std::string wr_get_file_ext() {
1379 return fWr->wr_get_file_ext();
1380 }
1381
1382 std::string wr_get_chain() {
1383 return "SHA512 | " + fWr->wr_get_chain();
1384 }
1385
1386private:
1390};
1391
1392/*---- LZ4 compressed writer --------------------------------------*/
1393
1394#include "mlz4frame.h"
1395
1397{
1398public:
1399 WriterLZ4(LOG_CHN* log_chn, WriterInterface* wr) // ctor
1400 {
1401 if (fTrace)
1402 printf("WriterLZ4: path [%s]\n", log_chn->path.c_str());
1403
1404 assert(wr != NULL);
1405
1406 fBuffer = NULL;
1407 fWr = wr;
1408 fBufferSize = 0;
1409 fBlockSize = 0;
1410 }
1411
1412 ~WriterLZ4() // dtor
1413 {
1414 if (fTrace)
1415 printf("WriterLZ4: destructor\n");
1416
1417 FREE(fBuffer);
1418 DELETE(fWr);
1419 }
1420
1421 int wr_open(LOG_CHN* log_chn, int run_number)
1422 {
1423 int status;
1424 MLZ4F_errorCode_t errorCode;
1425
1426 if (fTrace)
1427 printf("WriterLZ4: open path [%s]\n", log_chn->path.c_str());
1428
1429 status = fWr->wr_open(log_chn, run_number);
1430 if (status != SUCCESS) {
1431 return status;
1432 }
1433
1434 errorCode = MLZ4F_createCompressionContext(&fContext, MLZ4F_VERSION);
1435 if (MLZ4F_isError(errorCode)) {
1436 cm_msg(MERROR, "WriterLZ4::wr_open", "LZ4F_createCompressionContext() error %d (%s)", (int)errorCode, MLZ4F_getErrorName(errorCode));
1437 return SS_FILE_ERROR;
1438 }
1439
1440 MLZ4F_blockSizeID_t blockSizeId = MLZ4F_max4MB;
1441 fBlockSize = 4*1024*1024;
1442 fBufferSize = MLZ4F_compressFrameBound(fBlockSize, NULL);
1443 fBufferSize *= 2; // kludge
1444 fBuffer = (char*)malloc(fBufferSize);
1445 if (fBuffer == NULL) {
1446 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));
1447 return SS_FILE_ERROR;
1448 }
1449
1450 MEMZERO(fPrefs);
1451
1452 fPrefs.compressionLevel = 0; // 0=fast, non-zero=???
1453 fPrefs.autoFlush = 0; // ???
1454 fPrefs.frameInfo.contentChecksumFlag = MLZ4F_contentChecksumEnabled;
1455 fPrefs.frameInfo.blockSizeID = blockSizeId;
1456
1457 size_t headerSize = MLZ4F_compressBegin(fContext, fBuffer, fBufferSize, &fPrefs);
1458
1459 if (MLZ4F_isError(headerSize)) {
1460 errorCode = headerSize;
1461 cm_msg(MERROR, "WriterLZ4::wr_open", "LZ4F_compressBegin() error %d (%s)", (int)errorCode, MLZ4F_getErrorName(errorCode));
1462 return SS_FILE_ERROR;
1463 }
1464
1465 status = fWr->wr_write(log_chn, fBuffer, headerSize);
1466
1467 fBytesIn += 0;
1469
1470 if (status != SUCCESS) {
1471 return SS_FILE_ERROR;
1472 }
1473
1474 log_chn->handle = 9999;
1475
1476 return SUCCESS;
1477 }
1478
1479 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
1480 {
1481 const char* ptr = (const char*)data;
1482 int remaining = size;
1483
1484 if (fTrace)
1485 printf("WriterLZ4: write path [%s], size %d\n", log_chn->path.c_str(), size);
1486
1487 while (remaining > 0) {
1488 int wsize = remaining;
1489
1490 if (wsize > fBlockSize)
1491 wsize = fBlockSize;
1492
1493 size_t outSize = MLZ4F_compressUpdate(fContext, fBuffer, fBufferSize, ptr, wsize, NULL);
1494
1495 if (MLZ4F_isError(outSize)) {
1496 int errorCode = outSize;
1497 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));
1498 return SS_FILE_ERROR;
1499 }
1500
1501 if (outSize > 0) {
1502 int status = fWr->wr_write(log_chn, fBuffer, outSize);
1503
1504 fBytesIn += wsize;
1506
1507 if (status != SUCCESS) {
1508 return SS_FILE_ERROR;
1509 }
1510 }
1511
1512 ptr += wsize;
1513 remaining -= wsize;
1514 }
1515
1516 return SUCCESS;
1517 }
1518
1519 int wr_close(LOG_CHN* log_chn, int run_number)
1520 {
1521 int xstatus = SUCCESS;
1522 MLZ4F_errorCode_t errorCode;
1523
1524 if (fTrace)
1525 printf("WriterLZ4: close path [%s]\n", log_chn->path.c_str());
1526
1527 log_chn->handle = 0;
1528
1529 /* write End of Stream mark */
1530 size_t headerSize = MLZ4F_compressEnd(fContext, fBuffer, fBufferSize, NULL);
1531
1532 if (MLZ4F_isError(headerSize)) {
1533 errorCode = headerSize;
1534 cm_msg(MERROR, "WriterLZ4::wr_close", "LZ4F_compressEnd() error %d (%s)", (int)errorCode, MLZ4F_getErrorName(errorCode));
1535 return SS_FILE_ERROR;
1536 }
1537
1538 int status = fWr->wr_write(log_chn, fBuffer, headerSize);
1539
1540 fBytesIn += 0;
1542
1543 if (status != SUCCESS) {
1544 if (xstatus == SUCCESS)
1545 xstatus = status;
1546 }
1547
1548 /* close downstream writer */
1549
1550 status = fWr->wr_close(log_chn, run_number);
1551
1552 if (status != SUCCESS) {
1553 if (xstatus == SUCCESS)
1554 xstatus = status;
1555 }
1556
1557 /* free resources */
1558
1559 free(fBuffer);
1560 fBuffer = NULL;
1561 fBufferSize = 0;
1562
1563 errorCode = MLZ4F_freeCompressionContext(fContext);
1564 if (MLZ4F_isError(errorCode)) {
1565 cm_msg(MERROR, "WriterLZ4::wr_close", "LZ4F_freeCompressionContext() error %d (%s)", (int)errorCode, MLZ4F_getErrorName(errorCode));
1566 if (xstatus == SUCCESS)
1567 xstatus = SS_FILE_ERROR;
1568 }
1569
1570 return xstatus;
1571 }
1572
1573 std::string wr_get_file_ext() {
1574 return ".lz4" + fWr->wr_get_file_ext();
1575 }
1576
1577 std::string wr_get_chain() {
1578 return "lz4 | " + fWr->wr_get_chain();
1579 }
1580
1581private:
1583 MLZ4F_compressionContext_t fContext;
1584 MLZ4F_preferences_t fPrefs;
1585 char* fBuffer;
1588};
1589
1590/*---- Logging initialization --------------------------------------*/
1591
1593{
1594 INT size, status, delay;
1595 BOOL flag;
1596 HNDLE hKey, hKeyChannel;
1597 KEY key;
1598 std::string str;
1599
1600 /*---- create /logger entries -----*/
1601
1602 str = cm_get_path();
1603 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &str, TRUE);
1604
1605 str = "";
1606 db_get_value_string(hDB, 0, "/Logger/Message dir", 0, &str, TRUE);
1607
1608 str = "";
1609 db_get_value_string(hDB, 0, "/Logger/History dir", 0, &str, TRUE);
1610
1611 str = "";
1612 db_get_value_string(hDB, 0, "/Logger/Message file date format", 0, &str, TRUE);
1613
1614 size = sizeof(BOOL);
1615 flag = TRUE;
1616 db_get_value(hDB, 0, "/Logger/Write data", &flag, &size, TID_BOOL, TRUE);
1617
1618 flag = FALSE;
1619 db_get_value(hDB, 0, "/Logger/ODB Dump", &flag, &size, TID_BOOL, TRUE);
1620
1621 str = "run%05d.json";
1622 db_get_value_string(hDB, 0, "/Logger/ODB Dump File", 0, &str, TRUE);
1623
1624 str = "last.json";
1625 db_get_value_string(hDB, 0, "/Logger/ODB Last Dump File", 0, &str, TRUE);
1626
1627 flag = FALSE;
1628 size = sizeof(BOOL);
1629 db_get_value(hDB, 0, "/Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
1630
1631 delay = 0;
1632 size = sizeof(INT);
1633 db_get_value(hDB, 0, "/Logger/Auto restart delay", &delay, &size, TID_INT32, TRUE);
1634
1635 flag = TRUE;
1636 db_get_value(hDB, 0, "/Logger/Tape message", &flag, &size, TID_BOOL, TRUE);
1637
1638 /* create at least one logging channel */
1639 status = db_find_key(hDB, 0, "/Logger/Channels/0", &hKey);
1640 if (status != DB_SUCCESS) {
1641 /* if no channels are defined, define at least one */
1642 status = db_create_record(hDB, 0, "/Logger/Channels/0", strcomb1(chn_tree_str).c_str());
1643 if (status != DB_SUCCESS)
1644 cm_msg(MERROR, "logger_init", "Cannot create channel entry in database");
1645 } else {
1646 /* check format of other channels */
1647 status = db_find_key(hDB, 0, "/Logger/Channels", &hKey);
1648 if (status == DB_SUCCESS) {
1649 for (int index = 0; ; index++) {
1650 status = db_enum_key(hDB, hKey, index, &hKeyChannel);
1652 break;
1653
1654 db_get_key(hDB, hKeyChannel, &key);
1655 status = db_check_record(hDB, hKey, key.name, strcomb1(chn_tree_str).c_str(), TRUE);
1656 if (status != DB_SUCCESS && status != DB_OPEN_RECORD) {
1657 cm_msg(MERROR, "logger_init", "Cannot create/check channel record %s, db_check_record() status %d", key.name, status);
1658 break;
1659 }
1660 }
1661 }
1662 }
1663#ifdef HAVE_MYSQL
1664 create_runlog_sql_tree();
1665#endif
1668}
1669
1670/*---- ODB dump routine --------------------------------------------*/
1671
1673{
1674 /* write ODB dump */
1675
1676 static int buffer_size = 100000;
1677
1678 do {
1679 EVENT_HEADER* pevent = (EVENT_HEADER *) malloc(buffer_size);
1680 if (pevent == NULL) {
1681 cm_msg(MERROR, "log_odb_dump", "Cannot allocate ODB dump buffer");
1682 break;
1683 }
1684
1685 int size = buffer_size - sizeof(EVENT_HEADER);
1686 //int status = db_copy_xml(hDB, 0, (char *) (pevent + 1), &size);
1687 int status = db_copy(hDB, 0, (char *) (pevent + 1), &size, "");
1688 if (status != DB_TRUNCATED) {
1689 bm_compose_event(pevent, event_id, MIDAS_MAGIC, buffer_size - sizeof(EVENT_HEADER) - size + 1, run_number);
1690 log_write(log_chn, pevent);
1691 free(pevent);
1692 break;
1693 }
1694
1695 /* increase buffer size if truncated */
1696 free(pevent);
1697 buffer_size *= 10;
1698 } while (1);
1699}
1700
1702{
1703 /* write ODB dump */
1704
1705 static int buffer_size = 100000;
1706
1707 do {
1708 EVENT_HEADER* pevent = (EVENT_HEADER *) malloc(buffer_size);
1709 if (pevent == NULL) {
1710 cm_msg(MERROR, "log_odb_dump", "Cannot allocate ODB dump buffer");
1711 break;
1712 }
1713
1714 int size = buffer_size - sizeof(EVENT_HEADER);
1715 int status = db_copy_xml(hDB, 0, (char *) (pevent + 1), &size, true);
1716
1717 /* following line would dump ODB in old ASCII format instead of XML */
1718 //status = db_copy(hDB, 0, (char *) (pevent + 1), &size, "");
1719 if (status != DB_TRUNCATED) {
1721 log_write(log_chn, pevent);
1722 free(pevent);
1723 break;
1724 }
1725
1726 /* increase buffer size if truncated */
1727 free(pevent);
1728 buffer_size *= 10;
1729 } while (1);
1730}
1731
1733{
1734 /* write ODB dump */
1735
1736 char* buffer = NULL;
1737 int buffer_size = 0;
1738 int buffer_end = 0;
1739
1740 int status = db_copy_json_save(hDB, 0, &buffer, &buffer_size, &buffer_end);
1741
1742 //printf("db_copy_json_save: status %d, buffer_size %d, buffer_end %d\n", status, buffer_size, buffer_end);
1743
1744 if (status == DB_SUCCESS) {
1745 int event_size = sizeof(EVENT_HEADER) + buffer_end;
1746 EVENT_HEADER* pevent = (EVENT_HEADER *) malloc(event_size);
1747 if (pevent == NULL) {
1748 cm_msg(MERROR, "log_odb_dump", "Cannot allocate ODB dump buffer size %d", event_size);
1749 } else {
1750 bm_compose_event(pevent, event_id, MIDAS_MAGIC, buffer_end, run_number);
1751 memcpy(pevent+1, buffer, buffer_end);
1752 log_write(log_chn, pevent);
1753 free(pevent);
1754 }
1755 }
1756 free(buffer);
1757}
1758
1759void log_odb_dump(LOG_CHN * log_chn, short int event_id, INT run_number)
1760{
1761 if (equal_ustring(log_chn->settings.odb_dump_format, "odb")) {
1763 } else if (equal_ustring(log_chn->settings.odb_dump_format, "xml")) {
1765 } else if (equal_ustring(log_chn->settings.odb_dump_format, "json")) {
1767 } else {
1768 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());
1769 }
1770}
1771
1772/*---- ODB save routine --------------------------------------------*/
1773
1774void odb_save(const char *filename, bool make_file_readonly)
1775{
1776 std::string path;
1777
1778 if (strchr(filename, DIR_SEPARATOR) == NULL) {
1779 db_get_value_string(hDB, 0, "/Logger/Data Dir", 0, &path, TRUE, 256);
1780 if (path.length() > 0) {
1781 if (!ends_with_char(path, DIR_SEPARATOR)) {
1782 path += DIR_SEPARATOR_STR;
1783 }
1784 }
1785 path += filename;
1786 } else {
1787 path = filename;
1788 }
1789
1790 //printf("filename [%s] path [%s]\n", filename, path.c_str());
1791
1792 DWORD t0 = ss_millitime();
1793
1794 if (ends_with_ustring(filename, ".xml"))
1795 db_save_xml(hDB, 0, path.c_str());
1796 else if (ends_with_ustring(filename, ".json"))
1797 db_save_json(hDB, 0, path.c_str());
1798 else
1799 db_save(hDB, 0, path.c_str(), FALSE);
1800
1801 if (make_file_readonly)
1802 chmod(path.c_str(), 0444);
1803
1804 DWORD te = ss_millitime();
1805
1806 if (verbose)
1807 printf("saved odb to \"%s\" in %d ms\n", path.c_str(), te-t0);
1808}
1809
1810
1811#ifdef HAVE_MYSQL
1812
1813static void xwrite(const char* filename, int fd, const void* data, int size)
1814{
1815 int wr = write(fd, data, size);
1816 if (wr != size) {
1817 cm_msg(MERROR, "xwrite", "cannot write to \'%s\', write(%d) returned %d, errno %d (%s)", filename, size, wr, errno, strerror(errno));
1818 }
1819}
1820
1821/*==== SQL routines ================================================*/
1822
1823/*---- Convert ctime() type date/time to SQL 'datetime' ------------*/
1824
1825typedef struct {
1826 char column_name[NAME_LENGTH];
1827 char column_type[NAME_LENGTH];
1828 char data[256];
1829} SQL_LIST;
1830
1831static const char *mname[] = {
1832 "January",
1833 "February",
1834 "March",
1835 "April",
1836 "May",
1837 "June",
1838 "July",
1839 "August",
1840 "September",
1841 "October",
1842 "November",
1843 "December"
1844};
1845
1846void ctime_to_datetime(char *date)
1847{
1848 char ctime_date[30];
1849 struct tm tms;
1850 int i;
1851
1852 mstrlcpy(ctime_date, date, sizeof(ctime_date));
1853 memset(&tms, 0, sizeof(struct tm));
1854
1855 for (i = 0; i < 12; i++)
1856 if (strncmp(ctime_date + 4, mname[i], 3) == 0)
1857 break;
1858 tms.tm_mon = i;
1859
1860 tms.tm_mday = atoi(ctime_date + 8);
1861 tms.tm_hour = atoi(ctime_date + 11);
1862 tms.tm_min = atoi(ctime_date + 14);
1863 tms.tm_sec = atoi(ctime_date + 17);
1864 tms.tm_year = atoi(ctime_date + 20) - 1900;
1865 tms.tm_isdst = -1;
1866
1867 if (tms.tm_year < 90)
1868 tms.tm_year += 100;
1869
1870 ss_mktime(&tms);
1871 sprintf(date, "%d-%02d-%02d %02d-%02d-%02d",
1872 tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday, tms.tm_hour, tms.tm_min, tms.tm_sec);
1873}
1874
1875/*---- mySQL debugging output --------------------------------------*/
1876
1877int mysql_query_debug(MYSQL * db, const char *query)
1878{
1879 int status, fh;
1880 std::string filename;
1881 std::string path;
1882 std::string dir;
1883 HNDLE hKey;
1884
1885 /* comment in this line if you need debugging output */
1886 //cm_msg(MINFO, "mysql_query_debug", "SQL query: %s", query);
1887
1888 /* write query into logfile if requested */
1889 filename = "";
1890 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Logfile", 0, &filename, TRUE);
1891 if (!filename.empty()) {
1892 status = db_find_key(hDB, 0, "/Logger/Data dir", &hKey);
1893 if (status == DB_SUCCESS) {
1894 dir = "";
1895 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &dir, TRUE);
1896 if (!dir.empty())
1897 if (dir.back() != DIR_SEPARATOR)
1898 dir += DIR_SEPARATOR_STR;
1899
1900 path = dir + filename;
1901 } else {
1902 std::string dir = cm_get_path();
1903 if (!dir.empty())
1904 if (dir.back() != DIR_SEPARATOR)
1905 dir += DIR_SEPARATOR_STR;
1906
1907 path = dir + filename;
1908 }
1909
1910 fh = open(path.c_str(), O_WRONLY | O_CREAT | O_APPEND | O_LARGEFILE, 0644);
1911 if (fh < 0) {
1912 printf("Cannot open message log file \'%s\', open() returned %d, errno %d (%s)\n", path.c_str(),
1913 fh, errno, strerror(errno));
1914 } else {
1915 xwrite(path.c_str(), fh, query, strlen(query));
1916 xwrite(path.c_str(), fh, ";\n", 2);
1917 close(fh);
1918 }
1919 }
1920
1921 /* execut sql query */
1922 status = mysql_query(db, query);
1923
1924 if (status)
1925 cm_msg(MERROR, "mysql_query_debug", "SQL error: %s", mysql_error(db));
1926
1927 return status;
1928}
1929
1930/*---- Retrieve list of columns from ODB tree ----------------------*/
1931
1932int sql_get_columns(HNDLE hKeyRoot, SQL_LIST ** sql_list)
1933{
1934 HNDLE hKey;
1935 int n, i, status;
1936 KEY key;
1937
1938 for (i = 0;; i++) {
1939 status = db_enum_key(hDB, hKeyRoot, i, &hKey);
1941 break;
1942 }
1943
1944 if (i == 0)
1945 return 0;
1946
1947 n = i;
1948
1949 *sql_list = (SQL_LIST *) malloc(sizeof(SQL_LIST) * n);
1950
1951 for (i = 0; i < n; i++) {
1952
1953 /* get name of link, NOT of link target */
1954 db_enum_link(hDB, hKeyRoot, i, &hKey);
1955 db_get_link(hDB, hKey, &key);
1956 mstrlcpy((*sql_list)[i].column_name, key.name, NAME_LENGTH);
1957
1958 /* get key */
1959 db_enum_key(hDB, hKeyRoot, i, &hKey);
1960 db_get_key(hDB, hKey, &key);
1961
1962 /* get key data */
1963 int size = key.total_size;
1964 char* data = (char*)malloc(size);
1965 assert(data);
1966 db_get_data(hDB, hKey, data, &size, key.type);
1967 char str[1000];
1968 std::string s = db_sprintf(data, size, 0, key.type);
1969 mstrlcpy(str, s.c_str(), sizeof(str));
1970 //printf("AAA key %s size %d %d [%s]\n", key.name, key.total_size, (int)strlen(str), str);
1971 assert(strlen(str) < sizeof(str));
1972 free(data);
1973 if (key.type == TID_BOOL)
1974 strcpy((*sql_list)[i].data, str[0] == 'y' || str[0] == 'Y' ? "1" : "0");
1975 else
1976 strcpy((*sql_list)[i].data, str);
1977
1978 if (key.type == TID_STRING) {
1979 /* check if string is date/time */
1980 if (strlen(str) == 24 && str[10] == ' ' && str[13] == ':') {
1981 strcpy(str, "DATETIME");
1982 ctime_to_datetime((*sql_list)[i].data);
1983 } else if (key.item_size < 256)
1984 sprintf(str, "VARCHAR (%d)", key.item_size);
1985 else
1986 sprintf(str, " TEXT");
1987
1988 } else {
1989 switch (key.type) {
1990 case TID_UINT8:
1991 strcpy(str, "TINYINT UNSIGNED ");
1992 break;
1993 case TID_INT8:
1994 strcpy(str, "TINYINT ");
1995 break;
1996 case TID_CHAR:
1997 strcpy(str, "CHAR ");
1998 break;
1999 case TID_UINT16:
2000 strcpy(str, "SMALLINT UNSIGNED ");
2001 break;
2002 case TID_INT16:
2003 strcpy(str, "SMALLINT ");
2004 break;
2005 case TID_UINT32:
2006 strcpy(str, "INT UNSIGNED ");
2007 break;
2008 case TID_INT32:
2009 strcpy(str, "INT ");
2010 break;
2011 case TID_BOOL:
2012 strcpy(str, "BOOLEAN ");
2013 break;
2014 case TID_FLOAT:
2015 strcpy(str, "FLOAT ");
2016 break;
2017 case TID_DOUBLE:
2018 strcpy(str, "DOUBLE ");
2019 break;
2020 default:
2021 cm_msg(MERROR, "sql_create_database",
2022 "No SQL type mapping for key \"%s\" of type %s", key.name, rpc_tid_name(key.type));
2023 }
2024 }
2025
2026 strcpy((*sql_list)[i].column_type, str);
2027 }
2028
2029 return n;
2030}
2031
2032/*---- Create mySQL table from ODB tree ----------------------------*/
2033
2034BOOL sql_create_table(MYSQL * db, char *database, char *table, HNDLE hKeyRoot)
2035{
2036 SQL_LIST *sql_list;
2037
2038 std::string query = msprintf("CREATE TABLE `%s`.`%s` (", database, table);
2039
2040 int n_col = sql_get_columns(hKeyRoot, &sql_list);
2041 if (n_col == 0) {
2042 std::string path = db_get_path(hDB, hKeyRoot);
2043 cm_msg(MERROR, "sql_create_database", "ODB tree \"%s\" contains no variables", path.c_str());
2044 return FALSE;
2045 }
2046
2047 for (int i = 0; i < n_col; i++) {
2048 query += msprintf("`%s` %s NOT NULL, ", sql_list[i].column_name, sql_list[i].column_type);
2049 }
2050
2051 query += msprintf("PRIMARY KEY (`%s`))", sql_list[0].column_name);
2052 free(sql_list);
2053
2054 if (mysql_query_debug(db, query.c_str())) {
2055 cm_msg(MERROR, "sql_create_table", "Failed to create table: Error: %s", mysql_error(db));
2056 return FALSE;
2057 }
2058
2059 return TRUE;
2060}
2061
2062/*---- Create mySQL table from ODB tree ----------------------------*/
2063
2064BOOL sql_modify_table(MYSQL * db, char *database, char *table, HNDLE hKeyRoot)
2065{
2066 SQL_LIST *sql_list;
2067
2068 int n_col = sql_get_columns(hKeyRoot, &sql_list);
2069 if (n_col == 0) {
2070 std::string path = db_get_path(hDB, hKeyRoot);
2071 cm_msg(MERROR, "sql_modify_table", "ODB tree \"%s\" contains no variables", path.c_str());
2072 return FALSE;
2073 }
2074
2075 for (int i = 0; i < n_col; i++) {
2076 std::string query;
2077
2078 /* try to add column */
2079 if (i == 0) {
2080 query = msprintf("ALTER TABLE `%s`.`%s` ADD `%s` %s", database, table, sql_list[i].column_name, sql_list[i].column_type);
2081 } else {
2082 query = msprintf("ALTER TABLE `%s`.`%s` ADD `%s` %s AFTER `%s`",
2083 database, table,
2084 sql_list[i].column_name,
2085 sql_list[i].column_type,
2086 sql_list[i - 1].column_name);
2087 }
2088
2089 if (mysql_query_debug(db, query.c_str())) {
2090 if (mysql_errno(db) == ER_DUP_FIELDNAME) {
2091
2092 /* try to modify column */
2093 query = msprintf("ALTER TABLE `%s`.`%s` MODIFY `%s` %s", database, table, sql_list[i].column_name, sql_list[i].column_type);
2094
2095 if (mysql_query_debug(db, query.c_str())) {
2096 free(sql_list);
2097 cm_msg(MERROR, "sql_modify_table", "Failed to modify column: Error: %s", mysql_error(db));
2098 return FALSE;
2099 }
2100
2101 } else {
2102 free(sql_list);
2103 cm_msg(MERROR, "sql_modify_table", "Failed to add column: Error: %s", mysql_error(db));
2104 return FALSE;
2105 }
2106 }
2107 }
2108
2109 cm_msg(MINFO, "sql_insert", "SQL table '%s.%s' modified successfully", database, table);
2110
2111 return TRUE;
2112}
2113
2114/*---- Create mySQL database ---------------------------------------*/
2115
2116BOOL sql_create_database(MYSQL * db, const char *database)
2117{
2118 std::string query = msprintf("CREATE DATABASE `%s`", database);
2119 if (mysql_query_debug(db, query.c_str())) {
2120 cm_msg(MERROR, "sql_create_database", "Failed to create database: Error: %s", mysql_error(db));
2121 return FALSE;
2122 }
2123
2124 /* select database */
2125 query = msprintf("USE `%s`", database);
2126 if (mysql_query_debug(db, query.c_str())) {
2127 cm_msg(MERROR, "sql_create_database", "Failed to select database: Error: %s", mysql_error(db));
2128 return FALSE;
2129 }
2130
2131 return TRUE;
2132}
2133
2134/*---- Insert table row from ODB tree ------------------------------*/
2135
2136int sql_insert(MYSQL * db, char *database, char *table, HNDLE hKeyRoot, BOOL create_flag)
2137{
2138 SQL_LIST *sql_list;
2139
2140 /*
2141 build SQL query in the form
2142 "INSERT INTO `<table>` (`<name>`, <name`,..) VALUES (`<value>`, `value`, ...)
2143 */
2144 std::string query = msprintf("INSERT INTO `%s`.`%s` (", database, table);
2145 int n_col = sql_get_columns(hKeyRoot, &sql_list);
2146 if (n_col == 0)
2147 return DB_SUCCESS;
2148
2149 for (int i = 0; i < n_col; i++) {
2150 query += msprintf("`%s`", sql_list[i].column_name);
2151 if (i < n_col - 1) {
2152 query += ", ";
2153 }
2154 }
2155
2156 query += ") VALUES (";
2157
2158 for (int i = 0; i < n_col; i++) {
2159 query += "'";
2160
2161 size_t len = strlen(sql_list[i].data);
2162 char str[len*2+1];
2163 mysql_escape_string(str, sql_list[i].data, len);
2164 query += str;
2165 query += "'";
2166
2167 if (i < n_col - 1) {
2168 query += ", ";
2169 }
2170 }
2171
2172 free(sql_list);
2173 sql_list = NULL;
2174 query += ")";
2175 if (mysql_query_debug(db, query.c_str())) {
2176
2177 /* if entry for this run exists alreay return */
2178 if (mysql_errno(db) == ER_DUP_ENTRY) {
2179
2180 return ER_DUP_ENTRY;
2181
2182 } else if (mysql_errno(db) == ER_NO_SUCH_TABLE && create_flag) {
2183
2184 /* if table does not exist, creat it and try again */
2185 sql_create_table(db, database, table, hKeyRoot);
2186 if (mysql_query_debug(db, query.c_str())) {
2187 cm_msg(MERROR, "sql_insert", "Failed to update database: Error: %s", mysql_error(db));
2188 return mysql_errno(db);
2189 }
2190 cm_msg(MINFO, "sql_insert", "SQL table '%s.%s' created successfully", database, table);
2191
2192 } else if (mysql_errno(db) == ER_BAD_FIELD_ERROR && create_flag) {
2193
2194 /* if table structure is different, adjust it and try again */
2195 sql_modify_table(db, database, table, hKeyRoot);
2196 if (mysql_query_debug(db, query.c_str())) {
2197 cm_msg(MERROR, "sql_insert", "Failed to update database: Error: %s", mysql_error(db));
2198 return mysql_errno(db);
2199 }
2200
2201 } else {
2202 int status = mysql_errno(db);
2203 cm_msg(MERROR, "sql_insert", "Failed to update database: Errno: %d, Error: %s", status, mysql_error(db));
2204 return mysql_errno(db);
2205 }
2206 }
2207
2208 return DB_SUCCESS;
2209}
2210
2211/*---- Update table row from ODB tree ------------------------------*/
2212
2213int sql_update(MYSQL * db, char *database, char *table, HNDLE hKeyRoot, BOOL create_flag, char *where)
2214{
2215 SQL_LIST *sql_list;
2216
2217 /*
2218 build SQL query in the form
2219 "UPDATE `<database`.`<table>` SET `<name>`='<value', ... WHERE `<name>`='value'
2220 */
2221
2222 std::string query = msprintf("UPDATE `%s`.`%s` SET ", database, table);
2223 int n_col = sql_get_columns(hKeyRoot, &sql_list);
2224 if (n_col == 0)
2225 return DB_SUCCESS;
2226
2227 for (int i = 0; i < n_col; i++) {
2228 size_t len = strlen(sql_list[i].data);
2229 char str[2*len+1]; // see https://dev.mysql.com/doc/c-api/8.0/en/mysql-real-escape-string.html
2230 mysql_escape_string(str, sql_list[i].data, len);
2231 query += msprintf("`%s`='%s'", sql_list[i].column_name, str);
2232 if (i < n_col - 1) {
2233 query += ", ";
2234 }
2235 }
2236 free(sql_list);
2237 sql_list = NULL;
2238
2239 query += msprintf(" %s", where);
2240 if (mysql_query_debug(db, query.c_str())) {
2241 if (mysql_errno(db) == ER_NO_SUCH_TABLE && create_flag) {
2242
2243 /* if table does not exist, creat it and try again */
2244 sql_create_table(db, database, table, hKeyRoot);
2245 return sql_insert(db, database, table, hKeyRoot, create_flag);
2246
2247 } else if (mysql_errno(db) == ER_BAD_FIELD_ERROR && create_flag) {
2248
2249 /* if table structure is different, adjust it and try again */
2250 sql_modify_table(db, database, table, hKeyRoot);
2251 if (mysql_query_debug(db, query.c_str())) {
2252 cm_msg(MERROR, "sql_update", "Failed to update database: Error: %s", mysql_error(db));
2253 return mysql_errno(db);
2254 }
2255
2256 } else {
2257 cm_msg(MERROR, "sql_update", "Failed to update database: Error: %s", mysql_error(db));
2258 return mysql_errno(db);
2259 }
2260 }
2261
2262 return DB_SUCCESS;
2263}
2264
2265/*---- Create /Logger/Runlog/SQL tree ------------------------------*/
2266
2267void create_runlog_sql_tree()
2268{
2269 char hostname[80], username[80], password[80], table[80], filename[80];
2270 int size, write_flag, create_flag;
2271 HNDLE hKeyRoot, hKey;
2272
2273 size = sizeof(create_flag);
2274 create_flag = 0;
2275 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Create database", &create_flag, &size, TID_BOOL, TRUE);
2276
2277 size = sizeof(write_flag);
2278 write_flag = 0;
2279 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Write data", &write_flag, &size, TID_BOOL, TRUE);
2280
2281 size = sizeof(hostname);
2282 strcpy(hostname, "localhost");
2283 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Hostname", hostname, &size, TID_STRING, TRUE);
2284
2285 size = sizeof(username);
2286 strcpy(username, "root");
2287 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Username", username, &size, TID_STRING, TRUE);
2288
2289 size = sizeof(password);
2290 password[0] = 0;
2291 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Password", password, &size, TID_STRING, TRUE);
2292
2293 /* use experiment name as default database name */
2294 std::string database;
2295 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &database, TRUE);
2296 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Database", 0, &database, TRUE);
2297
2298 size = sizeof(table);
2299 strcpy(table, "Runlog");
2300 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Table", table, &size, TID_STRING, TRUE);
2301
2302 size = sizeof(filename);
2303 strcpy(filename, "sql.log");
2304 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Logfile", filename, &size, TID_STRING, TRUE);
2305
2306 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links BOR", &hKeyRoot);
2307 if (!hKeyRoot) {
2308 /* create some default links */
2309 db_create_key(hDB, 0, "/Logger/Runlog/SQL/Links BOR", TID_KEY);
2310
2311 if (db_find_key(hDB, 0, "/Runinfo/Run number", &hKey) == DB_SUCCESS)
2312 db_create_link(hDB, 0, "/Logger/Runlog/SQL/Links BOR/Run number", "/Runinfo/Run number");
2313
2314 if (db_find_key(hDB, 0, "/Experiment/Run parameters/Comment", &hKey) == DB_SUCCESS)
2315 db_create_link(hDB, 0, "/Logger/Runlog/SQL/Links BOR/Comment", "/Experiment/Run parameters/Comment");
2316
2317 if (db_find_key(hDB, 0, "/Runinfo/Start time", &hKey) == DB_SUCCESS)
2318 db_create_link(hDB, 0, "/Logger/Runlog/SQL/Links BOR/Start time", "/Runinfo/Start time");
2319 }
2320
2321 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links EOR", &hKeyRoot);
2322 if (!hKeyRoot) {
2323 /* create some default links */
2324 db_create_key(hDB, 0, "/Logger/Runlog/SQL/Links EOR", TID_KEY);
2325
2326 if (db_find_key(hDB, 0, "/Runinfo/Stop time", &hKey) == DB_SUCCESS)
2327 db_create_link(hDB, 0, "/Logger/Runlog/SQL/Links EOR/Stop time", "/Runinfo/Stop time");
2328
2329 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/Events sent", &hKey) == DB_SUCCESS)
2330 db_create_link(hDB, 0, "/Logger/Runlog/SQL/Links EOR/Number of events",
2331 "/Equipment/Trigger/Statistics/Events sent");
2332
2333 }
2334}
2335
2336/*---- Write ODB tree to SQL table ---------------------------------*/
2337
2338void write_runlog_sql(BOOL bor)
2339{
2340 MYSQL db;
2341 char hostname[80], username[80], password[80], database[80], table[80], query[5000], where[500];
2342 int status, size, write_flag, create_flag;
2343 BOOL insert;
2344 HNDLE hKey, hKeyRoot;
2345 SQL_LIST *sql_list;
2346
2347 /* do not update SQL if logger does not write data */
2348 size = sizeof(BOOL);
2349 write_flag = FALSE;
2350 db_get_value(hDB, 0, "/Logger/Write data", &write_flag, &size, TID_BOOL, TRUE);
2351 if (!write_flag)
2352 return;
2353
2354 /* insert SQL on bor, else update */
2355 insert = bor;
2356
2357 /* determine primary key */
2358 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links BOR", &hKeyRoot);
2359 status = db_enum_link(hDB, hKeyRoot, 0, &hKey);
2360
2361 /* if BOR list empty, take first one from EOR list */
2362 if (status == DB_NO_MORE_SUBKEYS) {
2363 insert = TRUE;
2364 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links EOR", &hKeyRoot);
2365 status = db_enum_link(hDB, hKeyRoot, 0, &hKey);
2367 return;
2368 }
2369
2370 sql_get_columns(hKeyRoot, &sql_list);
2371 sprintf(where, "WHERE `%s`='%s'", sql_list[0].column_name, sql_list[0].data);
2372 free(sql_list);
2373 sql_list = NULL;
2374
2375 /* get BOR or EOR list */
2376 if (bor) {
2377 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links BOR", &hKeyRoot);
2378 if (!hKeyRoot) {
2379 cm_msg(MERROR, "write_runlog_sql", "Cannot find \"/Logger/Runlog/SQL/Links BOR");
2380 return;
2381 }
2382 } else {
2383 db_find_key(hDB, 0, "/Logger/Runlog/SQL/Links EOR", &hKeyRoot);
2384 if (!hKeyRoot) {
2385 cm_msg(MERROR, "write_runlog_sql", "Cannot find \"/Logger/Runlog/SQL/Links EOR");
2386 return;
2387 }
2388 }
2389
2390 size = sizeof(create_flag);
2391 create_flag = 0;
2392 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Create database", &create_flag, &size, TID_BOOL, TRUE);
2393
2394 size = sizeof(write_flag);
2395 write_flag = 0;
2396 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Write data", &write_flag, &size, TID_BOOL, TRUE);
2397
2398 size = sizeof(hostname);
2399 strcpy(hostname, "localhost");
2400 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Hostname", hostname, &size, TID_STRING, TRUE);
2401
2402 size = sizeof(username);
2403 strcpy(username, "root");
2404 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Username", username, &size, TID_STRING, TRUE);
2405
2406 size = sizeof(password);
2407 password[0] = 0;
2408 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Password", password, &size, TID_STRING, TRUE);
2409
2410 /* use experiment name as default database name */
2411 size = sizeof(database);
2412 db_get_value(hDB, 0, "/Experiment/Name", database, &size, TID_STRING, TRUE);
2413 size = sizeof(database);
2414 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Database", database, &size, TID_STRING, TRUE);
2415
2416 size = sizeof(table);
2417 strcpy(table, "Runlog");
2418 db_get_value(hDB, 0, "/Logger/Runlog/SQL/Table", table, &size, TID_STRING, TRUE);
2419
2420 /* continue only if data should be written */
2421 if (!write_flag)
2422 return;
2423
2424 /* connect to MySQL database */
2425 mysql_init(&db);
2426
2427 if (!mysql_real_connect(&db, hostname, username, password, NULL, 0, NULL, 0)) {
2428 cm_msg(MERROR, "write_runlog_sql", "Failed to connect to database: Error: %s", mysql_error(&db));
2429 mysql_close(&db);
2430 return;
2431 }
2432
2433 /* select database */
2434 sprintf(query, "USE `%s`", database);
2435 if (mysql_query_debug(&db, query)) {
2436
2437 /* create database if selected */
2438 if (create_flag) {
2439 if (!sql_create_database(&db, database)) {
2440 mysql_close(&db);
2441 return;
2442 }
2443 cm_msg(MINFO, "write_runlog_sql", "Database \"%s\" created successfully", database);
2444
2445 } else {
2446 cm_msg(MERROR, "write_runlog_sql", "Failed to select database: Error: %s", mysql_error(&db));
2447 mysql_close(&db);
2448 return;
2449 }
2450 }
2451
2452 if (insert) {
2453 status = sql_insert(&db, database, table, hKeyRoot, create_flag);
2454 if (status == ER_DUP_ENTRY)
2455 sql_update(&db, database, table, hKeyRoot, create_flag, where);
2456 } else
2457 sql_update(&db, database, table, hKeyRoot, create_flag, where);
2458
2459 mysql_close(&db);
2460}
2461
2462#endif // HAVE_MYSQL
2463
2464/*---- Create /Logger/Runlog/ASCII tree ----------------------------*/
2465
2467{
2468 std::string filename;
2469 int size, write_flag;
2470 HNDLE hKeyRoot, hKey;
2471
2472 size = sizeof(write_flag);
2473 write_flag = 0;
2474 db_get_value(hDB, 0, "/Logger/Runlog/ASCII/Write data", &write_flag, &size, TID_BOOL, TRUE);
2475
2476 filename = "runlog.log";
2477 db_get_value_string(hDB, 0, "/Logger/Runlog/ASCII/Filename", 0, &filename, TRUE);
2478
2479 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", &hKeyRoot);
2480 if (!hKeyRoot) {
2481 /* create some default links */
2482 db_create_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", TID_KEY);
2483
2484 if (db_find_key(hDB, 0, "/Runinfo/Run number", &hKey) == DB_SUCCESS)
2485 db_create_link(hDB, 0, "/Logger/Runlog/ASCII/Links BOR/Run number", "/Runinfo/Run number");
2486
2487 if (db_find_key(hDB, 0, "/Experiment/Run parameters/Comment", &hKey) == DB_SUCCESS)
2488 db_create_link(hDB, 0, "/Logger/Runlog/ASCII/Links BOR/Comment", "/Experiment/Run parameters/Comment");
2489
2490 if (db_find_key(hDB, 0, "/Runinfo/Start time", &hKey) == DB_SUCCESS)
2491 db_create_link(hDB, 0, "/Logger/Runlog/ASCII/Links BOR/Start time", "/Runinfo/Start time");
2492 }
2493
2494 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", &hKeyRoot);
2495 if (!hKeyRoot) {
2496 /* create some default links */
2497 db_create_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", TID_KEY);
2498
2499 if (db_find_key(hDB, 0, "/Runinfo/Stop time", &hKey) == DB_SUCCESS)
2500 db_create_link(hDB, 0, "/Logger/Runlog/ASCII/Links EOR/Stop time", "/Runinfo/Stop time");
2501
2502 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/Events sent", &hKey) == DB_SUCCESS)
2503 db_create_link(hDB, 0, "/Logger/Runlog/ASCII/Links EOR/Number of events",
2504 "/Equipment/Trigger/Statistics/Events sent");
2505
2506 }
2507}
2508
2509/*---- Write ODB tree to ASCII log file ----------------------------*/
2510
2512{
2513 char filename[256], dir[256], path[256];
2514 int status, size, write_flag;
2515 HNDLE hKey, hKeyRoot;
2516
2517 /* do not update runlog if logger does not write data */
2518 size = sizeof(BOOL);
2519 write_flag = FALSE;
2520 db_get_value(hDB, 0, "/Logger/Write data", &write_flag, &size, TID_BOOL, TRUE);
2521 if (!write_flag)
2522 return;
2523
2524 /* get BOR or EOR list */
2525 if (bor) {
2526 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", &hKeyRoot);
2527 if (!hKeyRoot) {
2528 cm_msg(MERROR, "write_runlog_ascii", "Cannot find \"/Logger/Runlog/ASCII/Links BOR");
2529 return;
2530 }
2531 } else {
2532 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", &hKeyRoot);
2533 if (!hKeyRoot) {
2534 cm_msg(MERROR, "write_runlog_ascii", "Cannot find \"/Logger/Runlog/ASCII/Links EOR");
2535 return;
2536 }
2537 }
2538
2539 size = sizeof(write_flag);
2540 write_flag = 0;
2541 db_get_value(hDB, 0, "/Logger/Runlog/ASCII/Write data", &write_flag, &size, TID_BOOL, TRUE);
2542
2543 size = sizeof(filename);
2544 strcpy(filename, "runlog.log");
2545 db_get_value(hDB, 0, "/Logger/Runlog/ASCII/Filename", filename, &size, TID_STRING, TRUE);
2546
2547 if (strchr(filename, DIR_SEPARATOR) == NULL) {
2548 size = sizeof(dir);
2549 dir[0] = 0;
2550 db_get_value(hDB, 0, "/Logger/Message Dir", dir, &size, TID_STRING, TRUE);
2551 if (dir[0] != 0)
2552 if (dir[strlen(dir) - 1] != DIR_SEPARATOR)
2553 strcat(dir, DIR_SEPARATOR_STR);
2554 strcpy(path, dir);
2555 strcat(path, filename);
2556 } else
2557 strcpy(path, filename);
2558
2559 /* continue only if data should be written */
2560 if (!write_flag)
2561 return;
2562
2563 FILE *f = fopen(path, "r");
2564 if (f == NULL) {
2565 // create new file
2566 f = fopen(path, "wt");
2567
2568 assert(f != NULL);
2569
2570 // write column header line with variable names
2571 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", &hKeyRoot);
2572 for (int i = 0;; i++) {
2573 status = db_enum_key(hDB, hKeyRoot, i, &hKey);
2575 break;
2576 KEY key;
2577 db_get_key(hDB, hKey, &key);
2578 fprintf(f, "%s\t", key.name);
2579 }
2580 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", &hKeyRoot);
2581 for (int i = 0;; i++) {
2582 status = db_enum_key(hDB, hKeyRoot, i, &hKey);
2584 break;
2585 KEY key;
2586 db_get_key(hDB, hKey, &key);
2587 fprintf(f, "%s\t", key.name);
2588 }
2589 fprintf(f, "\n");
2590 fclose(f);
2591 }
2592
2593 // append data to logfile
2594 f = fopen(path, "at");
2595
2596 assert(f != NULL);
2597
2598 if (bor)
2599 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links BOR", &hKeyRoot);
2600 else
2601 db_find_key(hDB, 0, "/Logger/Runlog/ASCII/Links EOR", &hKeyRoot);
2602
2603 for (int i = 0;; i++) {
2604 status = db_enum_key(hDB, hKeyRoot, i, &hKey);
2606 break;
2607 KEY key;
2608 db_get_key(hDB, hKey, &key);
2609 int size = key.total_size;
2610 char* data = (char*)malloc(size);
2611 assert(data);
2612 db_get_data(hDB, hKey, data, &size, key.type);
2613 std::string str = db_sprintf(data, size, 0, key.type);
2614 //printf("BBB key %s size %d %d [%s]\n", key.name, size, (int)strlen(str), str);
2615 free(data);
2616 fprintf(f, "%s\t", str.c_str());
2617 }
2618 if (!bor)
2619 fprintf(f, "\n");
2620 fclose(f);
2621}
2622
2623/*---- Create /Logger/Runlog/JSON tree ----------------------------*/
2624
2626{
2627 char dirname[256];
2628 int size, write_flag;
2629 HNDLE hKeyRoot, hKey;
2630
2631 size = sizeof(write_flag);
2632 write_flag = 0;
2633 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Write data", &write_flag, &size, TID_BOOL, TRUE);
2634
2635 size = sizeof(dirname);
2636 strcpy(dirname, "runlogs");
2637 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Subdir", dirname, &size, TID_STRING, TRUE);
2638
2639 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", &hKeyRoot);
2640 if (!hKeyRoot) {
2641 /* create some default links */
2642 db_create_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", TID_KEY);
2643
2644 if (db_find_key(hDB, 0, "/Runinfo/Run number", &hKey) == DB_SUCCESS)
2645 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links BOR/Run number", "/Runinfo/Run number");
2646
2647 if (db_find_key(hDB, 0, "/Experiment/Run parameters/Comment", &hKey) == DB_SUCCESS)
2648 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links BOR/Comment", "/Experiment/Run parameters/Comment");
2649
2650 if (db_find_key(hDB, 0, "/Runinfo/Start time", &hKey) == DB_SUCCESS)
2651 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links BOR/Start time", "/Runinfo/Start time");
2652 }
2653
2654 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", &hKeyRoot);
2655 if (!hKeyRoot) {
2656 /* create some default links */
2657 db_create_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", TID_KEY);
2658
2659 if (db_find_key(hDB, 0, "/Runinfo/Stop time", &hKey) == DB_SUCCESS)
2660 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links EOR/Stop time", "/Runinfo/Stop time");
2661
2662 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/Events sent", &hKey) == DB_SUCCESS)
2663 db_create_link(hDB, 0, "/Logger/Runlog/JSON/Links EOR/Number of events",
2664 "/Equipment/Trigger/Statistics/Events sent");
2665
2666 }
2667}
2668
2669
2670/*---- Write ODB tree to JSON log file (one per run) -----------------*/
2671
2673 char filename[256], messagedir[256], datadir[256], dirname[256], path[256];
2674 int status, size, write_flag;
2675 int runnumber;
2676 HNDLE hKey;
2677
2678 /* do not update runlog if logger does not write data */
2679 size = sizeof(BOOL);
2680 write_flag = FALSE;
2681 db_get_value(hDB, 0, "/Logger/Write data", &write_flag, &size, TID_BOOL, TRUE);
2682 if (!write_flag)
2683 return;
2684
2685 /* get BOR or EOR list */
2686 if (bor) {
2687 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", &hKey);
2688 if (!hKey) {
2689 cm_msg(MERROR, "write_runlog_json", "Cannot find \"/Logger/Runlog/JSON/Links BOR");
2690 return;
2691 }
2692 } else {
2693 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", &hKey);
2694 if (!hKey) {
2695 cm_msg(MERROR, "write_runlog_json", "Cannot find \"/Logger/Runlog/JSON/Links EOR");
2696 return;
2697 }
2698 }
2699
2700 size = sizeof(write_flag);
2701 write_flag = 0;
2702 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Write data", &write_flag, &size, TID_BOOL, TRUE);
2703
2704 size = sizeof(datadir);
2705 strcpy(datadir, "");
2706 db_get_value(hDB, 0, "/Logger/Data Dir", datadir, &size, TID_STRING, TRUE);
2707
2708 size = sizeof(messagedir);
2709 strcpy(messagedir, "");
2710 db_get_value(hDB, 0, "/Logger/Message Dir", messagedir, &size, TID_STRING, TRUE);
2711
2712 size = sizeof(dirname);
2713 strcpy(dirname, "runlogs");
2714 db_get_value(hDB, 0, "/Logger/Runlog/JSON/Subdir", dirname, &size, TID_STRING, TRUE);
2715
2716 size = sizeof(runnumber);
2717 db_get_value(hDB, 0, "/Runinfo/Run number", &runnumber, &size, TID_INT32, FALSE);
2718
2719 snprintf(filename, 256, "runlog_%06i.json", runnumber);
2720
2721 // use /Logger/Message dir, and if empty use /Logger/Data dir
2722 mstrlcpy(path, messagedir, sizeof(path));
2723 if (path[0] == 0)
2724 mstrlcpy(path, datadir, sizeof(path));
2725 if (path[strlen(path) - 1] != DIR_SEPARATOR)
2726 mstrlcat(path, DIR_SEPARATOR_STR, sizeof(path));
2727 mstrlcat(path, dirname, sizeof(path));
2728 if (path[strlen(path) - 1] != DIR_SEPARATOR)
2729 mstrlcat(path, DIR_SEPARATOR_STR, sizeof(path));
2730
2731 /* create directory if needed */
2732#ifdef OS_WINNT
2733 status = mkdir(path);
2734#else
2735 status = mkdir(path, 0755);
2736#endif
2737
2738 mstrlcat(path, filename, sizeof(path));
2739
2740 /* continue only if data should be written */
2741 if (!write_flag)
2742 return;
2743
2744 char fileflag[2] = "a";
2745 if (bor)
2746 strcpy(fileflag, "a");
2747
2748 FILE *file = fopen(path, fileflag);
2749 if (file == NULL) {
2750 cm_msg(MERROR, "write_runlog_json", "Cannot open file \"%s\"", path);
2751 return;
2752 }
2753
2754 if (bor)
2755 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links BOR", &hKey);
2756 else
2757 db_find_key(hDB, 0, "/Logger/Runlog/JSON/Links EOR", &hKey);
2758
2759 int buffer_size = 100000;
2760 char *buffer = (char *)malloc(buffer_size);
2761 int buffer_end = 0;
2762
2763 if (bor)
2764 json_write(&buffer, &buffer_size, &buffer_end, 0, "{\n \"BOR\": ", 0);
2765 else
2766 json_write(&buffer, &buffer_size, &buffer_end, 0, " \"EOR\": ", 0);
2767
2768 if (!rpc_is_remote())
2771 status = json_write_anything(hDB, hKey, &buffer, &buffer_size, &buffer_end, JS_LEVEL_1, 0, flags, 0);
2772 if (!rpc_is_remote())
2774
2775 if (bor)
2776 json_write(&buffer, &buffer_size, &buffer_end, 0, ",\n", 0);
2777 else
2778 json_write(&buffer, &buffer_size, &buffer_end, 0, " \n}\n", 0);
2779
2780 if (status == DB_SUCCESS) {
2781 if (buffer) {
2782 size_t wr = fwrite(buffer, 1, buffer_end, file);
2783 if (wr != (size_t) buffer_end) {
2784 cm_msg(MERROR, "write_runlog_json", "Cannot write to file \"%s\", fwrite() errno %d (%s)", filename, errno, strerror(errno));
2785 free(buffer);
2786 fclose(file);
2787 return;
2788 }
2789 }
2790 }
2791
2792 if (buffer)
2793 free(buffer);
2794
2795 fclose(file);
2796}
2797
2798/*---- open FTP channel --------------------------------------------*/
2799
2801{
2802 cm_msg(MERROR, "ftp_error", "%s", message);
2803 return 1;
2804}
2805
2806INT ftp_open(const char *xdestination, FTP_CON ** con)
2807{
2808 INT status;
2809 short port = 0;
2810 char *token;
2812 char user[32], pass[32];
2813 char directory[256], file_name[256], file_mode[256];
2814 char bdestination[256]; // have to make a copy of destination because strtok() modifies it's string
2815 mstrlcpy(bdestination, xdestination, sizeof(bdestination));
2816 char* destination = bdestination;
2817
2818 // skip leading slash
2819 if (destination[0] == '/')
2820 destination += 1;
2821
2822 /*
2823 destination should have the form:
2824 host, port, user, password, directory, run%05d.mid
2825 */
2826
2827 /* break destination in components */
2828 token = strtok(destination, ",");
2829 if (token)
2830 mstrlcpy(host_name, token, sizeof(host_name));
2831
2832 token = strtok(NULL, ", ");
2833 if (token)
2834 port = atoi(token);
2835
2836 token = strtok(NULL, ", ");
2837 if (token)
2838 mstrlcpy(user, token, sizeof(user));
2839
2840 token = strtok(NULL, ", ");
2841 if (token)
2842 mstrlcpy(pass, token, sizeof(pass));
2843
2844 token = strtok(NULL, ", ");
2845 if (token)
2846 mstrlcpy(directory, token, sizeof(directory));
2847
2848 token = strtok(NULL, ", ");
2849 if (token)
2850 mstrlcpy(file_name, token, sizeof(file_name));
2851
2852 token = strtok(NULL, ", ");
2853 file_mode[0] = 0;
2854 if (token)
2855 mstrlcpy(file_mode, token, sizeof(file_mode));
2856
2857#ifdef FAL_MAIN
2858 ftp_debug(NULL, ftp_error);
2859#else
2860 ftp_debug((int (*)(const char *)) puts, ftp_error);
2861#endif
2862
2863 status = ftp_login(con, host_name, port, user, pass, "");
2864 if (status >= 0)
2865 return status;
2866
2867 status = ftp_chdir(*con, directory);
2868 if (status >= 0)
2869 return status;
2870
2871 status = ftp_binary(*con);
2872 if (status >= 0)
2873 return status;
2874
2875 if (file_mode[0]) {
2876 status = ftp_command(*con, "umask %s", file_mode, 200, 250, EOF);
2877 if (status >= 0)
2878 return status;
2879 }
2880
2881 if (ftp_open_write(*con, file_name) >= 0)
2882 return (*con)->err_no;
2883
2884 return SS_SUCCESS;
2885}
2886
2887/*---- FTP writer --------------------------------------------------*/
2888
2890{
2891public:
2892 WriterFtp(LOG_CHN* log_chn) // ctor
2893 {
2894 if (fTrace)
2895 printf("WriterFtp: path [%s]\n", log_chn->path.c_str());
2896
2897 fFtp = NULL;
2898 }
2899
2900 ~WriterFtp() // dtor
2901 {
2902 if (fTrace)
2903 printf("WriterFtp: destructor\n");
2904
2905 if (fFtp) {
2906 ftp_bye(fFtp);
2907 fFtp = NULL;
2908 }
2909 }
2910
2911 int wr_open(LOG_CHN* log_chn, int run_number)
2912 {
2913 fBytesIn = 0;
2914 fBytesOut = 0;
2915
2916 if (fTrace)
2917 printf("WriterFtp: open path [%s]\n", log_chn->path.c_str());
2918
2919 assert(fFtp == NULL);
2920
2921 int status = ftp_open(log_chn->path.c_str(), &fFtp);
2922 if (status != SS_SUCCESS || fFtp == NULL) {
2923 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));
2924 return SS_FILE_ERROR;
2925 }
2926
2927 log_chn->handle = 9999;
2928
2929 return SUCCESS;
2930 }
2931
2932 int wr_write(LOG_CHN* log_chn, const void* data, const int size)
2933 {
2934 if (fTrace)
2935 printf("WriterFtp: write path [%s], size %d\n", log_chn->path.c_str(), size);
2936
2937 if (size == 0)
2938 return SUCCESS;
2939
2940 if (fFtp == NULL) {
2941 return SS_FILE_ERROR;
2942 }
2943
2944 fBytesIn += size;
2945
2946 int wr = ftp_send(fFtp->data, (const char*)data, size);
2947
2948 if (wr > 0)
2949 fBytesOut += wr;
2950
2951 if (wr != size) {
2952 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));
2953 return SS_FILE_ERROR;
2954 }
2955
2956 return SUCCESS;
2957 }
2958
2959 int wr_close(LOG_CHN* log_chn, int run_number)
2960 {
2961 if (fTrace)
2962 printf("WriterFtp: close path [%s]\n", log_chn->path.c_str());
2963
2964 assert(fFtp != NULL);
2965
2966 ftp_close(fFtp);
2967 ftp_bye(fFtp);
2968 fFtp = NULL;
2969
2970 log_chn->handle = 0;
2971
2972 return SUCCESS;
2973 }
2974
2975 std::string wr_get_file_ext()
2976 {
2977 return "";
2978 }
2979
2980 std::string wr_get_chain()
2981 {
2982 return "FTP";
2983 }
2984
2985private:
2987};
2988
2989/*-- db_get_event_definition ---------------------------------------*/
2990
2991typedef struct {
2992 short int event_id;
2993 WORD format;
2994 HNDLE hDefKey;
2995} EVENT_DEF;
2996
2998{
2999 INT i, index, status, size;
3000 char str[80];
3001 HNDLE hKey, hKeyRoot;
3002 WORD id;
3003
3004#define EVENT_DEF_CACHE_SIZE 30
3005 static EVENT_DEF *event_def = NULL;
3006
3007 /* allocate memory for cache */
3008 if (event_def == NULL)
3009 event_def = (EVENT_DEF *) calloc(EVENT_DEF_CACHE_SIZE, sizeof(EVENT_DEF));
3010
3011 assert(event_def != NULL);
3012
3013 /* lookup if event definition in cache */
3014 for (i = 0; event_def[i].event_id; i++)
3015 if (event_def[i].event_id == event_id)
3016 return &event_def[i];
3017
3018 /* search free cache entry */
3019 for (index = 0; index < EVENT_DEF_CACHE_SIZE; index++)
3020 if (event_def[index].event_id == 0)
3021 break;
3022
3023 if (index == EVENT_DEF_CACHE_SIZE) {
3024 cm_msg(MERROR, "db_get_event_definition", "too many event definitions");
3025 return NULL;
3026 }
3027
3028 /* check for system events */
3029 if (event_id < 0) {
3030 event_def[index].event_id = event_id;
3031 event_def[index].format = FORMAT_MIDAS;
3032 event_def[index].hDefKey = 0;
3033 return &event_def[index];
3034 }
3035
3036 status = db_find_key(hDB, 0, "/equipment", &hKeyRoot);
3037 if (status != DB_SUCCESS) {
3038 cm_msg(MERROR, "db_get_event_definition", "cannot find /equipment entry in ODB");
3039 return NULL;
3040 }
3041
3042 for (i = 0;; i++) {
3043 /* search for client with specific name */
3044 status = db_enum_key(hDB, hKeyRoot, i, &hKey);
3045 if (status == DB_NO_MORE_SUBKEYS) {
3046 cm_msg(MERROR, "db_get_event_definition", "Cannot find event id %d under /equipment", event_id);
3047 return NULL;
3048 }
3049
3050 size = sizeof(id);
3051 status = db_get_value(hDB, hKey, "Common/Event ID", &id, &size, TID_UINT16, TRUE);
3052 if (status != DB_SUCCESS)
3053 continue;
3054
3055 if (id == event_id) {
3056 /* set cache entry */
3057 event_def[index].event_id = id;
3058
3059 size = sizeof(str);
3060 str[0] = 0;
3061 db_get_value(hDB, hKey, "Common/Format", str, &size, TID_STRING, TRUE);
3062
3063 if (equal_ustring(str, "Fixed"))
3064 event_def[index].format = FORMAT_FIXED;
3065 else if (equal_ustring(str, "MIDAS"))
3066 event_def[index].format = FORMAT_MIDAS;
3067 else {
3068 cm_msg(MERROR, "db_get_event_definition", "unknown data format name \"%s\"", str);
3069 event_def[index].event_id = 0;
3070 return NULL;
3071 }
3072
3073 db_find_key(hDB, hKey, "Variables", &event_def[index].hDefKey);
3074 return &event_def[index];
3075 }
3076 }
3077}
3078
3079/*------------------------------------------------------------------*/
3080
3082{
3083 std::string bzip2_command = "bzip2 -z";
3084
3085 if (log_chn->settings.bzip2_compression) {
3086 bzip2_command += " -";
3087 bzip2_command += IntToString(log_chn->settings.bzip2_compression);
3088 }
3089
3090 return new WriterPopen(log_chn, (bzip2_command + " > ").c_str(), ".bz2");
3091}
3092
3094{
3095 std::string pbzip2_command = "pbzip2 -c -z";
3096
3097 if (log_chn->settings.pbzip2_num_cpu) {
3098 pbzip2_command += " -p";
3099 pbzip2_command += IntToString(log_chn->settings.pbzip2_num_cpu);
3100 }
3101
3102 if (log_chn->settings.pbzip2_compression) {
3103 pbzip2_command += " -";
3104 pbzip2_command += IntToString(log_chn->settings.pbzip2_compression);
3105 }
3106
3107 if (strlen(log_chn->settings.pbzip2_options) > 0) {
3108 pbzip2_command += " ";
3109 pbzip2_command += log_chn->settings.pbzip2_options;
3110 }
3111
3112 return new WriterPopen(log_chn, (pbzip2_command + " > ").c_str(), ".bz2");
3113}
3114
3115#define CHECKSUM_NONE 0
3116#define CHECKSUM_ZLIB 1
3117#define CHECKSUM_CRC32C 2
3118#define CHECKSUM_SHA256 3
3119#define CHECKSUM_SHA512 4
3120
3121WriterInterface* NewChecksum(LOG_CHN* log_chn, int code, int level, WriterInterface* chained)
3122{
3123 if (code == CHECKSUM_NONE) {
3124 return chained;
3125 } else if (code == CHECKSUM_ZLIB) {
3126 return new WriterCRC32Zlib(log_chn, level, chained);
3127 } else if (code == CHECKSUM_CRC32C) {
3128 return new WriterCRC32C(log_chn, level, chained);
3129 } else if (code == CHECKSUM_SHA256) {
3130 return new WriterSHA256(log_chn, level, chained);
3131 } else if (code == CHECKSUM_SHA512) {
3132 return new WriterSHA512(log_chn, level, chained);
3133 } else {
3134 cm_msg(MERROR, "log_create_writer", "channel %s unknown checksum code %d", log_chn->path.c_str(), code);
3135 return chained;
3136 }
3137}
3138
3139#define COMPRESS_NONE 0
3140#define COMPRESS_ZLIB 1
3141#define COMPRESS_LZ4 2
3142#define COMPRESS_BZIP2 3
3143#define COMPRESS_PBZIP2 4
3144
3146{
3147 if (code == COMPRESS_NONE) {
3148 return chained;
3149 } else if (code == COMPRESS_LZ4) {
3150 return new WriterLZ4(log_chn, chained);
3151 } else {
3152 cm_msg(MERROR, "log_create_writer", "channel %s unknown compression code %d", log_chn->path.c_str(), code);
3153 return chained;
3154 }
3155}
3156
3157#define OUTPUT_NONE 0
3158#define OUTPUT_NULL 1
3159#define OUTPUT_FILE 2
3160#define OUTPUT_FTP 3
3161//#define OUTPUT_ROOT 4
3162#define OUTPUT_PIPE 5
3163
3164std::string get_value(HNDLE hDB, HNDLE hDir, const char* name)
3165{
3167 value[0] = 0;
3168 int size = sizeof(value);
3169 int status = db_get_value(hDB, hDir, name, &value, &size, TID_STRING, FALSE);
3170 if (status != DB_SUCCESS)
3171 return "";
3172 return value;
3173}
3174
3175void set_value(HNDLE hDB, HNDLE hDir, const char* name, const std::string& set, const std::string& def)
3176{
3177 std::string s = set + " (one of:" + def + ")";
3178 int size = 256; // MUST match record definition // strlen(value);
3179 s.reserve(size);
3180 const char* value = s.c_str();
3181 db_set_value(hDB, hDir, name, value, size, 1, TID_STRING);
3182}
3183
3184int check_add(int v, int n, const std::string& val, const char* str, bool bdef, std::string* def, std::string* sel)
3185{
3186 (*def) += std::string(" ") + str;
3187 if (v)
3188 return v; // keep returning the first selection
3189 if (val.find(str) == 0) {
3190 *sel = str;
3191 return n; // if no selection yet, return the new selection
3192 }
3193 return v;
3194}
3195
3197{
3198 std::string val = get_value(hDB, hSet, name);
3199 std::string sel;
3200 std::string def;
3201 int s = 0;
3202 s = check_add(s, CHECKSUM_NONE, val, "NONE", false, &def, &sel);
3203 s = check_add(s, CHECKSUM_CRC32C, val, "CRC32C", true, &def, &sel);
3204 s = check_add(s, CHECKSUM_SHA256, val, "SHA256", false, &def, &sel);
3205 s = check_add(s, CHECKSUM_SHA512, val, "SHA512", false, &def, &sel);
3206 s = check_add(s, CHECKSUM_ZLIB, val, "ZLIB", false, &def, &sel);
3207 if (sel == "")
3208 sel = "NONE";
3209 //set_value(hDB, hSet, name, sel, def);
3210 return s;
3211}
3212
3214{
3215 std::string val = get_value(hDB, hSet, name);
3216 std::string sel;
3217 std::string def;
3218 int s = 0;
3219 s = check_add(s, COMPRESS_NONE, val, "none", false, &def, &sel);
3220 s = check_add(s, COMPRESS_ZLIB, val, "gzip", true, &def, &sel);
3221 s = check_add(s, COMPRESS_LZ4, val, "lz4", false, &def, &sel);
3222 s = check_add(s, COMPRESS_BZIP2, val, "bzip2", false, &def, &sel);
3223 s = check_add(s, COMPRESS_PBZIP2, val, "pbzip2", false, &def, &sel);
3224 if (sel == "")
3225 sel = "none";
3226 //set_value(hDB, hSet, name, sel, def);
3227 return s;
3228}
3229
3231{
3232 std::string val = get_value(hDB, hSet, name);
3233 std::string sel;
3234 std::string def;
3235 int s = 0;
3236 s = check_add(s, OUTPUT_NULL, val, "NULL", false, &def, &sel);
3237 s = check_add(s, OUTPUT_FILE, val, "FILE", true, &def, &sel);
3238 s = check_add(s, OUTPUT_FTP, val, "FTP", false, &def, &sel);
3239 s = check_add(s, OUTPUT_PIPE, val, "PIPE", false, &def, &sel);
3240 if (sel == "")
3241 sel = "FILE";
3242 //set_value(hDB, hSet, name, sel, def);
3243 return s;
3244}
3245
3247{
3248 assert(log_chn->writer == NULL);
3249 log_chn->writer = NULL;
3250
3251 if (log_chn->output_module > 0) {
3252
3253 if (log_chn->compression_module == COMPRESS_ZLIB) {
3254
3255 if (log_chn->output_module != OUTPUT_FILE) {
3256 cm_msg(MERROR, "log_create_writer", "channel %s requested GZIP/ZLIB compression, output module must be FILE", log_chn->path.c_str());
3257 return SS_FILE_ERROR;
3258 }
3259
3260 log_chn->writer = new WriterGzip(log_chn, 0);
3261 log_chn->do_disk_level = TRUE;
3262 }
3263 else if (log_chn->compression_module == COMPRESS_BZIP2) {
3264
3265 if (log_chn->output_module != OUTPUT_FILE) {
3266 cm_msg(MERROR, "log_create_writer", "channel %s requested BZIP2 compression, output module must be FILE", log_chn->path.c_str());
3267 return SS_FILE_ERROR;
3268 }
3269
3270 log_chn->writer = NewWriterBzip2(log_chn);
3271 log_chn->do_disk_level = TRUE;
3272
3273 }
3274 else if (log_chn->compression_module == COMPRESS_PBZIP2) {
3275
3276 if (log_chn->output_module != OUTPUT_FILE) {
3277 cm_msg(MERROR, "log_create_writer", "channel %s requested PBZIP2 compression, output module must be FILE", log_chn->path.c_str());
3278 return SS_FILE_ERROR;
3279 }
3280
3281 log_chn->writer = NewWriterPbzip2(log_chn);
3282 log_chn->do_disk_level = TRUE;
3283 }
3284 else if (log_chn->output_module == OUTPUT_NULL) {
3285
3286 log_chn->writer = new WriterNull(log_chn);
3287 log_chn->do_disk_level = TRUE;
3288 }
3289 else if (log_chn->output_module == OUTPUT_FILE) {
3290
3291 log_chn->writer = NewCompression(log_chn, log_chn->compression_module, NewChecksum(log_chn, log_chn->post_checksum_module, 0, new WriterFile(log_chn)));
3292 log_chn->do_disk_level = TRUE;
3293 }
3294 else if (log_chn->output_module == OUTPUT_FTP) {
3295
3296 log_chn->writer = NewCompression(log_chn, log_chn->compression_module, NewChecksum(log_chn, log_chn->post_checksum_module, 0, new WriterFtp(log_chn)));
3297 log_chn->do_disk_level = FALSE;
3298 log_chn->statistics.disk_level = -1;
3299 }
3300 else if (log_chn->output_module == OUTPUT_PIPE) {
3301
3302 log_chn->writer = NewCompression(log_chn, log_chn->compression_module, NewChecksum(log_chn, log_chn->post_checksum_module, 0, new WriterPopen(log_chn, "xxx", "")));
3303 log_chn->do_disk_level = FALSE;
3304 log_chn->statistics.disk_level = -1;
3305 }
3306
3307 //log_chn->writer = new WriterROOT(log_chn);
3308 //log_chn->do_disk_level = TRUE;
3309
3310 if (log_chn->pre_checksum_module) {
3311 log_chn->writer = NewChecksum(log_chn, log_chn->pre_checksum_module, 1, log_chn->writer);
3312 }
3313
3314 //cm_msg(MINFO, "log_create_writer", "channel \"%s\" writer chain: %s", log_chn->path.c_str(), log_chn->writer->wr_get_chain().c_str());
3315
3316 return SUCCESS;
3317 }
3318
3319 cm_msg(MERROR, "log_create_writer", "channel %s invalid output module value %d", log_chn->path.c_str(), log_chn->output_module);
3320 return SS_FILE_ERROR;
3321}
3322
3323/*---- log_open ----------------------------------------------------*/
3324
3326{
3327 INT status = SUCCESS;
3328
3329 log_chn->last_checked = ss_millitime();
3330
3331 if (log_chn->writer) {
3332 WriterInterface* wr = log_chn->writer;
3333
3334 int status = wr->wr_open(log_chn, run_number);
3335
3336 if (status != SUCCESS)
3337 return status;
3338
3339 /* write ODB dump */
3340 if (log_chn->settings.odb_dump)
3342
3343 /* update statistics */
3344 double incr = wr->fBytesOut - log_chn->statistics.bytes_written_subrun;
3345 if (incr < 0)
3346 incr = 0;
3347
3348 //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);
3349
3350 log_chn->statistics.bytes_written += incr;
3352 log_chn->statistics.bytes_written_total += incr;
3353 } else {
3354 return SS_INVALID_FORMAT;
3355 }
3356 return status;
3357}
3358
3359/*---- log_close ---------------------------------------------------*/
3360
3362{
3363 if (log_chn->writer) {
3364 /* write ODB dump */
3365 if (log_chn->settings.odb_dump)
3367
3368 WriterInterface* wr = log_chn->writer;
3369
3370 wr->wr_close(log_chn, run_number);
3371
3372 /* update statistics */
3373
3374 double incr = wr->fBytesOut - log_chn->statistics.bytes_written_subrun;
3375 if (incr < 0)
3376 incr = 0;
3377
3378 //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);
3379
3380 log_chn->statistics.bytes_written += incr;
3382 log_chn->statistics.bytes_written_total += incr;
3383 }
3384
3385 /* if file name starts with '.', rename it */
3386 char str[256]; // FIXME: this will truncate the filename of the output file. K.O.
3387 mstrlcpy(str, log_chn->path.c_str(), sizeof(str));
3388 char* p = str;
3389 if (strrchr(str, DIR_SEPARATOR)) {
3390 p = strrchr(str, DIR_SEPARATOR)+1;
3391 }
3392 if (*p == '.') {
3393 mstrlcpy(p, p+1, sizeof(str));
3394 rename(log_chn->path.c_str(), str); // FIXME: must check return status. K.O.
3395 }
3396
3397 log_chn->statistics.files_written += 1;
3398 log_chn->handle = 0;
3399 log_chn->ftp_con = NULL;
3400
3401 if (log_chn->writer) {
3402 delete log_chn->writer;
3403 log_chn->writer = NULL;
3404 }
3405
3406 return SS_SUCCESS;
3407}
3408
3409/*---- log disk levels ---------------------------------------------*/
3410
3411int log_disk_level(LOG_CHN* log_chn, double* pdisk_size, double* pdisk_free)
3412{
3413 std::string str = log_chn->path.c_str();
3414 size_t pos = str.rfind('/');
3415 if (pos != std::string::npos) {
3416 str.erase(pos); // strip filename for bzip2
3417 }
3418
3419 //printf("log_disk_level [%s] [%s]\n", log_chn->path.c_str(), str.c_str());
3420
3421 double MiB = 1024*1024;
3422 double disk_size = ss_disk_size(str.c_str());
3423 double disk_free = ss_disk_free(str.c_str());
3424 double limit = 10E6;
3425 double level = 1.0-disk_free/disk_size;
3426
3427 if (pdisk_size)
3428 *pdisk_size = disk_size; // should be in statistics
3429 if (pdisk_free)
3430 *pdisk_free = disk_free; // should be in statistics
3431
3432 log_chn->statistics.disk_level = level;
3433
3434 if (verbose)
3435 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);
3436
3437 return SUCCESS;
3438}
3439
3441{
3443 static DWORD last_check_time = 0;
3444
3445 if (last_check_time == 0)
3446 last_check_time = actual_time;
3447
3448 if (actual_time - last_check_time < DISK_CHECK_INTERVAL_MILLISEC)
3449 return SUCCESS;
3450
3451 last_check_time = actual_time;
3452
3453 for (unsigned i = 0; i < log_channels.size(); i++) {
3454 LOG_CHN* chn = log_channels[i];
3455
3456 if (!chn->do_disk_level)
3457 continue;
3458
3459 log_disk_level(chn, NULL, NULL);
3460 }
3461
3462 return SUCCESS;
3463}
3464
3465static int get_trans_flag()
3466{
3467 int status, size, flag;
3468
3469 size = sizeof(BOOL);
3470 flag = FALSE;
3471 status = db_get_value(hDB, 0, "/Logger/Async transitions", &flag, &size, TID_BOOL, FALSE);
3472
3473 if (status == DB_SUCCESS) {
3474 cm_msg(MINFO, "get_trans_flag", "ODB \"/Logger/Async transitions\" is obsolete, please delete it");
3475 }
3476
3477 size = sizeof(BOOL);
3478 flag = TRUE;
3479 status = db_get_value(hDB, 0, "/Logger/Multithread transitions", &flag, &size, TID_BOOL, FALSE);
3480
3481 if (status == DB_SUCCESS) {
3482 cm_msg(MINFO, "get_trans_flag", "ODB \"/Logger/Multithread transitions\" is obsolete, please delete it");
3483 }
3484
3485 size = sizeof(BOOL);
3486 flag = FALSE;
3487 db_get_value(hDB, 0, "/Logger/Detached transitions", &flag, &size, TID_BOOL, TRUE);
3488
3489 // NB: we must use multithread or detached (via mtransition) transition
3490 // otherwise we deadlock against frontends: they are writing to the SYSTEM
3491 // buffer but we (mlogger) are not reading from it. if SYSTEM buffer is full,
3492 // clients get stuck waiting for free space and cannot not handle TR_STOP RPC.
3493 // if they could handle, it, they would still be stuck in bm_flush_cache()
3494 // because we (mlogger) are not reading the SYSTEM buffer and these last
3495 // events have nowhere to go. K.O.
3496
3497 if (flag)
3498 return TR_DETACH;
3499 else
3500 return TR_MTHREAD;
3501}
3502
3503/*---- log_write ---------------------------------------------------*/
3504
3505int stop_the_run(int restart)
3506{
3507 int status, flag, size;
3508 char errstr[256];
3509
3510 if (restart) {
3511 size = sizeof(BOOL);
3512 flag = FALSE;
3513 db_get_value(hDB, 0, "/Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
3514
3515 if (flag) {
3517 auto_restart = 0;
3518 }
3519 }
3520
3522 stop_try_later = 0;
3523
3524 int trans_flag = get_trans_flag();
3525
3526 status = cm_transition(TR_STOP, 0, errstr, sizeof(errstr), trans_flag, verbose);
3528 cm_msg(MERROR, "stop_the_run", "another transition is in progress, will try again later");
3530 stop_try_later = ss_time_sec() + 10.0;
3531 } else if (status != CM_SUCCESS) {
3532 cm_msg(MERROR, "stop_the_run", "cannot stop the run, cm_transition() status %d, error: %s", status, errstr);
3533 return status;
3534 }
3535
3536 return status;
3537}
3538
3540{
3541 int status, size, state, run_number, flag;
3542 char errstr[256];
3543
3545 auto_restart = 0;
3546
3547 /* check if autorestart is still on */
3548 size = sizeof(BOOL);
3549 flag = FALSE;
3550 db_get_value(hDB, 0, "/Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
3551
3552 if (!flag) {
3553 cm_msg(MINFO, "start_the_run", "Run auto restart canceled");
3554 return SUCCESS;
3555 }
3556
3557 /* check if really stopped */
3558 size = sizeof(state);
3559 status = db_get_value(hDB, 0, "Runinfo/State", &state, &size, TID_INT32, TRUE);
3560 if (status != DB_SUCCESS) {
3561 cm_msg(MERROR, "start_the_run", "cannot get Runinfo/State in database, db_get_value() status %d", status);
3562 return status;
3563 }
3564
3565 static int backoff = 1;
3566
3567 if (state != STATE_STOPPED) {
3568 cm_msg(MINFO, "start_the_run", "Runinfo/State %d is not STATE_STOPPED, will try again in %d seconds", state, backoff);
3569 auto_restart = ss_time() + backoff; /* try again later */
3570 if (backoff < 1)
3571 backoff = 1;
3572 else if (backoff > 1*60)
3573 backoff = 1*60;
3574 else
3575 backoff *= 2;
3576 return SUCCESS;
3577 }
3578
3579 backoff = 1;
3580
3581 size = sizeof(run_number);
3582 status = db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
3583 assert(status == SUCCESS);
3584
3585 if (run_number <= 0) {
3586 cm_msg(MERROR, "start_the_run", "aborting on attempt to use invalid run number %d", run_number);
3587 abort();
3588 }
3589
3590 int trans_flag = get_trans_flag();
3591
3592 cm_msg(MTALK, "start_the_run", "starting new run");
3593 status = cm_transition(TR_START, run_number + 1, errstr, sizeof(errstr), trans_flag, verbose);
3594 if (status != CM_SUCCESS)
3595 cm_msg(MERROR, "start_the_run", "cannot restart run: cm_transition() status %d, error: %s", status, errstr);
3596
3597 return status;
3598}
3599
3600INT log_write(LOG_CHN * log_chn, EVENT_HEADER * pevent)
3601{
3602 INT status = 0, size;
3603 DWORD duration;
3604 BOOL next_subrun;
3605
3606 //printf("log_write %d\n", pevent->data_size + sizeof(EVENT_HEADER));
3607
3608 DWORD start_time = ss_millitime();
3609 int evt_size = pevent->data_size + sizeof(EVENT_HEADER);
3610
3611 if (log_chn->writer) {
3612 WriterInterface* wr = log_chn->writer;
3613 status = wr->wr_write(log_chn, pevent, evt_size);
3614
3615 if (status == SUCCESS) {
3616 /* update statistics */
3617 log_chn->statistics.events_written++;
3618 log_chn->statistics.bytes_written_uncompressed += evt_size;
3619 }
3620
3621 double incr = wr->fBytesOut - log_chn->statistics.bytes_written_subrun;
3622 if (incr < 0)
3623 incr = 0;
3624
3625 //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);
3626
3627 log_chn->statistics.bytes_written += incr;
3629 log_chn->statistics.bytes_written_total += incr;
3630 }
3631
3633 if (actual_time - start_time > 3000)
3634 cm_msg(MINFO, "log_write", "Write operation on \'%s\' took %d ms", log_chn->path.c_str(), actual_time - start_time);
3635
3636 if (status != SS_SUCCESS && !stop_requested) {
3637 cm_msg(MTALK, "log_write", "Error writing output file, stopping run");
3638 cm_msg(MERROR, "log_write", "Cannot write \'%s\', error %d, stopping run", log_chn->path.c_str(), status);
3639 stop_the_run(0);
3640
3641 return status;
3642 }
3643
3644 /* check if event limit is reached to stop run */
3646 log_chn->settings.event_limit > 0 &&
3647 log_chn->statistics.events_written >= log_chn->settings.event_limit) {
3649
3650 cm_msg(MTALK, "log_write", "stopping run after having received %1.0lf events",
3651 log_chn->settings.event_limit);
3652
3653 status = stop_the_run(1);
3654 return status;
3655 }
3656
3657 /* check if duration is reached for subrun */
3658 duration = 0;
3659 size = sizeof(duration);
3660 db_get_value(hDB, 0, "/Logger/Subrun duration", &duration, &size, TID_UINT32, TRUE);
3661 if (!stop_requested && duration > 0 && ss_time() >= subrun_start_time + duration) {
3662 int run_number;
3663
3664 // cm_msg(MTALK, "main", "stopping subrun after %d seconds", duration);
3665
3666 size = sizeof(run_number);
3667 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
3668 assert(status == SUCCESS);
3669
3670 stop_requested = TRUE; // avoid recursive call thourgh log_odb_dump
3671 log_close(log_chn, run_number);
3672 log_chn->subrun_number++;
3673 log_chn->statistics.bytes_written_subrun = 0;
3674 log_create_writer(log_chn);
3675 log_generate_file_name(log_chn);
3676 log_open(log_chn, run_number);
3679 }
3680
3681 /* check if byte limit is reached for subrun */
3682 if (!stop_requested && log_chn->settings.subrun_byte_limit > 0 &&
3684 int run_number;
3685
3686 // cm_msg(MTALK, "main", "stopping subrun after %1.0lf bytes", log_chn->settings.subrun_byte_limit);
3687
3688 size = sizeof(run_number);
3689 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
3690 assert(status == SUCCESS);
3691
3692 stop_requested = TRUE; // avoid recursive call thourgh log_odb_dump
3693 log_close(log_chn, run_number);
3694 log_chn->subrun_number++;
3695 log_chn->statistics.bytes_written_subrun = 0;
3696 log_create_writer(log_chn);
3697 log_generate_file_name(log_chn);
3698 log_open(log_chn, run_number);
3701 }
3702
3703 /* check if new subrun is requested manually */
3704 next_subrun = FALSE;
3705 size = sizeof(next_subrun);
3706 db_get_value(hDB, 0, "/Logger/Next subrun", &next_subrun, &size, TID_BOOL, true);
3707 if (!stop_requested && next_subrun) {
3708 int run_number;
3709
3710 // cm_msg(MTALK, "main", "stopping subrun by user request");
3711
3712 size = sizeof(run_number);
3713 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
3714 assert(status == SUCCESS);
3715
3716 stop_requested = TRUE; // avoid recursive call thourgh log_odb_dump
3717 log_close(log_chn, run_number);
3718 log_chn->subrun_number++;
3719 log_chn->statistics.bytes_written_subrun = 0;
3720 log_create_writer(log_chn);
3721 log_generate_file_name(log_chn);
3722 log_open(log_chn, run_number);
3725
3726 next_subrun = FALSE;
3727 db_set_value(hDB, 0, "/Logger/Next subrun", &next_subrun, sizeof(next_subrun), 1, TID_BOOL);
3728 }
3729
3730 /* check if byte limit is reached to stop run */
3732 log_chn->settings.byte_limit > 0 &&
3733 log_chn->statistics.bytes_written >= log_chn->settings.byte_limit) {
3735
3736 cm_msg(MTALK, "log_write", "stopping run after having received %1.0lf mega bytes",
3737 log_chn->statistics.bytes_written / 1E6);
3738
3739 status = stop_the_run(1);
3740
3741 return status;
3742 }
3743
3744 /* stop run if less than 10MB free disk space */
3746 if (log_chn->type == LOG_TYPE_DISK && log_chn->do_disk_level && actual_time - log_chn->last_checked > DISK_CHECK_INTERVAL_MILLISEC) {
3747 log_chn->last_checked = actual_time;
3748
3749 const double MiB = 1024*1024;
3750 double disk_size = 0;
3751 double disk_free = 0;
3752
3753 log_disk_level(log_chn, &disk_size, &disk_free);
3754
3755 double limit = 10E6;
3756
3757 if (disk_size > 100E9) {
3758 limit = 1000E6;
3759 } else if (disk_size > 10E9) {
3760 limit = 100E6;
3761 }
3762
3763 if (disk_free < limit) {
3765 cm_msg(MTALK, "log_write", "disk nearly full, stopping the run");
3766 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);
3767
3768 status = stop_the_run(0);
3769 }
3770 }
3771
3772 return status;
3773}
3774
3775/*---- open_history ------------------------------------------------*/
3776
3777void log_history(HNDLE hDB, HNDLE hKey, void *info);
3778
3779#include "history.h"
3780
3781static std::vector<MidasHistoryInterface*> mh;
3782static std::vector<std::string> history_events;
3783
3784static 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)
3785{
3786 int status;
3787 int size, i;
3788 int index = *indexp;
3789
3790#if 0
3791 {
3792 /* print the tags */
3793 printf("add_event: event %d, name \"%s\", ntags %d\n", event_id, event_name, ntags);
3794 for (i=0; i<ntags; i++) {
3795 printf("tag %d: name \"%s\", type %d, n_data %d\n", i, tags[i].name, tags[i].type, tags[i].n_data);
3796 }
3797 }
3798#endif
3799
3800 /* check for duplicate event id's */
3801 for (i=0; i<index; i++) {
3802 if (strcmp(hist_log[i].event_name, event_name) == 0) {
3803 cm_msg(MERROR, "add_event", "Duplicate event name \'%s\' with event id %d", event_name, event_id);
3804 return 0;
3805 }
3806 }
3807
3808 while (index >= hist_log_size) {
3809 int new_size = 2*hist_log_size;
3810
3811 if (hist_log_size == 0)
3812 new_size = 10;
3813
3814 hist_log = (hist_log_s*)realloc(hist_log, sizeof(hist_log[0])*new_size);
3815 assert(hist_log!=NULL);
3816
3817 hist_log_size = new_size;
3818 }
3819
3820 if (index >= hist_log_max)
3821 hist_log_max = index + 1;
3822
3823 /* check for invalid history tags */
3824 for (i=0; i<ntags; i++) {
3825 if (tags[i].type == TID_STRING) {
3826 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);
3827 return 0;
3828 }
3829 if (tags[i].type == TID_INT64) {
3830 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);
3831 return 0;
3832 }
3833 if (tags[i].type == TID_UINT64) {
3834 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);
3835 return 0;
3836 }
3837 if (rpc_tid_size(tags[i].type) == 0) {
3838 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);
3839 return 0;
3840 }
3841 }
3842
3843 /* check for trailing spaces in tag names */
3844 for (i=0; i<ntags; i++) {
3845 if (isspace(tags[i].name[strlen(tags[i].name)-1])) {
3846 cm_msg(MERROR, "add_event", "Invalid tag %d \'%s\' in event %d \'%s\': has trailing spaces", i, tags[i].name, event_id, event_name);
3847 return 0;
3848 }
3849 }
3850
3851 for (unsigned i=0; i<mh.size(); i++) {
3852 status = mh[i]->hs_define_event(event_name, timestamp, ntags, tags);
3853 if (status != HS_SUCCESS) {
3854 cm_msg(MERROR, "add_event", "Cannot define event \"%s\", hs_define_event() status %d", event_name, status);
3855 return 0;
3856 }
3857 }
3858
3859 status = db_get_record_size(hDB, hKey, 0, &size);
3860
3861 if (status != DB_SUCCESS) {
3862 cm_msg(MERROR, "add_event", "Cannot define event \"%s\", db_get_record_size() status %d", event_name, status);
3863 return 0;
3864 }
3865
3866 /* setup hist_log structure for this event */
3867 mstrlcpy(hist_log[index].event_name, event_name, sizeof(hist_log[index].event_name));
3868 hist_log[index].n_var = ntags;
3870 hist_log[index].buffer_size = size;
3871 hist_log[index].buffer = (char*)malloc(size);
3872 hist_log[index].min_period = min_period;
3873 hist_log[index].last_log = 0;
3874
3875 if (hist_log[index].buffer == NULL) {
3876 cm_msg(MERROR, "add_event", "Cannot allocate data buffer for event \"%s\" size %d", event_name, size);
3877 return 0;
3878 }
3879
3880 /* open hot link to variables */
3881 if (hotlink) {
3882 status = db_open_record(hDB, hKey, hist_log[index].buffer, size, MODE_READ, log_history, NULL);
3883 if (status != DB_SUCCESS) {
3884 cm_msg(MERROR, "add_event",
3885 "Cannot hotlink event %d \"%s\" for history logging, db_open_record() status %d",
3886 event_id, event_name, status);
3887 return status;
3888 }
3889 }
3890
3891 history_events.push_back(event_name);
3892
3893 if (verbose)
3894 printf("Created event %d for equipment \"%s\", %d tags, size %d\n", event_id, event_name, ntags, size);
3895
3896 *indexp = index+1;
3897
3898 return SUCCESS;
3899}
3900
3902{
3903 INT size, index, i_tag, status, i, j, li, max_event_id;
3904 int ieq;
3905 INT n_var, n_tags, n_names = 0;
3906 HNDLE hKeyRoot, hKeyVar, hLinkKey, hVarKey, hKeyEq, hHistKey, hKey;
3907 HNDLE hKeyHist;
3908 TAG *tag = NULL;
3909 KEY key, varkey, linkkey, histkey;
3910 WORD eq_id;
3911 char str[256], eq_name[NAME_LENGTH], hist_name[NAME_LENGTH];
3912 int global_per_variable_history = 0;
3913
3914 time_t now = time(NULL);
3915
3916 double tstart = ss_time_sec();
3917
3918 // delete old history channels
3919
3920 for (unsigned i=0; i<mh.size(); i++)
3921 delete mh[i];
3922 mh.clear();
3923
3924 history_events.clear();
3925
3926 // create and initialize the history channels tree
3927
3928 status = db_find_key(hDB, 0, "/Logger/History", &hKeyHist);
3929
3930 if (status == DB_NO_KEY) {
3931 int active;
3932 std::string type;
3933 int debug;
3934
3935 // create entry for FILE history
3936
3937 type = "FILE";
3938 status = db_get_value_string(hDB, 0, "/Logger/History/FILE/Type", 0, &type, TRUE);
3939 assert(status==DB_SUCCESS);
3940
3941 active = 1;
3942 size = sizeof(active);
3943 status = db_get_value(hDB, 0, "/Logger/History/FILE/Active", &active, &size, TID_BOOL, TRUE);
3944 assert(status==DB_SUCCESS);
3945
3946 debug = 0;
3947 size = sizeof(debug);
3948 status = db_get_value(hDB, 0, "/Logger/History/FILE/Debug", &debug, &size, TID_INT32, TRUE);
3949 assert(status==DB_SUCCESS);
3950
3951 int per_variable = 1;
3952 size = sizeof(per_variable);
3953 status = db_get_value(hDB, 0, "/Logger/History/FILE/PerVariableHistory", &per_variable, &size, TID_INT32, TRUE);
3954 assert(status==DB_SUCCESS);
3955
3956 // create entry for the MIDAS history
3957
3958 type = "MIDAS";
3959 status = db_get_value_string(hDB, 0, "/Logger/History/MIDAS/Type", 0, &type, TRUE);
3960 assert(status==DB_SUCCESS);
3961
3962 active = 0;
3963 size = sizeof(active);
3964 status = db_get_value(hDB, 0, "/Logger/History/MIDAS/Active", &active, &size, TID_BOOL, TRUE);
3965 assert(status==DB_SUCCESS);
3966
3967 debug = 0;
3968 size = sizeof(debug);
3969 status = db_get_value(hDB, 0, "/Logger/History/MIDAS/Debug", &debug, &size, TID_INT32, TRUE);
3970 assert(status==DB_SUCCESS);
3971
3972 // create entry for ODBC (MySQL) history
3973
3974 type = "ODBC";
3975 status = db_get_value_string(hDB, 0, "/Logger/History/ODBC/Type", 0, &type, TRUE);
3976 assert(status==DB_SUCCESS);
3977
3978 active = 0;
3979 size = sizeof(active);
3980 status = db_get_value(hDB, 0, "/Logger/History/ODBC/Active", &active, &size, TID_BOOL, TRUE);
3981 assert(status==DB_SUCCESS);
3982
3983 debug = 0;
3984 size = sizeof(debug);
3985 status = db_get_value(hDB, 0, "/Logger/History/ODBC/Debug", &debug, &size, TID_INT32, TRUE);
3986 assert(status==DB_SUCCESS);
3987
3988 // create entry for SQLITE history
3989
3990 type = "SQLITE";
3991 status = db_get_value_string(hDB, 0, "/Logger/History/SQLITE/Type", 0, &type, TRUE);
3992 assert(status==DB_SUCCESS);
3993
3994 active = 0;
3995 size = sizeof(active);
3996 status = db_get_value(hDB, 0, "/Logger/History/SQLITE/Active", &active, &size, TID_BOOL, TRUE);
3997 assert(status==DB_SUCCESS);
3998
3999 debug = 0;
4000 size = sizeof(debug);
4001 status = db_get_value(hDB, 0, "/Logger/History/SQLITE/Debug", &debug, &size, TID_INT32, TRUE);
4002 assert(status==DB_SUCCESS);
4003
4004 // create entry for MYSQL history writer
4005
4006 type = "MYSQL";
4007 status = db_get_value_string(hDB, 0, "/Logger/History/MYSQL/Type", 0, &type, TRUE);
4008 assert(status==DB_SUCCESS);
4009
4010 active = 0;
4011 size = sizeof(active);
4012 status = db_get_value(hDB, 0, "/Logger/History/MYSQL/Active", &active, &size, TID_BOOL, TRUE);
4013 assert(status==DB_SUCCESS);
4014
4015 debug = 0;
4016 size = sizeof(debug);
4017 status = db_get_value(hDB, 0, "/Logger/History/MYSQL/Debug", &debug, &size, TID_INT32, TRUE);
4018 assert(status==DB_SUCCESS);
4019
4020 // create entry for PGSQL history writer
4021
4022 type = "PGSQL";
4023 status = db_get_value_string(hDB, 0, "/Logger/History/PGSQL/Type", 0, &type, TRUE);
4024 assert(status==DB_SUCCESS);
4025
4026 active = 0;
4027 size = sizeof(active);
4028 status = db_get_value(hDB, 0, "/Logger/History/PGSQL/Active", &active, &size, TID_BOOL, TRUE);
4029 assert(status==DB_SUCCESS);
4030
4031 debug = 0;
4032 size = sizeof(debug);
4033 status = db_get_value(hDB, 0, "/Logger/History/PGSQL/Debug", &debug, &size, TID_INT32, TRUE);
4034 assert(status==DB_SUCCESS);
4035
4036 // get newly created /Logger/History
4037
4038 status = db_find_key(hDB, 0, "/Logger/History", &hKeyHist);
4039 }
4040
4041 if (status != DB_SUCCESS) {
4042 cm_msg(MERROR, "open_history", "Something is wrong with /Logger/History, db_find_key() status %d", status);
4043 return status;
4044 }
4045
4046 // loop over history channels
4047
4048 for (int ichan = 0; ; ichan++) {
4049 status = db_enum_key(hDB, hKeyHist, ichan, &hKey);
4050 if (status != DB_SUCCESS)
4051 break;
4052
4053 MidasHistoryInterface* hi = NULL;
4054
4056
4057 if (status==HS_SUCCESS && hi) {
4058 if (strcasecmp(hi->type, "MIDAS")==0) {
4059 i = 0;
4060 size = sizeof(i);
4061 status = db_get_value(hDB, hKey, "PerVariableHistory", &i, &size, TID_INT32, TRUE);
4062 assert(status==DB_SUCCESS);
4063
4064 if (i)
4065 global_per_variable_history = 1;
4066 } else if (strcasecmp(hi->type, "FILE")==0) {
4067 i = 0;
4068 size = sizeof(i);
4069 status = db_get_value(hDB, hKey, "PerVariableHistory", &i, &size, TID_INT32, TRUE);
4070 assert(status==DB_SUCCESS);
4071
4072 if (i)
4073 global_per_variable_history = 1;
4074 } else if (strcasecmp(hi->type, "ODBC")==0) {
4075 global_per_variable_history = 1;
4076 } else if (strcasecmp(hi->type, "SQLITE")==0) {
4077 global_per_variable_history = 1;
4078 } else if (strcasecmp(hi->type, "MYSQL")==0) {
4079 global_per_variable_history = 1;
4080 } else if (strcasecmp(hi->type, "PGSQL")==0) {
4081 global_per_variable_history = 1;
4082 }
4083
4084 if (verbose)
4085 cm_msg(MINFO, "open_history", "Writing history to channel \'%s\' type \'%s\'", hi->name, hi->type);
4086
4087 mh.push_back(hi);
4088 }
4089 }
4090
4091 // prepare history channels
4092
4093 for (unsigned i=0; i<mh.size(); i++) {
4094 status = mh[i]->hs_clear_cache();
4095 assert(status == HS_SUCCESS);
4096 }
4097
4098 // check global per-variable history settings
4099
4100 i = 0;
4101 size = sizeof(i);
4102 status = db_get_value(hDB, 0, "/History/PerVariableHistory", &i, &size, TID_INT32, FALSE);
4103 if (status==DB_SUCCESS) {
4104 cm_msg(MERROR, "open_history", "mlogger ODB setting /History/PerVariableHistory is obsolete, please delete it. Use /Logger/History/MIDAS/PerVariableHistory instead");
4105 if (i)
4106 global_per_variable_history = i;
4107 }
4108
4109 if (global_per_variable_history) {
4110 static int previous = -1;
4111 if (global_per_variable_history != previous) {
4112 if (global_per_variable_history)
4113 cm_msg(MINFO, "open_history", "Per-variable history is enabled");
4114 else
4115 ;//cm_msg(MINFO, "open_history", "Per-variable history is disabled");
4116 }
4117 previous = global_per_variable_history;
4118 }
4119
4120 // setup history links
4121
4122 if (db_find_key(hDB, 0, "/History/Links", &hKeyRoot) != DB_SUCCESS ||
4123 db_find_key(hDB, 0, "/History/Links/System", &hKeyRoot) != DB_SUCCESS) {
4124 /* create default history keys */
4125 db_create_key(hDB, 0, "/History/Links", TID_KEY);
4126
4127 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/Events per sec.", &hKeyEq) == DB_SUCCESS)
4128 db_create_link(hDB, 0, "/History/Links/System/Trigger per sec.",
4129 "/Equipment/Trigger/Statistics/Events per sec.");
4130
4131 if (db_find_key(hDB, 0, "/Equipment/Trigger/Statistics/kBytes per sec.", &hKeyEq) == DB_SUCCESS)
4132 db_create_link(hDB, 0, "/History/Links/System/Trigger kB per sec.",
4133 "/Equipment/Trigger/Statistics/kBytes per sec.");
4134 }
4135
4136 /*---- define equipment events as history ------------------------*/
4137
4138 max_event_id = 0;
4139
4140 status = db_find_key(hDB, 0, "/Equipment", &hKeyRoot);
4141 if (status == DB_NO_KEY) {
4142 cm_msg(MINFO, "open_history", "Cannot find /Equipment entry in database, history system is inactive");
4143 return CM_SUCCESS;
4144 }
4145
4146 if (status != DB_SUCCESS) {
4147 cm_msg(MERROR, "open_history", "Cannot find /Equipment entry in database, db_find_key() status %d", status);
4148 return status;
4149 }
4150
4151 /* loop over equipment */
4152 index = 0;
4153 for (ieq = 0; ; ieq++) {
4154 status = db_enum_key(hDB, hKeyRoot, ieq, &hKeyEq);
4155 if (status != DB_SUCCESS)
4156 break;
4157
4158 int32_t min_period = 0; // in seconds
4159
4160 /* retrieve min period for history logging */
4161 size = sizeof(min_period);
4162 db_get_value(hDB, hKeyEq, "Common/Log history", &min_period, &size, TID_INT32, TRUE);
4163
4164 /* define history tags only if log history flag is on */
4165 if (min_period > 0) {
4166 BOOL per_variable_history = global_per_variable_history;
4167
4168 /* get equipment name */
4169 db_get_key(hDB, hKeyEq, &key);
4170 strcpy(eq_name, key.name);
4171
4172 if (strchr(eq_name, ':'))
4173 cm_msg(MERROR, "open_history", "Equipment name \'%s\' contains characters \':\', this may break the history system", eq_name);
4174
4175 status = db_find_key(hDB, hKeyEq, "Variables", &hKeyVar);
4176 if (status != DB_SUCCESS) {
4177 cm_msg(MERROR, "open_history", "Cannot find /Equipment/%s/Variables entry in database", eq_name);
4178 return 0;
4179 }
4180
4181 size = sizeof(eq_id);
4182 status = db_get_value(hDB, hKeyEq, "Common/Event ID", &eq_id, &size, TID_UINT16, TRUE);
4183 assert(status == DB_SUCCESS);
4184
4185 size = sizeof(int);
4186 status = db_get_value(hDB, hKeyEq, "Settings/PerVariableHistory", &per_variable_history, &size, TID_INT32, FALSE);
4187 assert(status == DB_SUCCESS || status == DB_NO_KEY);
4188
4189 if (verbose)
4190 printf
4191 ("\n==================== Equipment \"%s\", ID %d =======================\n",
4192 eq_name, eq_id);
4193
4194 /* count keys in variables tree */
4195 for (n_var = 0, n_tags = 0;; n_var++) {
4196 status = db_enum_key(hDB, hKeyVar, n_var, &hKey);
4198 break;
4199 db_get_key(hDB, hKey, &key);
4200 if (key.type != TID_KEY) {
4201 n_tags += key.num_values;
4202 }
4203 else {
4204 int ii;
4205 for (ii=0;; ii++) {
4206 KEY vvarkey;
4207 HNDLE hhKey;
4208
4209 status = db_enum_key(hDB, hKey, ii, &hhKey);
4211 break;
4212
4213 /* get variable key */
4214 db_get_key(hDB, hhKey, &vvarkey);
4215
4216 n_tags += vvarkey.num_values;
4217 }
4218 }
4219 }
4220
4221 if (n_var == 0)
4222 cm_msg(MINFO, "open_history", "Equipment \"%s\" history is enabled, but there are no Variables in ODB", eq_name);
4223
4224 /* create tag array */
4225 tag = (TAG *) calloc(sizeof(TAG), n_tags);
4226
4227 i_tag = 0;
4228 for (i=0; ; i++) {
4229 status = db_enum_key(hDB, hKeyVar, i, &hKey);
4231 break;
4232
4233 /* get variable key */
4234 db_get_key(hDB, hKey, &varkey);
4235
4236
4237 HNDLE hKeyNames = 0;
4238 BOOL single_names = false;
4239
4240 /* look for names */
4241
4242 if (!hKeyNames) {
4243 sprintf(str, "Settings/Names %s", varkey.name);
4244 db_find_key(hDB, hKeyEq, str, &hKeyNames);
4245 if (hKeyNames) {
4246 if (verbose)
4247 printf("Using \"/Equipment/%s/Settings/Names %s\" for variable \"%s\"\n", eq_name, varkey.name, varkey.name);
4248
4249 /* define tags from names list */
4250 db_get_key(hDB, hKeyNames, &key);
4251 n_names = key.num_values;
4252 }
4253 }
4254
4255 if (!hKeyNames) {
4256 db_find_key(hDB, hKeyEq, "Settings/Names", &hKeyNames);
4257 single_names = (hKeyNames > 0);
4258
4259 if (hKeyNames) {
4260 if (verbose)
4261 printf("Using \"/Equipment/%s/Settings/Names\" for variable \"%s\"\n", eq_name, varkey.name);
4262
4263 /* define tags from names list */
4264 db_get_key(hDB, hKeyNames, &key);
4265 n_names = key.num_values;
4266 }
4267 }
4268
4269 if (hKeyNames && n_names < varkey.num_values) {
4270 cm_msg(MERROR, "open_history",
4271 "Array size mismatch: \"/Equipment/%s/Settings/%s\" has %d entries while \"/Equipment/%s/Variables/%s\" has %d entries",
4272 eq_name, key.name, n_names,
4273 eq_name, varkey.name, varkey.num_values);
4274 free(tag);
4275 return 0;
4276 }
4277
4278 if (hKeyNames) {
4279 /* loop over array elements */
4280 for (j = 0; j < varkey.num_values; j++) {
4281 char xname[256];
4282
4283 tag[i_tag].name[0] = 0;
4284
4285 /* get name #j */
4286 size = sizeof(xname);
4287 status = db_get_data_index(hDB, hKeyNames, xname, &size, j, TID_STRING);
4288 if (status == DB_SUCCESS)
4289 mstrlcpy(tag[i_tag].name, xname, sizeof(tag[i_tag].name));
4290
4291 if (strlen(tag[i_tag].name) < 1) {
4292 char buf[256];
4293 sprintf(buf, "%d", j);
4294 mstrlcpy(tag[i_tag].name, varkey.name, NAME_LENGTH);
4295 mstrlcat(tag[i_tag].name, "_", NAME_LENGTH);
4296 mstrlcat(tag[i_tag].name, buf, NAME_LENGTH);
4297 }
4298
4299 /* append variable key name for single name array */
4300 if (single_names) {
4301 if (strlen(tag[i_tag].name) + 1 + strlen(varkey.name) >= NAME_LENGTH) {
4302 cm_msg(MERROR, "open_history",
4303 "Name for history entry \"%s %s\" too long", tag[i_tag].name, varkey.name);
4304 free(tag);
4305 return 0;
4306 }
4307 mstrlcat(tag[i_tag].name, " ", NAME_LENGTH);
4308 mstrlcat(tag[i_tag].name, varkey.name, NAME_LENGTH);
4309 }
4310
4311 tag[i_tag].type = varkey.type;
4312 tag[i_tag].n_data = 1;
4313
4314 if (verbose)
4315 printf("Defined tag %d, name \"%s\", type %d, num_values %d\n",
4316 i_tag, tag[i_tag].name, tag[i_tag].type, tag[i_tag].n_data);
4317
4318 i_tag++;
4319 }
4320 } else if (varkey.type == TID_KEY) {
4321 int ii;
4322 for (ii=0;; ii++) {
4323 KEY vvarkey;
4324 HNDLE hhKey;
4325
4326 status = db_enum_key(hDB, hKey, ii, &hhKey);
4328 break;
4329
4330 /* get variable key */
4331 db_get_key(hDB, hhKey, &vvarkey);
4332
4333 mstrlcpy(tag[i_tag].name, varkey.name, NAME_LENGTH);
4334 mstrlcat(tag[i_tag].name, "_", NAME_LENGTH);
4335 mstrlcat(tag[i_tag].name, vvarkey.name, NAME_LENGTH);
4336 tag[i_tag].type = vvarkey.type;
4337 tag[i_tag].n_data = vvarkey.num_values;
4338
4339 if (verbose)
4340 printf("Defined tag %d, name \"%s\", type %d, num_values %d\n", i_tag, tag[i_tag].name,
4341 tag[i_tag].type, tag[i_tag].n_data);
4342
4343 i_tag++;
4344 }
4345 } else {
4346 mstrlcpy(tag[i_tag].name, varkey.name, NAME_LENGTH);
4347 tag[i_tag].type = varkey.type;
4348 tag[i_tag].n_data = varkey.num_values;
4349
4350 if (verbose)
4351 printf("Defined tag %d, name \"%s\", type %d, num_values %d\n", i_tag, tag[i_tag].name,
4352 tag[i_tag].type, tag[i_tag].n_data);
4353
4354 i_tag++;
4355 }
4356
4357 if (per_variable_history && i_tag>0) {
4358 WORD event_id = 0;
4359 char event_name[NAME_LENGTH];
4360
4361 mstrlcpy(event_name, eq_name, NAME_LENGTH);
4362 mstrlcat(event_name, "/", NAME_LENGTH);
4363 mstrlcat(event_name, varkey.name, NAME_LENGTH);
4364
4365 assert(i_tag <= n_tags);
4366
4367 status = add_event(&index, now, event_id, event_name, hKey, i_tag, tag, min_period, 1);
4368 if (status != DB_SUCCESS)
4369 return status;
4370
4371 i_tag = 0;
4372 } /* if per-variable history */
4373
4374 } /* loop over variables */
4375
4376 if (!per_variable_history && i_tag>0) {
4377 assert(i_tag <= n_tags);
4378
4379 status = add_event(&index, now, eq_id, eq_name, hKeyVar, i_tag, tag, min_period, 1);
4380 if (status != DB_SUCCESS)
4381 return status;
4382
4383 }
4384
4385 if (tag) {
4386 free(tag);
4387 tag = NULL;
4388 }
4389
4390 /* remember maximum event id for later use with system events */
4391 if (eq_id > max_event_id)
4392 max_event_id = eq_id;
4393 }
4394 } /* loop over equipments */
4395
4396 /*---- define linked trees --------------------------------------*/
4397
4398 /* round up event id */
4399 max_event_id = ((int) ((max_event_id + 1) / 10) + 1) * 10;
4400
4401 status = db_find_key(hDB, 0, "/History/Links", &hKeyRoot);
4402 if (status == DB_SUCCESS) {
4403 for (li = 0;; li++) {
4404 status = db_enum_link(hDB, hKeyRoot, li, &hHistKey);
4406 break;
4407
4408 db_get_key(hDB, hHistKey, &histkey);
4409 strcpy(hist_name, histkey.name);
4410 db_enum_key(hDB, hKeyRoot, li, &hHistKey);
4411
4412 db_get_key(hDB, hHistKey, &key);
4413 if (key.type != TID_KEY) {
4414 cm_msg(MERROR, "open_history", "Only subkeys allows in /History/Links, key \"%s\"", key.name);
4415 continue;
4416 }
4417
4418 if (verbose)
4419 printf("\n==================== History link \"%s\", ID %d =======================\n",
4420 hist_name, max_event_id);
4421
4422 /* count subkeys in link */
4423 for (i = n_var = 0;; i++) {
4424 status = db_enum_key(hDB, hHistKey, i, &hKey);
4426 break;
4427
4428 if (status == DB_SUCCESS && db_get_key(hDB, hKey, &key) == DB_SUCCESS) {
4429 if (key.type != TID_KEY)
4430 n_var++;
4431 } else {
4432 db_enum_link(hDB, hHistKey, i, &hKey);
4433 db_get_key(hDB, hKey, &key);
4434 cm_msg(MERROR, "open_history",
4435 "History link /History/Links/%s/%s is invalid", hist_name, key.name);
4436 return 0;
4437 }
4438 }
4439
4440 if (n_var == 0)
4441 cm_msg(MERROR, "open_history", "History event %s has no variables in ODB", hist_name);
4442 else {
4443 /* create tag array */
4444 tag = (TAG *) calloc(sizeof(TAG), n_var);
4445
4446 assert(tag != NULL);
4447
4448 for (i = 0, size = 0, n_var = 0;; i++) {
4449 status = db_enum_link(hDB, hHistKey, i, &hLinkKey);
4451 break;
4452
4453 /* get link key */
4454 db_get_key(hDB, hLinkKey, &linkkey);
4455
4456 if (linkkey.type == TID_KEY)
4457 continue;
4458
4459 /* get link target */
4460 db_enum_key(hDB, hHistKey, i, &hVarKey);
4461 if (db_get_key(hDB, hVarKey, &varkey) == DB_SUCCESS) {
4462 /* hot-link individual values */
4463 if (histkey.type == TID_KEY) {
4464 db_close_record(hDB, hVarKey); // close previously opened record
4465 db_open_record(hDB, hVarKey, NULL, varkey.total_size, MODE_READ, log_system_history,
4466 (void *) (POINTER_T) index);
4467 }
4468
4469 strcpy(tag[n_var].name, linkkey.name);
4470 tag[n_var].type = varkey.type;
4471 tag[n_var].n_data = varkey.num_values;
4472
4473 if (verbose)
4474 printf("Defined tag \"%s\", type %d, num_values %d\n",
4475 tag[n_var].name, tag[n_var].type, tag[n_var].n_data);
4476
4477 size += varkey.total_size;
4478 n_var++;
4479 }
4480 }
4481
4482 /* hot-link whole subtree */
4483 if (histkey.type == TID_LINK) {
4484 db_close_record(hDB, hHistKey); // close previously opened record
4485 db_open_record(hDB, hHistKey, NULL, size, MODE_READ, log_system_history, (void *) (POINTER_T) index);
4486 }
4487
4488 status = add_event(&index, now, max_event_id, hist_name, hHistKey, n_var, tag, 0, 0);
4489 if (status != DB_SUCCESS)
4490 return status;
4491
4492 free(tag);
4493 tag = NULL;
4494
4495 max_event_id++;
4496 }
4497 }
4498 }
4499
4500 /*---- define run start/stop event ------------------------------*/
4501
4502 tag = (TAG *) calloc(sizeof(TAG), 2);
4503
4504 assert(tag != NULL);
4505
4506 strcpy(tag[0].name, "State");
4507 tag[0].type = TID_UINT32;
4508 tag[0].n_data = 1;
4509
4510 strcpy(tag[1].name, "Run number");
4511 tag[1].type = TID_UINT32;
4512 tag[1].n_data = 1;
4513
4514 const char* event_name = "Run transitions";
4515
4516 for (unsigned i=0; i<mh.size(); i++) {
4517 status = mh[i]->hs_define_event(event_name, now, 2, tag);
4518 if (status != HS_SUCCESS) {
4519 cm_msg(MERROR, "add_event", "Cannot define event \"%s\", hs_define_event() status %d", event_name, status);
4520 return 0;
4521 }
4522 }
4523
4524 history_events.push_back(event_name);
4525
4526 free(tag);
4527 tag = NULL;
4528
4529 /* outcommented not to produce a log entry on every run
4530 cm_msg(MINFO, "open_history", "Configured history with %d events", count_events);
4531 */
4532
4534 if (status != HS_SUCCESS)
4535 return status;
4536
4537 double tend = ss_time_sec();
4538 double telapsed = tend - tstart;
4539 if (telapsed > 10.0) {
4540 cm_msg(MERROR, "open_history", "open_history() took %.3f seconds", telapsed);
4541 }
4542
4543 return CM_SUCCESS;
4544}
4545
4546/*---- periodically flush history buffers---------------------------*/
4547
4549
4550void maybe_flush_history(time_t now)
4551{
4552 time_t flush_period_sec = 1; // flush once every 1 seconds
4553
4554 if ((last_history_flush == 0) || (now >= last_history_flush + flush_period_sec)) {
4555
4556 if (verbose)
4557 printf("flush history buffers!\n");
4558
4559 for (unsigned h = 0; h < mh.size(); h++)
4560 mh[h]->hs_flush_buffers();
4561
4562 last_history_flush = now;
4563 }
4564}
4565
4566/*---- close_history -----------------------------------------------*/
4567
4569{
4570 INT status;
4571 HNDLE hKeyRoot;
4572
4573 /* close system history */
4574 status = db_find_key(hDB, 0, "/History/Links", &hKeyRoot);
4575 if (status == DB_SUCCESS) {
4576 for (int i = 0;; i++) {
4577 HNDLE hKey;
4578 status = db_enum_key(hDB, hKeyRoot, i, &hKey);
4580 break;
4582 }
4583 }
4584
4585 /* close event history */
4586 for (int i = 0; i < hist_log_max; i++)
4587 if (hist_log[i].hKeyVar) {
4588 db_close_record(hDB, hist_log[i].hKeyVar);
4589 hist_log[i].hKeyVar = 0;
4590 if (hist_log[i].buffer)
4591 free(hist_log[i].buffer);
4592 hist_log[i].buffer = NULL;
4593 }
4594
4595 for (unsigned h=0; h<mh.size(); h++) {
4596 mh[h]->hs_disconnect();
4597 delete mh[h];
4598 mh[h] = NULL;
4599 }
4600
4601 mh.clear();
4602}
4603
4604/*---- log_history -------------------------------------------------*/
4605
4607{
4608 INT i, size, status;
4609 DWORD start_millitime = ss_millitime();
4610
4611 time_t now = time(NULL);
4612
4613 for (i = 0; i < hist_log_max; i++)
4614 if (hist_log[i].hKeyVar == hKey)
4615 break;
4616
4617 if (i == hist_log_max)
4618 return;
4619
4620 /* check if over minimum period */
4621 if (now - hist_log[i].last_log < hist_log[i].min_period)
4622 return;
4623
4624 /* check if event size has changed */
4625 db_get_record_size(hDB, hKey, 0, &size);
4626 if (size != hist_log[i].buffer_size) {
4627 close_history();
4628 status = open_history();
4629 if (status != CM_SUCCESS) {
4630 printf("Error in history system, aborting.\n");
4632 exit(1);
4633 }
4634 return;
4635 }
4636
4637 hist_log[i].last_log = now;
4638
4639 if (verbose)
4640 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);
4641
4642 for (unsigned h=0; h<mh.size(); h++) {
4643 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);
4644 if (verbose)
4645 if (status != HS_SUCCESS)
4646 printf("write_history_event: \'%s\', channel \'%s\' hs_write_event() status %d\n", hist_log[i].event_name, mh[h]->name, status);
4647 }
4648
4650
4651 DWORD end_millitime = ss_millitime();
4652 if (end_millitime - start_millitime > 3000)
4653 cm_msg(MINFO, "log_history", "History write operation took %d ms", end_millitime - start_millitime);
4654}
4655
4656/*------------------------------------------------------------------*/
4657
4659{
4660 INT size, total_size, status, index;
4661 DWORD i;
4662 KEY key;
4663 DWORD start_millitime = ss_millitime();
4664
4665 index = (INT) (POINTER_T) info;
4666
4667 time_t now = time(NULL);
4668
4669 /* check if over period */
4670 if (now - hist_log[index].last_log < hist_log[index].min_period)
4671 return;
4672
4673 for (i = 0, total_size = 0;; i++) {
4674 status = db_enum_key(hDB, hist_log[index].hKeyVar, i, &hKey);
4676 break;
4677
4678 db_get_key(hDB, hKey, &key);
4679 size = key.total_size;
4680 db_get_data(hDB, hKey, (char *) hist_log[index].buffer + total_size, &size, key.type);
4681 total_size += size;
4682 }
4683
4684 if (i != hist_log[index].n_var) {
4685 close_history();
4686 status = open_history();
4687 if (status != CM_SUCCESS) {
4688 printf("Error in history system, aborting.\n");
4690 exit(1);
4691 }
4692 return;
4693 }
4694
4695 hist_log[index].last_log = now;
4696
4697 if (verbose)
4698 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);
4699
4700 for (unsigned h=0; h<mh.size(); h++)
4701 mh[h]->hs_write_event(hist_log[index].event_name, hist_log[index].last_log, total_size, hist_log[index].buffer);
4702
4704
4705 DWORD end_millitime = ss_millitime();
4706 if (end_millitime - start_millitime > 3000)
4707 cm_msg(MINFO, "log_system_history", "History write operation took %d ms", end_millitime - start_millitime);
4708}
4709
4710/*------------------------------------------------------------------*/
4711
4713{
4714 INT size, status, run_number = 0;
4715 std::string path;
4716 std::string data_dir;
4717 CHN_SETTINGS *chn_settings;
4718
4719 chn_settings = &log_chn->settings;
4720 size = sizeof(run_number);
4721 status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT32, TRUE);
4722 assert(status == SUCCESS);
4723
4724 std::string filename = chn_settings->filename;
4725 /* Check if data stream are throw pipe command */
4726 log_chn->pipe_command = "";
4727 bool ispipe = false;
4728 if (log_chn->type == LOG_TYPE_DISK) {
4729 char* p = strchr(chn_settings->filename, '>');
4730 if (chn_settings->filename[0] == '|' && p) {
4731 /* skip second arrow in ">>" */
4732 while (*p == '>')
4733 p++;
4734 /* skip spaces after '>' */
4735 while (*p == ' ')
4736 p++;
4737 filename = p;
4738 ispipe = true;
4739 // pipe_command is contents of chn_settings->filename without the leading "|" and trailing ">"
4740 log_chn->pipe_command = "";
4741 const char*s = chn_settings->filename;
4742 /* skip leading pipe */
4743 if (*s == '|')
4744 s++;
4745 /* skip spaces */
4746 while (*s == ' ')
4747 s++;
4748 /* copy up to ">" */
4749 while (*s != '>') {
4750 log_chn->pipe_command += *s++;
4751 }
4752 /* copy as many ">" as they put there */
4753 while (*s == '>') {
4754 log_chn->pipe_command += *s++;
4755 }
4756 }
4757 }
4758
4759 std::string str;
4760
4761 /* if disk, precede filename with directory if not already there */
4762 if (log_chn->type == LOG_TYPE_DISK && filename[0] != DIR_SEPARATOR) {
4763 db_get_value_string(hDB, 0, "/Logger/Data Dir", 0, &data_dir, TRUE);
4764 if (data_dir.empty()) {
4765 data_dir = cm_get_path();
4766 } else {
4767 if (data_dir.back() != DIR_SEPARATOR)
4768 data_dir += DIR_SEPARATOR_STR;
4769 }
4770 str = data_dir;
4771
4772 /* append subdirectory if requested */
4773 if (chn_settings->subdir_format[0]) {
4774 ss_tzset(); // required for localtime_r()
4775 time_t now;
4776 time(&now);
4777 struct tm tms;
4778 localtime_r(&now, &tms);
4779
4780 char dir[256];
4781 strftime(dir, sizeof(dir), chn_settings->subdir_format, &tms);
4782 str += dir;
4784 }
4785
4786 /* create directory if needed */
4787#ifdef OS_WINNT
4788 status = mkdir(str.c_str());
4789#else
4790 status = mkdir(str.c_str(), 0755);
4791#endif
4792#if defined(EEXIST)
4793 if (status == -1 && errno != EEXIST)
4794 cm_msg(MERROR, "log_generate_file_name", "Cannot create subdirectory \"%s\", mkdir() errno %d (%s)", str.c_str(), errno, strerror(errno));
4795#endif
4796
4797 str += filename;
4798 } else {
4799 str = filename;
4800 }
4801
4802 /* check if two "%" are present in filename */
4803 if (strchr(str.c_str(), '%')) {
4804 if (strchr(strchr(str.c_str(), '%')+1, '%')) {
4805 /* substitude first "%d" by current run number, second "%d" by subrun number */
4806 path = msprintf(str.c_str(), run_number, log_chn->subrun_number);
4807 } else {
4808 /* substitue "%d" by current run number */
4809 path = msprintf(str.c_str(), run_number);
4810 }
4811 } else {
4812 path = str;
4813 }
4814
4815 /* add required file extension */
4816 if (log_chn->writer) {
4817 path += log_chn->writer->wr_get_file_ext();
4818 }
4819
4820 log_chn->path = path;
4821
4822 /* write back current file name to ODB */
4823 std::string tmpstr;
4824 if (strncmp(path.c_str(), data_dir.c_str(), data_dir.length()) == 0)
4825 tmpstr = path.c_str() + data_dir.length();
4826 else
4827 tmpstr = path;
4828 char cstr[256];
4829 mstrlcpy(cstr, tmpstr.c_str(), sizeof(cstr));
4830 db_set_value(hDB, log_chn->settings_hkey, "Current filename", cstr, 256, 1, TID_STRING);
4831
4832 /* construct full pipe command */
4833 if (ispipe) {
4834 /* check if %d must be substitude by current run number in pipe command options */
4835 if (strchr(log_chn->pipe_command.c_str(), '%')) {
4836 std::string str = log_chn->pipe_command;
4837 if (strchr(strchr(str.c_str(), '%')+1, '%')) {
4838 /* substitude first "%d" by current run number, second "%d" by subrun number */
4839 log_chn->pipe_command = msprintf(str.c_str(), run_number, log_chn->subrun_number);
4840 } else {
4841 /* substitue "%d" by current run number */
4842 log_chn->pipe_command = msprintf(str.c_str(), run_number);
4843 }
4844 } else {
4845 }
4846 /* add a space */
4847 if (log_chn->pipe_command.back() != ' ')
4848 log_chn->pipe_command += " ";
4849 /* add generated filename to pipe command */
4850 log_chn->pipe_command += path;
4851 //printf("pipe command [%s]\n", log_chn->pipe_command.c_str());
4852 }
4853
4854 return CM_SUCCESS;
4855}
4856
4857/*------------------------------------------------------------------*/
4858
4859/********************************************************************\
4860
4861 transition callbacks
4862
4863\********************************************************************/
4864
4865/*------------------------------------------------------------------*/
4866
4867int close_channels(int run_number, BOOL* p_tape_flag)
4868{
4869 BOOL tape_flag = FALSE;
4870
4871 for (unsigned i = 0; i < log_channels.size(); i++) {
4872 LOG_CHN* chn = log_channels[i];
4873 if (chn->handle || chn->ftp_con|| chn->pfile) {
4874 /* generate MTALK message */
4875#ifndef FAL_MAIN
4876 /* wait until buffer is empty */
4877 if (chn->buffer_handle) {
4878#ifdef DELAYED_STOP
4879 DWORD start_time = ss_millitime();
4880 do {
4881 cm_yield(100);
4882 } while (ss_millitime() - start_time < DELAYED_STOP);
4883#else
4884 INT n_bytes;
4885 do {
4886 bm_get_buffer_level(chn->buffer_handle, &n_bytes);
4887 if (n_bytes > 0)
4888 cm_yield(100);
4889 } while (n_bytes > 0);
4890#endif
4891 }
4892#endif /* FAL_MAIN */
4893
4894 /* close logging channel */
4895 log_close(chn, run_number);
4896
4897 /* close statistics record */
4898 db_set_record(hDB, chn->stats_hkey, &chn->statistics, sizeof(CHN_STATISTICS), 0);
4901 chn->stats_hkey = 0;
4902 chn->settings_hkey = 0;
4903 }
4904 }
4905
4906 if (p_tape_flag)
4907 *p_tape_flag = tape_flag;
4908
4909 return SUCCESS;
4910}
4911
4913{
4914 /* close buffers */
4915 for (unsigned i = 0; i < log_channels.size(); i++) {
4916 LOG_CHN* chn = log_channels[i];
4917#ifndef FAL_MAIN
4918 if (chn->buffer_handle) {
4920 for (unsigned j = i + 1; j < log_channels.size(); j++)
4921 if (log_channels[j]->buffer_handle == chn->buffer_handle)
4922 log_channels[j]->buffer_handle = 0;
4923 }
4924
4925 if (chn->msg_request_id)
4927#endif
4928
4929 delete chn;
4930 log_channels[i] = NULL;
4931 }
4932
4933 log_channels.clear();
4934
4935 return SUCCESS;
4936}
4937
4938/*------------------------------------------------------------------*/
4939
4941{
4942 DWORD eb[2];
4943 eb[0] = transition;
4944 eb[1] = run_number;
4945
4946 time_t now = time(NULL);
4947
4948 for (unsigned h=0; h<mh.size(); h++)
4949 mh[h]->hs_write_event("Run transitions", now, sizeof(eb), (const char*)eb);
4950
4951 return SUCCESS;
4952}
4953
4954/*------------------------------------------------------------------*/
4955
4957{
4958 int status;
4959 assert(info != NULL);
4960 LOG_CHN *log_chn = (LOG_CHN*)info;
4961 int size = sizeof(CHN_SETTINGS);
4962 status = db_get_record1(hDB, log_chn->settings_hkey, &log_chn->settings, &size, 0, strcomb1(chn_settings_str).c_str());
4963 if (status != DB_SUCCESS) {
4964 cm_msg(MINFO, "watch_settings", "db_get_record(%s) status %d", log_chn->name.c_str(), status);
4965 return;
4966 }
4967
4968 if (verbose)
4969 printf("Channel %s settings updated\n", log_chn->name.c_str());
4970}
4971
4972/*------------------------------------------------------------------*/
4973
4975/********************************************************************\
4976
4977 Prestart:
4978
4979 Loop through channels defined in /logger/channels.
4980 Neglect channels with are not active.
4981 If "filename" contains a "%", substitute it by the
4982 current run number. Open logging channel and
4983 corresponding buffer. Place a event request
4984 into the buffer.
4985
4986\********************************************************************/
4987{
4988 INT size, status;
4989 HNDLE hKeyRoot, hKeyChannel;
4990 CHN_SETTINGS *chn_settings;
4991 KEY key;
4992 BOOL write_data, tape_flag = FALSE;
4993 HNDLE hDB;
4994
4995 if (verbose)
4996 printf("tr_start: run %d\n", run_number);
4997
4998 assert(error != NULL);
4999
5000 DWORD t0 = ss_millitime();
5001
5003
5004 /* save current ODB */
5005 std::string str = "last.json";
5006 db_get_value_string(hDB, 0, "/Logger/ODB Last Dump File", 0, &str, TRUE);
5007 odb_save(str.c_str(), false);
5008
5009 DWORD t1 = ss_millitime();
5010
5012
5014 close_buffers();
5015
5016 DWORD t2 = ss_millitime();
5017
5019
5021
5022 /* read global logging flag */
5023 size = sizeof(BOOL);
5024 write_data = TRUE;
5025 db_get_value(hDB, 0, "/Logger/Write data", &write_data, &size, TID_BOOL, TRUE);
5026
5027 /* read tape message flag */
5028 size = sizeof(tape_message);
5029 db_get_value(hDB, 0, "/Logger/Tape message", &tape_message, &size, TID_BOOL, TRUE);
5030
5031 /* reset next subrun flag */
5032 status = FALSE;
5033 db_set_value(hDB, 0, "/Logger/Next subrun", &status, sizeof(status), 1, TID_BOOL);
5034
5035 /* loop over all channels */
5036 status = db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot);
5037 if (status != DB_SUCCESS) {
5038 /* if no channels are defined, define at least one */
5039 status = db_create_record(hDB, 0, "/Logger/Channels/0/", strcomb1(chn_tree_str).c_str());
5040 if (status != DB_SUCCESS) {
5041 strcpy(error, "Cannot create channel entry in database");
5042 cm_msg(MERROR, "tr_start", "%s", error);
5043 return 0;
5044 }
5045
5046 status = db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot);
5047 if (status != DB_SUCCESS) {
5048 strcpy(error, "Cannot create channel entry in database");
5049 cm_msg(MERROR, "tr_start", "%s", error);
5050 return 0;
5051 }
5052 }
5053
5054 // after close_buffers() all log channels are closed and deleted
5055 assert(log_channels.size() == 0);
5056
5057 for (unsigned index = 0; ; index++) {
5058 status = db_enum_key(hDB, hKeyRoot, index, &hKeyChannel);
5060 break;
5061
5062 /* correct channel record */
5063 db_get_key(hDB, hKeyChannel, &key);
5064 status = db_check_record(hDB, hKeyRoot, key.name, strcomb1(chn_tree_str).c_str(), TRUE);
5065 if (status != DB_SUCCESS && status != DB_OPEN_RECORD) {
5066 cm_msg(MERROR, "tr_start", "Cannot create/check channel record, status %d", status);
5067 break;
5068 }
5069
5070 if (status == DB_SUCCESS || status == DB_OPEN_RECORD) {
5071 LOG_CHN* chn = new_LOG_CHN(key.name);
5072
5073 log_channels.push_back(chn);
5074
5075 /* save settings key */
5076 status = db_find_key(hDB, hKeyChannel, "Settings", &chn->settings_hkey);
5077 if (status != DB_SUCCESS) {
5078 strcpy(error, "Cannot find channel settings info");
5079 cm_msg(MERROR, "tr_start", "%s", error);
5080 return 0;
5081 }
5082
5083 /* save statistics key */
5084 status = db_find_key(hDB, hKeyChannel, "Statistics", &chn->stats_hkey);
5085 if (status != DB_SUCCESS) {
5086 strcpy(error, "Cannot find channel statistics info");
5087 cm_msg(MERROR, "tr_start", "%s", error);
5088 return 0;
5089 }
5090
5091 /* clear statistics */
5092 size = sizeof(CHN_STATISTICS);
5093 db_get_record1(hDB, chn->stats_hkey, &chn->statistics, &size, 0, strcomb1(chn_statistics_str).c_str());
5094
5095 chn->statistics.events_written = 0;
5096 chn->statistics.bytes_written = 0;
5099
5100 db_set_record(hDB, chn->stats_hkey, &chn->statistics, size, 0);
5101
5102 /* get channel info structure */
5103 chn_settings = &chn->settings;
5104 size = sizeof(CHN_SETTINGS);
5105 status = db_get_record1(hDB, chn->settings_hkey, chn_settings, &size, 0, strcomb1(chn_settings_str).c_str());
5106 if (status != DB_SUCCESS) {
5107 strcpy(error, "Cannot read channel info");
5108 cm_msg(MERROR, "tr_start", "%s", error);
5109 return 0;
5110 }
5111
5112 chn->pre_checksum_module = select_checksum_module(hDB, chn->settings_hkey, "data checksum");
5113 chn->post_checksum_module = select_checksum_module(hDB, chn->settings_hkey, "file checksum");
5115 chn->output_module = select_output_module(hDB, chn->settings_hkey, "output");
5116
5117 //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);
5118
5119 /* check if active */
5120 if (!chn_settings->active || !write_data)
5121 continue;
5122
5123 /* initialize subrun number */
5124 chn->subrun_number = 0;
5125
5126 log_create_writer(chn);
5128
5129 /* open logging channel */
5130 status = log_open(chn, run_number);
5131
5132 /* return if logging channel couldn't be opened */
5133 if (status != SS_SUCCESS) {
5134 if (status == SS_FILE_ERROR)
5135 sprintf(error, "Cannot open file \'%s\' (See messages)", chn->path.c_str());
5136 if (status == SS_FILE_EXISTS)
5137 sprintf(error, "File \'%s\' exists already, run start aborted", chn->path.c_str());
5138 if (status == SS_NO_TAPE)
5139 sprintf(error, "No tape in device \'%s\'", chn->path.c_str());
5140 if (status == SS_TAPE_ERROR)
5141 sprintf(error, "Tape error, cannot start run");
5142 if (status == SS_DEV_BUSY)
5143 sprintf(error, "Device \'%s\' used by someone else", chn->path.c_str());
5145 sprintf(error, "Cannot open FTP channel to \'%s\'", chn->path.c_str());
5146 if (status == SS_NO_ROOT)
5147 sprintf(error, "No ROOT support compiled into mlogger, please compile with -DHAVE_ROOT flag");
5148
5150 sprintf(error, "Invalid data format, please use \"MIDAS\", \"ASCII\", \"DUMP\" or \"ROOT\"");
5151
5152 cm_msg(MERROR, "tr_start", "%s", error);
5153 return 0;
5154 }
5155
5156 /* close records if open from previous run start with abort */
5157 if (chn->stats_hkey)
5159 if (chn->settings_hkey)
5161
5162 /* open hot link to statistics tree */
5163 status = db_open_record1(hDB, chn->stats_hkey, &chn->statistics, sizeof(CHN_STATISTICS), MODE_WRITE, NULL, NULL, strcomb1(chn_statistics_str).c_str());
5164 if (status == DB_NO_ACCESS) {
5165 /* record is probably still in exclusive access by dead logger, so reset it */
5167 if (status != DB_SUCCESS)
5168 cm_msg(MERROR, "tr_start", "Cannot change access mode for statistics record, error %d", status);
5169 else
5170 cm_msg(MINFO, "tr_start", "Recovered access mode for statistics record of channel \"%s\"", chn->name.c_str());
5171 status = db_open_record1(hDB, chn->stats_hkey, &chn->statistics, sizeof(CHN_STATISTICS), MODE_WRITE, NULL, NULL, strcomb1(chn_statistics_str).c_str());
5172 }
5173
5174 if (status != DB_SUCCESS)
5175 cm_msg(MERROR, "tr_start", "Cannot open statistics record for channel \"%s\", error %d", chn->name.c_str(), status);
5176
5177 /* open hot link to settings tree */
5179 if (status != DB_SUCCESS)
5180 cm_msg(MERROR, "tr_start", "db_watch() status %d, cannot open channel settings record, probably other logger is using it", status);
5181
5182#ifndef FAL_MAIN
5183 /* open buffer */
5185 if (status != BM_SUCCESS && status != BM_CREATED) {
5186 sprintf(error, "Cannot open buffer %s", chn_settings->buffer);
5187 cm_msg(MERROR, "tr_start", "%s", error);
5188 return 0;
5189 }
5190 bm_set_cache_size(chn->buffer_handle, 1000000, 0);
5191
5192 /* place event request */
5193 status = bm_request_event(chn->buffer_handle, (short) chn_settings->event_id, (short) chn_settings->trigger_mask, GET_ALL, &chn->request_id, receive_event);
5194
5195 if (status != BM_SUCCESS) {
5196 sprintf(error, "Cannot place event request");
5197 cm_msg(MERROR, "tr_start", "%s", error);
5198 return 0;
5199 }
5200
5201 /* open message buffer if requested */
5202 if (chn_settings->log_messages) {
5204 if (status != BM_SUCCESS && status != BM_CREATED) {
5205 sprintf(error, "Cannot open buffer %s", MESSAGE_BUFFER_NAME);
5206 cm_msg(MERROR, "tr_start", "%s", error);
5207 return 0;
5208 }
5209
5210 /* place event request */
5212
5213 if (status != BM_SUCCESS) {
5214 sprintf(error, "Cannot place event request");
5215 cm_msg(MERROR, "tr_start", "%s", error);
5216 return 0;
5217 }
5218 }
5219#endif
5220 }
5221 }
5222
5223 DWORD t3 = ss_millitime();
5224
5225 if (tape_flag && tape_message)
5226 cm_msg(MTALK, "tr_start", "tape mounting finished");
5227
5228 /* write transition event into history */
5230
5231 DWORD t4 = ss_millitime();
5232
5233#ifdef HAVE_MYSQL
5234 /* write to SQL database if requested */
5235 write_runlog_sql(TRUE);
5236#endif
5237
5238 /* write to runlog file(s) if requested */
5241
5242 DWORD t5 = ss_millitime();
5243 DWORD te = t5;
5244
5245 if (verbose)
5246 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",
5247 run_number,
5248 te-t0,
5249 t1-t0,
5250 t2-t1,
5251 t3-t2,
5252 t4-t3,
5253 t5-t4
5254 );
5255
5258
5260
5261 return CM_SUCCESS;
5262}
5263
5264/*-- -------- ------------------------------------------------------*/
5265
5267{
5268 if (verbose)
5269 printf("tr_start_abort: run %d\n", run_number);
5270
5272
5273 for (unsigned i = 0; i < log_channels.size(); i++) {
5274 LOG_CHN* chn = log_channels[i];
5275 if (chn->handle && chn->type == LOG_TYPE_DISK) {
5276 cm_msg(MINFO, "tr_start_abort", "Deleting previous file \"%s\"", chn->path.c_str());
5277 unlink(chn->path.c_str());
5278 }
5279 }
5280
5282 close_buffers();
5283
5285
5287
5289
5290 return CM_SUCCESS;
5291}
5292
5293/*-- poststop ------------------------------------------------------*/
5294
5296/********************************************************************\
5297
5298 Poststop:
5299
5300 Wait until buffers are empty, then close logging channels
5301
5302\********************************************************************/
5303{
5304 INT size;
5305 BOOL flag, tape_flag = FALSE;
5306 char filename[256];
5307 char str[256];
5308
5309 if (verbose)
5310 printf("tr_stop: run %d\n", run_number);
5311
5313 return CM_SUCCESS;
5314
5315 DWORD t0 = ss_millitime();
5316
5318
5319 close_channels(run_number, &tape_flag);
5320 close_buffers();
5321
5322 DWORD t1 = ss_millitime();
5323
5324 /* ODB dump if requested */
5325 size = sizeof(flag);
5326 flag = 0;
5327 db_get_value(hDB, 0, "/Logger/ODB Dump", &flag, &size, TID_BOOL, TRUE);
5328 if (flag) {
5329 strcpy(str, "run%d.json");
5330 size = sizeof(str);
5331 str[0] = 0;
5332 db_get_value(hDB, 0, "/Logger/ODB Dump File", str, &size, TID_STRING, TRUE);
5333 if (str[0] == 0)
5334 strcpy(str, "run%d.json");
5335
5336 /* substitue "%d" by current run number */
5337 if (strchr(str, '%'))
5338 sprintf(filename, str, run_number);
5339 else
5340 strcpy(filename, str);
5341
5342 odb_save(filename, true);
5343 }
5344
5345 DWORD t2 = ss_millitime();
5346
5347#ifdef HAVE_MYSQL
5348 /* write to SQL database if requested */
5349 write_runlog_sql(FALSE);
5350#endif
5351
5352 /* write to ASCII file(s) if requested */
5355
5356 DWORD t3 = ss_millitime();
5357
5359
5360 if (tape_flag & tape_message)
5361 cm_msg(MTALK, "tr_stop", "all tape channels closed");
5362
5363 /* write transition event into history */
5365
5366 DWORD t4 = ss_millitime();
5367
5368 /* clear flag */
5370 stop_try_later = 0;
5371
5372 if (start_requested) {
5373 int delay = 0;
5374 size = sizeof(delay);
5375 db_get_value(hDB, 0, "/Logger/Auto restart delay", &delay, &size, TID_INT32, TRUE);
5376 auto_restart = ss_time() + delay; /* start after specified delay */
5378 }
5379
5380 DWORD te = t4;
5381
5382 if (verbose)
5383 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",
5384 run_number,
5385 te-t0,
5386 t1-t0,
5387 t2-t1,
5388 t3-t2,
5389 t4-t3);
5390
5391
5393
5395
5396 return CM_SUCCESS;
5397}
5398
5399/*== common code FAL/MLOGGER end ===================================*/
5400
5401/*----- pause/resume -----------------------------------------------*/
5402
5404{
5405 /* write transition event into history */
5407
5409
5411
5412 return CM_SUCCESS;
5413}
5414
5416{
5417 /* write transition event into history */
5419
5421
5423
5424 return CM_SUCCESS;
5425}
5426
5427/*----- receive_event ----------------------------------------------*/
5428
5429void receive_event(HNDLE hBuf, HNDLE request_id, EVENT_HEADER * pheader, void *pevent)
5430{
5431 if (verbose)
5432 printf("write data event: req %d, evid %d, timestamp %d, size %d\n", request_id, pheader->event_id, pheader->time_stamp, pheader->data_size);
5433
5434 /* find logging channel for this request id */
5435 for (unsigned i = 0; i < log_channels.size(); i++) {
5436 LOG_CHN* chn = log_channels[i];
5437 if (chn->handle == 0 && chn->ftp_con == NULL)
5438 continue;
5439
5440 /* write normal events */
5441 if (chn->request_id == request_id) {
5442 log_write(chn, pheader);
5443 break;
5444 }
5445
5446 /* write messages */
5447 if (chn->msg_request_id == request_id) {
5448 log_write(chn, pheader);
5449 break;
5450 }
5451 }
5452}
5453
5454/*------------------------ main ------------------------------------*/
5455
5456int main(int argc, char *argv[])
5457{
5458 INT status, msg, i, size, ch = 0;
5460 BOOL debug, daemon, save_mode;
5461 DWORD last_time_kb = 0;
5462 DWORD last_time_stat = 0;
5463 DWORD duration;
5464
5465#ifdef SIGPIPE
5466 // undo ROOT overwrites SIGPIPE
5467 signal(SIGPIPE, SIG_IGN);
5468#endif
5469
5470 setbuf(stdout, NULL);
5471 setbuf(stderr, NULL);
5472
5473 /* get default from environment */
5475
5476 debug = daemon = save_mode = FALSE;
5477
5478 /* parse command line parameters */
5479 for (i = 1; i < argc; i++) {
5480 if (argv[i][0] == '-' && argv[i][1] == 'd')
5481 debug = TRUE;
5482 else if (argv[i][0] == '-' && argv[i][1] == 'D')
5483 daemon = TRUE;
5484 else if (argv[i][0] == '-' && argv[i][1] == 's')
5485 save_mode = TRUE;
5486 else if (argv[i][0] == '-' && argv[i][1] == 'v')
5487 verbose = TRUE;
5488 else if (argv[i][0] == '-') {
5489 if (i + 1 >= argc || argv[i + 1][0] == '-')
5490 goto usage;
5491 if (argv[i][1] == 'e')
5492 strcpy(exp_name, argv[++i]);
5493 else {
5494 usage:
5495 printf("usage: mlogger [-e Experiment] [-d] [-D] [-s] [-v]\n\n");
5496 return 1;
5497 }
5498 }
5499 }
5500
5501 if (daemon) {
5502 printf("Becoming a daemon...\n");
5504 }
5505
5506 status = cm_connect_experiment(host_name, exp_name, "Logger", NULL);
5507 if (status != CM_SUCCESS)
5508 return 1;
5509
5510 /* check if logger already running */
5511 status = cm_exist("Logger", FALSE);
5512 if (status == CM_SUCCESS) {
5513 printf("Logger runs already.\n");
5515 return 1;
5516 }
5517
5519
5520 /* turn off watchdog if in debug mode */
5521 if (debug)
5523
5524 /* turn on save mode */
5525 if (save_mode) {
5528 }
5529
5530 /* register transition callbacks */
5532 cm_msg(MERROR, "main", "cannot register callbacks");
5533 return 1;
5534 }
5535
5540
5541 /* initialize ODB */
5542 logger_init();
5543
5544 /* obtain current state */
5546 size = sizeof(local_state);
5547 status = db_get_value(hDB, 0, "/Runinfo/State", &local_state, &size, TID_INT32, true);
5548
5549 /* open history logging */
5550 if (open_history() != CM_SUCCESS) {
5551 printf("Error in history system, aborting startup.\n");
5553 return 1;
5554 }
5555
5556 /* print startup message */
5557 std::string data_dir;
5558 db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &data_dir, TRUE);
5559 if (data_dir.length() <= 0)
5560 data_dir = cm_get_path();
5561 printf("Data directory is \"%s\" unless specified under /Logger/channels/\n", data_dir.c_str());
5562
5563 /* Alternate message path */
5564 std::string message_dir;
5565 db_get_value_string(hDB, 0, "/Logger/Message dir", 0, &message_dir, TRUE);
5566 if (message_dir.empty()) {
5567 message_dir = data_dir;
5568 printf("Message directory is \"%s\" unless specified in /Logger/Message dir\n", message_dir.c_str());
5569 } else
5570 printf("Message directory is \"%s\"\n", message_dir.c_str());
5571
5572 /* Alternate History and Elog path */
5573 std::string history_dir;
5574 db_get_value_string(hDB, 0, "/Logger/History dir", 0, &history_dir, TRUE);
5575 if (history_dir.empty()) {
5576 history_dir = data_dir;
5577 printf("History directory is \"%s\" unless specified under /Logger/history/\n", history_dir.c_str());
5578 } else
5579 printf("History directory is \"%s\"\n", history_dir.c_str());
5580
5581#ifdef HAVE_MYSQL
5582 {
5583 std::string sql_host;
5584 std::string sql_db;
5585 std::string sql_table;
5586
5587 HNDLE hktemp;
5588 status = db_find_key(hDB, 0, "/Logger/Runlog/SQL/Hostname", &hktemp);
5589 if (status == DB_SUCCESS) {
5590 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Hostname", 0, &sql_host, FALSE);
5591 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Database", 0, &sql_db, FALSE);
5592 db_get_value_string(hDB, 0, "/Logger/Runlog/SQL/Table", 0, &sql_table, FALSE);
5593 printf("SQL database is %s/%s/%s", sql_host.c_str(), sql_db.c_str(), sql_table.c_str());
5594 }
5595 }
5596#endif
5597
5598 printf("\nMIDAS logger started. Stop with \"!\"\n");
5599
5600 /* initialize ss_getchar() */
5601 ss_getchar(0);
5602
5603 /* start image history threads */
5605
5606 do {
5607 msg = cm_yield(100);
5608
5609 /* maybe update channel disk levels */
5611
5612 /* update channel statistics once every second */
5613 if (ss_millitime() - last_time_stat > 1000) {
5614 last_time_stat = ss_millitime();
5615 /*
5616 printf("update statistics!\n");
5617 //LOG_CHN* log_chn = log_chn[0];
5618 printf("events %.0f, subrun %.0f, written %.0f, total %.0f\n", log_chn->statistics.events_written,
5619 log_chn->statistics.bytes_written_subrun,
5620 log_chn->statistics.bytes_written,
5621 log_chn->statistics.bytes_written_total);
5622 */
5624 }
5625
5626 /* check for auto restart */
5627 if (auto_restart && ss_time() > auto_restart) {
5629 }
5630
5631 /* check if time is reached to stop run */
5632 duration = 0;
5633 size = sizeof(duration);
5634 db_get_value(hDB, 0, "/Logger/Run duration", &duration, &size, TID_UINT32, true);
5636 duration > 0 && ss_time() >= run_start_time + duration) {
5637 cm_msg(MTALK, "main", "stopping run after %d seconds", duration);
5638 status = stop_the_run(1);
5639 }
5640
5641 /* stop the run if previous attempt failed */
5642 if (stop_try_later) {
5643 if (ss_time_sec() > stop_try_later) {
5644 cm_msg(MTALK, "main", "another attempt to stop the run");
5645 status = stop_the_run(0);
5646 }
5647 }
5648
5649 /* check keyboard once every 100 ms */
5650 if (ss_millitime() - last_time_kb > 100) {
5651 last_time_kb = ss_millitime();
5652
5653 ch = 0;
5654 while (ss_kbhit()) {
5655 ch = ss_getchar(0);
5656 if (ch == -1)
5657 ch = getchar();
5658
5659 if ((char) ch == '!')
5660 break;
5661 }
5662 }
5663
5664 } while (msg != RPC_SHUTDOWN && msg != SS_ABORT && ch != '!');
5665
5666 /* reset terminal */
5668
5669 /* close history logging */
5670 close_history();
5671
5672 /* stop image history threads */
5674 printf("Stopping image history threads...");
5675 fflush(stdout);
5677 printf("ok\n");
5678 }
5679
5681
5682 return 0;
5683}
5684
5685/* emacs
5686 * Local Variables:
5687 * tab-width: 8
5688 * c-basic-offset: 3
5689 * indent-tabs-mode: nil
5690 * End:
5691 */
#define FALSE
Definition cfortran.h:309
char type[NAME_LENGTH]
history channel name
Definition history.h:112
char name[NAME_LENGTH]
Definition history.h:111
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:1045
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1064
uint32_t fCrc32
Definition mlogger.cxx:1109
std::string wr_get_file_ext()
Definition mlogger.cxx:1098
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1022
std::string wr_get_chain()
Definition mlogger.cxx:1102
WriterCRC32C(LOG_CHN *log_chn, int level, WriterInterface *wr)
Definition mlogger.cxx:1003
WriterInterface * fWr
Definition mlogger.cxx:1108
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:948
std::string wr_get_file_ext()
Definition mlogger.cxx:982
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:929
WriterCRC32Zlib(LOG_CHN *log_chn, int level, WriterInterface *wr)
Definition mlogger.cxx:887
WriterInterface * fWr
Definition mlogger.cxx:992
std::string wr_get_chain()
Definition mlogger.cxx:986
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:906
std::string fFilename
Definition mlogger.cxx:574
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:546
WriterFile(LOG_CHN *log_chn)
Definition mlogger.cxx:478
std::string wr_get_chain()
Definition mlogger.cxx:568
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:521
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:492
FTP_CON * fFtp
Definition mlogger.cxx:2986
std::string wr_get_file_ext()
Definition mlogger.cxx:2975
WriterFtp(LOG_CHN *log_chn)
Definition mlogger.cxx:2892
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:2911
std::string wr_get_chain()
Definition mlogger.cxx:2980
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:2932
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:2959
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:655
std::string wr_get_chain()
Definition mlogger.cxx:725
WriterGzip(LOG_CHN *log_chn, int compress)
Definition mlogger.cxx:585
std::string wr_get_file_ext()
Definition mlogger.cxx:720
int fCompress
Definition mlogger.cxx:733
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:689
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:605
std::string fFilename
Definition mlogger.cxx:731
time_t fLastCheckTime
Definition mlogger.cxx:734
gzFile fGzfp
Definition mlogger.cxx:732
virtual ~WriterInterface()
Definition mlogger.cxx:387
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:388
virtual int wr_write(LOG_CHN *log_chn, const void *data, const int size)=0
std::string wr_get_file_ext()
Definition mlogger.cxx:1573
int fBlockSize
Definition mlogger.cxx:1587
MLZ4F_compressionContext_t fContext
Definition mlogger.cxx:1583
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:1479
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1421
MLZ4F_preferences_t fPrefs
Definition mlogger.cxx:1584
WriterInterface * fWr
Definition mlogger.cxx:1582
int fBufferSize
Definition mlogger.cxx:1586
WriterLZ4(LOG_CHN *log_chn, WriterInterface *wr)
Definition mlogger.cxx:1399
char * fBuffer
Definition mlogger.cxx:1585
std::string wr_get_chain()
Definition mlogger.cxx:1577
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1519
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:425
std::string wr_get_file_ext()
Definition mlogger.cxx:459
bool fSimulateCompression
Definition mlogger.cxx:470
WriterNull(LOG_CHN *log_chn)
Definition mlogger.cxx:412
std::string wr_get_chain()
Definition mlogger.cxx:464
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:449
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:437
std::string fCommand
Definition mlogger.cxx:875
std::string wr_get_file_ext()
Definition mlogger.cxx:862
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:761
time_t fLastCheckTime
Definition mlogger.cxx:877
FILE * fFp
Definition mlogger.cxx:873
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:831
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:792
WriterPopen(LOG_CHN *log_chn, const char *pipe_command, const char *file_ext)
Definition mlogger.cxx:742
std::string fFileExt
Definition mlogger.cxx:876
std::string wr_get_chain()
Definition mlogger.cxx:867
std::string fPipeCommand
Definition mlogger.cxx:874
std::string toHex(unsigned char c)
Definition mlogger.cxx:1183
std::string wr_get_chain()
Definition mlogger.cxx:1242
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1198
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1141
WriterSHA256(LOG_CHN *log_chn, int level, WriterInterface *wr)
Definition mlogger.cxx:1119
std::string toString(const unsigned char sha256sum[32])
Definition mlogger.cxx:1190
mbedtls_sha256_context fCtx
Definition mlogger.cxx:1249
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:1164
std::string wr_get_file_ext()
Definition mlogger.cxx:1238
WriterInterface * fWr
Definition mlogger.cxx:1248
int wr_write(LOG_CHN *log_chn, const void *data, const int size)
Definition mlogger.cxx:1304
std::string toString(const unsigned char sha512sum[64])
Definition mlogger.cxx:1330
mbedtls_sha512_context fCtx
Definition mlogger.cxx:1389
std::string toHex(unsigned char c)
Definition mlogger.cxx:1323
std::string wr_get_file_ext()
Definition mlogger.cxx:1378
std::string wr_get_chain()
Definition mlogger.cxx:1382
int wr_close(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1338
WriterSHA512(LOG_CHN *log_chn, int level, WriterInterface *wr)
Definition mlogger.cxx:1259
WriterInterface * fWr
Definition mlogger.cxx:1388
int wr_open(LOG_CHN *log_chn, int run_number)
Definition mlogger.cxx:1281
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()
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 bm_open_buffer(const char *buffer_name, INT buffer_size, INT *buffer_handle)
Definition midas.cxx:6728
INT bm_delete_request(INT request_id)
Definition midas.cxx:8595
INT bm_request_event(HNDLE buffer_handle, short int event_id, short int trigger_mask, INT sampling_type, HNDLE *request_id, EVENT_HANDLER *func)
Definition midas.cxx:8476
INT bm_set_cache_size(INT buffer_handle, size_t read_size, size_t write_size)
Definition midas.cxx:8151
INT bm_close_buffer(INT buffer_handle)
Definition midas.cxx:7107
INT bm_compose_event(EVENT_HEADER *event_header, short int event_id, short int trigger_mask, DWORD data_size, DWORD serial)
Definition midas.cxx:8292
INT cm_register_transition(INT transition, INT(*func)(INT, char *), INT sequence_number)
Definition midas.cxx:3617
INT cm_yield(INT millisec)
Definition midas.cxx:5660
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3027
INT cm_connect_experiment(const char *host_name, const char *exp_name, const char *client_name, void(*func)(char *))
Definition midas.cxx:2294
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5304
INT cm_disconnect_experiment(void)
Definition midas.cxx:2862
std::string cm_get_path()
Definition midas.cxx:1553
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2150
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3299
INT cm_exist(const char *name, BOOL bUnique)
Definition midas.cxx:7531
static void xwrite(const char *filename, int fd, const void *data, int size)
Definition elog.cxx:70
#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:649
#define DB_SUCCESS
Definition midas.h:632
#define DB_NO_KEY
Definition midas.h:643
#define DB_OPEN_RECORD
Definition midas.h:651
#define DB_NO_MORE_SUBKEYS
Definition midas.h:647
#define DB_TRUNCATED
Definition midas.h:645
#define SS_SUCCESS
Definition midas.h:664
#define SS_TAPE_ERROR
Definition midas.h:683
#define SS_ABORT
Definition midas.h:678
#define SS_FILE_EXISTS
Definition midas.h:687
#define SS_FILE_ERROR
Definition midas.h:670
#define SS_NO_TAPE
Definition midas.h:680
#define SS_INVALID_FORMAT
Definition midas.h:689
#define SS_DEV_BUSY
Definition midas.h:681
#define SS_NO_ROOT
Definition midas.h:690
#define RPC_SHUTDOWN
Definition midas.h:708
#define HS_SUCCESS
Definition midas.h:728
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 MLOG
Definition midas.h:563
#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:501
#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
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:881
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:931
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3285
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6917
INT db_send_changed_records()
Definition odb.cxx:13809
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5185
INT db_save_json(HNDLE hDB, HNDLE hKey, const char *filename, int flags)
Definition odb.cxx:10548
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:13322
std::string strcomb1(const char **list)
Definition odb.cxx:668
INT db_save_xml(HNDLE hDB, HNDLE hKey, const char *filename)
Definition odb.cxx:9503
INT db_get_path(HNDLE hDB, HNDLE hKey, char *path, INT buf_size)
Definition odb.cxx:4775
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition odb.cxx:11834
INT db_copy(HNDLE hDB, HNDLE hKey, char *buffer, INT *buffer_size, const char *path)
Definition odb.cxx:8230
INT db_get_record_size(HNDLE hDB, HNDLE hKey, INT align, INT *buf_size)
Definition odb.cxx:11640
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6563
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3392
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:13003
INT db_copy_json_save(HNDLE hDB, HNDLE hKey, char **buffer, int *buffer_size, int *buffer_end)
Definition odb.cxx:10496
INT db_copy_xml(HNDLE hDB, HNDLE hKey, char *buffer, int *buffer_size, bool header)
Definition odb.cxx:9055
INT db_unwatch(HNDLE hDB, HNDLE hKey)
Definition odb.cxx:13920
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition odb.cxx:8040
INT db_save(HNDLE hDB, HNDLE hKey, const char *filename, BOOL bRemote)
Definition odb.cxx:9263
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6043
INT db_get_link(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6096
INT EXPRT db_get_value_string(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, int index, std::string *s, BOOL create, int create_string_length)
Definition odb.cxx:13967
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13845
INT db_enum_link(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5495
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:10405
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10865
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:5028
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4256
BOOL ends_with_ustring(const char *str, const char *suffix)
Definition odb.cxx:3306
void json_write(char **buffer, int *buffer_size, int *buffer_end, int level, const char *s, int quoted)
Definition odb.cxx:9550
static DATABASE * db_lock_database(HNDLE hDB, int *pstatus, const char *caller, bool check_attached=true)
Definition odb.cxx:2508
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:13473
INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size, INT align)
Definition odb.cxx:12320
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5357
static void db_unlock_database(DATABASE *pdb, const char *caller)
Definition odb.cxx:2670
INT db_close_record(HNDLE hDB, HNDLE hKey)
Definition odb.cxx:13505
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12831
INT db_create_link(HNDLE hDB, HNDLE hKey, const char *link_name, const char *destination)
Definition odb.cxx:3688
INT db_protect_database(HNDLE hDB)
Definition odb.cxx:3251
bool rpc_is_remote(void)
Definition midas.cxx:12892
const char * rpc_tid_name(INT id)
Definition midas.cxx:11895
INT rpc_tid_size(INT id)
Definition midas.cxx:11888
#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
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:7849
std::string msprintf(const char *format,...)
Definition midas.cxx:419
const char * mname[]
Definition midas.cxx:144
#define JSFLAG_RECURSE
Definition midas.h:1728
#define MIDAS_MAGIC
Definition midas.h:912
#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:1727
#define JSFLAG_OMIT_LAST_WRITTEN
Definition midas.h:1731
#define DEFAULT_BUFFER_SIZE
Definition midas.h:255
#define EVENTID_MESSAGE
Definition midas.h:903
#define JSFLAG_OMIT_NAMES
Definition midas.h:1730
#define EVENTID_EOR
Definition midas.h:902
#define JS_LEVEL_1
Definition midas.h:1724
#define TRUE
Definition midas.h:182
#define POINTER_T
Definition midas.h:166
#define JSFLAG_OMIT_OLD
Definition midas.h:1732
#define EVENTID_BOR
Definition midas.h:901
#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:3213
void log_history(HNDLE hDB, HNDLE hKey, void *info)
Definition mlogger.cxx:4606
#define FREE(ptr)
Definition mlogger.cxx:341
#define CHECKSUM_ZLIB
Definition mlogger.cxx:3116
void receive_event(HNDLE hBuf, HNDLE request_id, EVENT_HEADER *pheader, void *pevent)
Definition mlogger.cxx:5429
void create_runlog_json_tree()
Definition mlogger.cxx:2625
#define CHECKSUM_CRC32C
Definition mlogger.cxx:3117
INT tr_stop(INT run_number, char *error)
Definition mlogger.cxx:5295
#define DISK_CHECK_INTERVAL_MILLISEC
Definition mlogger.cxx:284
std::string get_value(HNDLE hDB, HNDLE hDir, const char *name)
Definition mlogger.cxx:3164
INT tr_start_abort(INT run_number, char *error)
Definition mlogger.cxx:5266
static std::vector< MidasHistoryInterface * > mh
Definition mlogger.cxx:3781
EVENT_DEF * db_get_event_definition(short int event_id)
Definition mlogger.cxx:2997
#define COMPRESS_NONE
Definition mlogger.cxx:3139
void log_odb_dump_json(LOG_CHN *log_chn, short int event_id, INT run_number)
Definition mlogger.cxx:1732
void maybe_flush_history(time_t now)
Definition mlogger.cxx:4550
void log_odb_dump(LOG_CHN *log_chn, short int event_id, INT run_number)
Definition mlogger.cxx:1759
int log_create_writer(LOG_CHN *log_chn)
Definition mlogger.cxx:3246
static int hist_log_size
Definition mlogger.cxx:308
void close_history()
Definition mlogger.cxx:4568
void stop_image_history()
INT local_state
Definition mlogger.cxx:286
#define CHN_TREE_STR(_name)
Definition mlogger.cxx:87
INT tr_pause(INT run_number, char *error)
Definition mlogger.cxx:5403
static std::vector< std::string > history_events
Definition mlogger.cxx:3782
int log_generate_file_name(LOG_CHN *log_chn)
Definition mlogger.cxx:4712
static FILE * fopen_wx(const char *filename)
Definition mlogger.cxx:360
static int get_trans_flag()
Definition mlogger.cxx:3465
void log_system_history(HNDLE hDB, HNDLE hKey, void *info)
Definition mlogger.cxx:4658
int select_checksum_module(HNDLE hDB, HNDLE hSet, const char *name)
Definition mlogger.cxx:3196
INT tr_start(INT run_number, char *error)
Definition mlogger.cxx:4974
WriterInterface * NewCompression(LOG_CHN *log_chn, int code, WriterInterface *chained)
Definition mlogger.cxx:3145
#define OUTPUT_FILE
Definition mlogger.cxx:3159
INT log_open(LOG_CHN *log_chn, INT run_number)
Definition mlogger.cxx:3325
#define OUTPUT_NULL
Definition mlogger.cxx:3158
#define EVENT_DEF_CACHE_SIZE
INT ftp_error(const char *message)
Definition mlogger.cxx:2800
time_t last_history_flush
Definition mlogger.cxx:4548
INT tr_resume(INT run_number, char *error)
Definition mlogger.cxx:5415
WriterInterface * NewChecksum(LOG_CHN *log_chn, int code, int level, WriterInterface *chained)
Definition mlogger.cxx:3121
#define MEMZERO(obj)
Definition mlogger.cxx:339
WriterInterface * NewWriterBzip2(LOG_CHN *log_chn)
Definition mlogger.cxx:3081
int maybe_check_disk_level()
Definition mlogger.cxx:3440
INT log_close(LOG_CHN *log_chn, INT run_number)
Definition mlogger.cxx:3361
void create_runlog_ascii_tree()
Definition mlogger.cxx:2466
void odb_save(const char *filename, bool make_file_readonly)
Definition mlogger.cxx:1774
void log_odb_dump_xml(LOG_CHN *log_chn, short int event_id, INT run_number)
Definition mlogger.cxx:1701
void set_value(HNDLE hDB, HNDLE hDir, const char *name, const std::string &set, const std::string &def)
Definition mlogger.cxx:3175
DWORD auto_restart
Definition mlogger.cxx:292
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:3184
int start_the_run()
Definition mlogger.cxx:3539
#define CHECKSUM_SHA256
Definition mlogger.cxx:3118
INT open_history()
Definition mlogger.cxx:3901
static std::string TimeToString(time_t t)
Definition mlogger.cxx:53
#define DELETE(ptr)
Definition mlogger.cxx:342
BOOL in_stop_transition
Definition mlogger.cxx:287
BOOL tape_message
Definition mlogger.cxx:288
#define CHN_SETTINGS_STR(_name)
Definition mlogger.cxx:191
DWORD subrun_start_time
Definition mlogger.cxx:293
INT ftp_open(const char *xdestination, FTP_CON **con)
Definition mlogger.cxx:2806
std::vector< LOG_CHN * > log_channels
Definition mlogger.cxx:296
#define OUTPUT_FTP
Definition mlogger.cxx:3160
int select_output_module(HNDLE hDB, HNDLE hSet, const char *name)
Definition mlogger.cxx:3230
#define OUTPUT_PIPE
Definition mlogger.cxx:3162
static void watch_settings(HNDLE hDB, HNDLE hKey, HNDLE index, void *info)
Definition mlogger.cxx:4956
#define CHECKSUM_NONE
Definition mlogger.cxx:3115
double stop_try_later
Definition mlogger.cxx:294
static std::string IntToString(int value)
Definition mlogger.cxx:46
int get_number_image_history_threads()
#define COMPRESS_BZIP2
Definition mlogger.cxx:3142
BOOL stop_requested
Definition mlogger.cxx:290
static HNDLE hDB
Definition mlogger.cxx:312
LOG_CHN * new_LOG_CHN(const char *name)
Definition mlogger.cxx:274
BOOL start_requested
Definition mlogger.cxx:291
static int write_history(DWORD transition, DWORD run_number)
Definition mlogger.cxx:4940
int close_buffers()
Definition mlogger.cxx:4912
DWORD run_start_time
Definition mlogger.cxx:293
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:3784
INT log_write(LOG_CHN *log_chn, EVENT_HEADER *pheader)
Definition mlogger.cxx:3600
static bool check_file_exists(const char *filename)
Definition mlogger.cxx:368
static struct hist_log_s * hist_log
Definition mlogger.cxx:310
void logger_init()
Definition mlogger.cxx:1592
void log_odb_dump_odb(LOG_CHN *log_chn, short int event_id, INT run_number)
Definition mlogger.cxx:1672
BOOL verbose
Definition mlogger.cxx:289
#define COMPRESS_PBZIP2
Definition mlogger.cxx:3143
#define CHN_STATISTICS_STR(_name)
Definition mlogger.cxx:231
void start_image_history()
static std::string xpathname(const char *xpath, int level)
Definition mlogger.cxx:346
static int hist_log_max
Definition mlogger.cxx:309
void write_runlog_json(BOOL bor)
Definition mlogger.cxx:2672
#define COMPRESS_LZ4
Definition mlogger.cxx:3141
void write_runlog_ascii(BOOL bor)
Definition mlogger.cxx:2511
int log_disk_level(LOG_CHN *log_chn, double *pdisk_size, double *pdisk_free)
Definition mlogger.cxx:3411
int close_channels(int run_number, BOOL *p_tape_flag)
Definition mlogger.cxx:4867
WriterInterface * NewWriterPbzip2(LOG_CHN *log_chn)
Definition mlogger.cxx:3093
#define CHECKSUM_SHA512
Definition mlogger.cxx:3119
#define COMPRESS_ZLIB
Definition mlogger.cxx:3140
int stop_the_run(int restart)
Definition mlogger.cxx:3505
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
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
char odb_dump_format[32]
Definition mlogger.cxx:162
uint32_t bzip2_compression
Definition mlogger.cxx:183
uint32_t pbzip2_num_cpu
Definition mlogger.cxx:184
double event_limit
Definition mlogger.cxx:168
INT obsolete_compression
Definition mlogger.cxx:160
double subrun_byte_limit
Definition mlogger.cxx:170
char filename[256]
Definition mlogger.cxx:158
double obsolete_tape_capacity
Definition mlogger.cxx:171
double byte_limit
Definition mlogger.cxx:169
uint32_t pbzip2_compression
Definition mlogger.cxx:185
DWORD log_messages
Definition mlogger.cxx:164
uint32_t gzip_compression
Definition mlogger.cxx:182
char pbzip2_options[256]
Definition mlogger.cxx:186
char buffer[32]
Definition mlogger.cxx:165
char subdir_format[32]
Definition mlogger.cxx:172
double bytes_written_subrun
Definition mlogger.cxx:226
double bytes_written_total
Definition mlogger.cxx:225
double bytes_written_uncompressed
Definition mlogger.cxx:224
double bytes_written
Definition mlogger.cxx:223
double events_written
Definition mlogger.cxx:222
double disk_level
Definition mlogger.cxx:228
double files_written
Definition mlogger.cxx:227
HNDLE hDefKey
Definition mana.cxx:450
WORD format
Definition mana.cxx:449
short int event_id
Definition mana.cxx:447
short int event_id
Definition midas.h:853
DWORD data_size
Definition midas.h:857
DWORD time_stamp
Definition midas.h:856
int data
Definition ftplib.h:27
Definition midas.h:1027
INT num_values
Definition midas.h:1029
DWORD type
Definition midas.h:1028
INT total_size
Definition midas.h:1032
char name[NAME_LENGTH]
Definition midas.h:1030
INT item_size
Definition midas.h:1033
void * pfile
Definition mlogger.cxx:264
INT handle
Definition mlogger.cxx:249
std::string path
Definition mlogger.cxx:250
WriterInterface * writer
Definition mlogger.cxx:265
int post_checksum_module
Definition mlogger.cxx:270
INT msg_request_id
Definition mlogger.cxx:257
std::string name
Definition mlogger.cxx:248
DWORD last_checked
Definition mlogger.cxx:266
int output_module
Definition mlogger.cxx:271
INT subrun_number
Definition mlogger.cxx:253
void * ftp_con
Definition mlogger.cxx:263
INT msg_buffer_handle
Definition mlogger.cxx:255
CHN_STATISTICS statistics
Definition mlogger.cxx:261
INT request_id
Definition mlogger.cxx:256
int compression_module
Definition mlogger.cxx:269
BOOL do_disk_level
Definition mlogger.cxx:267
HNDLE settings_hkey
Definition mlogger.cxx:259
HNDLE stats_hkey
Definition mlogger.cxx:258
MIDAS_INFO * midas_info
Definition mlogger.cxx:262
INT type
Definition mlogger.cxx:252
INT buffer_handle
Definition mlogger.cxx:254
int pre_checksum_module
Definition mlogger.cxx:268
std::string pipe_command
Definition mlogger.cxx:251
CHN_SETTINGS settings
Definition mlogger.cxx:260
char * write_pointer
Definition mlogger.cxx:324
char * buffer
Definition mlogger.cxx:323
Definition midas.h:1233
DWORD type
Definition midas.h:1235
DWORD n_data
Definition midas.h:1236
char name[NAME_LENGTH]
Definition midas.h:1234
char * buffer
Definition mlogger.cxx:300
char event_name[256]
Definition mlogger.cxx:299
HNDLE hKeyVar
Definition mlogger.cxx:302
INT buffer_size
Definition mlogger.cxx:301
time_t min_period
Definition mlogger.cxx:304
DWORD n_var
Definition mlogger.cxx:303
time_t last_log
Definition mlogger.cxx:305
SHA-256 context structure.
Definition sha256.h:48
SHA-512 context structure.
Definition sha512.h:48
char c
Definition system.cxx:1312