Add NF addressing method as ENV.
[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 int file_no = 0;
41 static int line_no = 0;
42 static const char *filename;
43
44 static char *extract_format(const char *format);
45
46 void log_init(const char *logfilename) {
47     assert(instances == 0);
48     instances++;
49
50     logfile = fopen(logfilename, "w");
51
52     assert(logfile);
53     file_no = 0;
54     line_no = 0;
55     filename = logfilename;
56 }
57
58 void log__message(char const * const fname, uint32_t location, int verbose_level, const char *format, ...) {
59     if(verbose_level >= 0) {
60         line_no++;
61         if(line_no >= 5000) {
62             fclose(logfile);
63
64             file_no++;
65             char logfilename[512];
66             sprintf(logfilename, "%s.%d", filename, file_no);
67             logfile = fopen(logfilename, "w");
68             line_no = 0;
69         }
70     }
71
72     va_list arg;
73
74     char *verbose_file = 0;
75     int free_verbose_file = 0;
76
77     char *verbose_screen = 0;
78     int free_verbose_screen = 0;
79
80     if(verbose_level < 0) {
81         //when verbose negative, treat as add (no filename, line, time, etc)
82         verbose_level = -verbose_level;
83         verbose_file = (char *)format;
84         verbose_screen = (char *)format;
85     }
86     else {
87         //extract just the filename, no path
88         const char *filename = fname + strlen(fname) - 1;
89         while((filename != fname) && (*filename != '/')) {
90             filename--;
91         }
92         if(*filename == '/') {
93             filename++;
94         }
95
96         time_t t = time(NULL);
97         struct tm tm = *localtime(&t);
98
99         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);
100         if(verbose_file == 0) {
101             verbose_file = (char *)format;
102         }
103         else {
104             free_verbose_file = 1;
105         }
106
107         if(verbose_level != 0) {
108             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);
109         }
110         else {
111             verbose_screen = strdup(verbose_file);
112         }
113
114         if(verbose_screen == 0) {
115             verbose_screen = (char *)format;
116         }
117         else {
118             free_verbose_screen = 1;
119         }
120     }
121     
122     //log to file in an uncolored format (simple format)
123     va_start(arg, format);
124     char *simple_format = extract_format(verbose_file);
125     vfprintf(logfile, simple_format, arg);
126
127     if(simple_format != verbose_file) {
128         free(simple_format);
129     }
130     va_end(arg);
131     fflush(logfile);
132
133     if(free_verbose_file) {
134         free(verbose_file);
135     }
136
137     if(verbose_level <= framework_arguments.verbosity_level) {
138         
139         if(verbose_level == 0) {      
140             fprintf(stderr, LOG_COLOR_BOLD_RED);
141             va_start(arg, format);
142             vfprintf(stderr, verbose_screen, arg);
143             va_end(arg);
144             fprintf(stderr, LOG_COLOR_RESET);
145
146             fprintf(stdout, LOG_COLOR_BOLD_RED);
147         }
148
149         va_start(arg, format);
150         vfprintf(stdout, verbose_screen, arg);
151         va_end(arg);
152
153         if(verbose_level == 0) {
154             fprintf(stdout, LOG_COLOR_RESET);
155         }
156     }
157
158     if(free_verbose_screen) {
159         free(verbose_screen);
160     }
161 }
162
163 void log_close(void) {
164     fclose(logfile);
165     instances--;
166 }
167
168 static char *extract_format(const char *format) {
169     assert(format);
170
171     int l = strlen(format);
172     char *ret = (char *)malloc(sizeof(char) * (l + 1));
173     if(ret == 0) {
174         fprintf(stderr, LOG_COLOR_BOLD_RED"bad malloc in log system\n"LOG_COLOR_RESET);
175         return (char *)format;
176     }
177
178     int s = 0;
179     int d = 0;
180     bool in_escape = false;
181
182     while(s < l) {
183         if(!in_escape) {
184             //escape char
185             if(format[s] == 27) {
186                 in_escape = true;
187                 s++;
188             }
189         }
190         else {
191             if(format[s] == 'm') {
192                 in_escape = false;
193                 s++;
194             }
195         }
196
197
198         if(!in_escape) {
199             ret[d++] = format[s];
200         }
201
202         s++;
203     }
204
205     ret[d] = 0;
206   
207     return ret;
208 }
209
210 void log_redirect_stderr(const char *stderrfilename) {
211     remove(stderrfilename);
212     int stderr_fd = open(stderrfilename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
213     dup2(stderr_fd, STDERR_FILENO);
214     close(stderr_fd);
215 }