b0e26afb25bac213ead7080ca8607e3e744660c9
[sim/o1-interface.git] / ntsimulator / ntsim-ng / utils / log_utils.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "log_utils.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <stdbool.h>
25 #include <time.h>
26 #include <assert.h>
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <fcntl.h>
33
34
35 #include <core/framework.h>
36
37 static int instances = 0;
38 static FILE* logfile = 0;
39
40 static char *extract_format(const char *format);
41
42 void log_init(const char *logfilename) {
43     assert(instances == 0);
44     instances++;
45
46     logfile = fopen(logfilename, "w");
47
48     assert(logfile);
49 }
50
51 void log__message(char const * const fname, uint32_t location, int verbose_level, const char *format, ...) {
52
53     va_list arg;
54
55     char *verbose_file = 0;
56     int free_verbose_file = 0;
57
58     char *verbose_screen = 0;
59     int free_verbose_screen = 0;
60
61     if(verbose_level < 0) {
62         //when verbose negative, treat as add (no filename, line, time, etc)
63         verbose_level = -verbose_level;
64         verbose_file = (char *)format;
65         verbose_screen = (char *)format;
66     }
67     else {
68         //extract just the filename, no path
69         const char *filename = fname + strlen(fname) - 1;
70         while((filename != fname) && (*filename != '/')) {
71             filename--;
72         }
73         if(*filename == '/') {
74             filename++;
75         }
76
77         time_t t = time(NULL);
78         struct tm tm = *localtime(&t);
79
80         asprintf(&verbose_file, "[%d-%02d-%02d|%02d:%02d:%02d|%s:%u] %s", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, filename, location, format);
81         if(verbose_file == 0) {
82             verbose_file = (char *)format;
83         }
84         else {
85             free_verbose_file = 1;
86         }
87
88         if(verbose_level != 0) {
89             asprintf(&verbose_screen, "[%d-%02d-%02d|%02d:%02d:%02d] %s", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, format);
90         }
91         else {
92             verbose_screen = strdup(verbose_file);
93         }
94
95         if(verbose_screen == 0) {
96             verbose_screen = (char *)format;
97         }
98         else {
99             free_verbose_screen = 1;
100         }
101     }
102     
103     //log to file in an uncolored format (simple format)
104     va_start(arg, format);
105     char *simple_format = extract_format(verbose_file);
106     vfprintf(logfile, simple_format, arg);
107
108     if(simple_format != verbose_file) {
109         free(simple_format);
110     }
111     va_end(arg);
112     fflush(logfile);
113
114     if(free_verbose_file) {
115         free(verbose_file);
116     }
117
118     if(verbose_level <= framework_arguments.verbosity_level) {
119         
120         if(verbose_level == 0) {      
121             fprintf(stderr, LOG_COLOR_BOLD_RED);
122             va_start(arg, format);
123             vfprintf(stderr, verbose_screen, arg);
124             va_end(arg);
125             fprintf(stderr, LOG_COLOR_RESET);
126
127             fprintf(stdout, LOG_COLOR_BOLD_RED);
128         }
129
130         va_start(arg, format);
131         vfprintf(stdout, verbose_screen, arg);
132         va_end(arg);
133
134         if(verbose_level == 0) {
135             fprintf(stdout, LOG_COLOR_RESET);
136         }
137     }
138
139     if(free_verbose_screen) {
140         free(verbose_screen);
141     }
142 }
143
144 void log_close(void) {
145     fclose(logfile);
146     instances--;
147 }
148
149 static char *extract_format(const char *format) {
150     assert(format);
151
152     int l = strlen(format);
153     char *ret = (char *)malloc(sizeof(char) * (l + 1));
154     if(ret == 0) {
155         fprintf(stderr, LOG_COLOR_BOLD_RED"bad malloc in log system\n"LOG_COLOR_RESET);
156         return (char *)format;
157     }
158
159     int s = 0;
160     int d = 0;
161     bool in_escape = false;
162
163     while(s < l) {
164         if(!in_escape) {
165             //escape char
166             if(format[s] == 27) {
167                 in_escape = true;
168                 s++;
169             }
170         }
171         else {
172             if(format[s] == 'm') {
173                 in_escape = false;
174                 s++;
175             }
176         }
177
178
179         if(!in_escape) {
180             ret[d++] = format[s];
181         }
182
183         s++;
184     }
185
186     ret[d] = 0;
187   
188     return ret;
189 }
190
191 void log_redirect_stderr(const char *stderrfilename) {
192     remove(stderrfilename);
193     int stderr_fd = open(stderrfilename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
194     dup2(stderr_fd, STDERR_FILENO);
195     close(stderr_fd);
196 }