Skip to content

Commit 7690b11

Browse files
Merge pull request #14 from kaltura/transcoder-log-json
Move transcoder log to Json format
2 parents 456a9d1 + 13b51fd commit 7690b11

File tree

4 files changed

+172
-14
lines changed

4 files changed

+172
-14
lines changed

transcoder/main.c

+10-2
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ int set_resource_limits()
166166
}
167167
return 0;
168168
}
169+
extern char *configString;
169170

170171
int main(int argc, char **argv)
171172
{
@@ -176,8 +177,6 @@ int main(int argc, char **argv)
176177

177178
log_init(AV_LOG_DEBUG);
178179

179-
LOGGER(CATEGORY_DEFAULT,AV_LOG_INFO,"Version: %s", APPLICATION_VERSION)
180-
181180
signal(SIGINT, intHandler);
182181
signal(SIGPIPE, pipeHandler);
183182

@@ -191,6 +190,15 @@ int main(int argc, char **argv)
191190
set_log_level(logLevel);
192191
}
193192

193+
bool logOutputJson;
194+
if (JSON_OK==json_get_bool(GetConfig(),"logger.logOutputJson",false,&logOutputJson)) {
195+
set_log_output_json(logOutputJson);
196+
}
197+
198+
LOGGER(CATEGORY_DEFAULT,AV_LOG_INFO,"Version: %s", APPLICATION_VERSION)
199+
200+
LOGGER(CATEGORY_DEFAULT,AV_LOG_INFO,"Parsed configuration successfully: %s",configString);
201+
194202
avformat_network_init();
195203

196204
if (start() < 0) {

transcoder/tests/config_v.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
},
2424
"logger": {
2525
"logLevels": ["DEBUG","VERBOSE","INFO","WARN","ERROR","FATAL","PANIC"],
26-
"logLevel": "DEBUG"
26+
"logLevel": "DEBUG",
27+
"logOutputJson": true,
28+
"channelId": "1_2345678",
29+
"contextId": "ABCDE1234"
2730
},
2831
"kmp": {
2932
"listenPort": 16543,

transcoder/utils/config.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,6 @@ int LoadConfig(int argc, char **argv)
7171
LOGGER(CATEGORY_DEFAULT,AV_LOG_FATAL,"Failed parsing configurtion! %s (%s)",configString,error);
7272
return -1;
7373
}
74-
LOGGER(CATEGORY_DEFAULT,AV_LOG_INFO,"Parsed configuration successfully: %s",configString);
74+
7575
return 0;
7676
}

transcoder/utils/logger.c

+157-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
static int logLevel =AV_LOG_VERBOSE;
1313

14+
static bool logOutputJson = false;
15+
1416
const char* getLevelStr(int level) {
1517
switch(level){
1618
case AV_LOG_PANIC: return "PANIC";
@@ -48,7 +50,12 @@ int parseLoglevel(const char* loglevel)
4850

4951
pthread_mutex_t logger_locker;
5052

51-
char logger_id[256] = {0};
53+
char context_id[256] = {0};
54+
char channel_id[256] = {0};
55+
56+
static int stringify_message(FILE *out, const char *fmt, va_list args);
57+
58+
void logger_unit_test();
5259

5360
void logger2(const char* category,const char* subcategory,int level,const char *fmt, bool newLine, va_list args)
5461
{
@@ -66,14 +73,22 @@ void logger2(const char* category,const char* subcategory,int level,const char *
6673

6774
FILE* out=stdout;
6875

69-
fprintf( out, "%s.%03lld %s:%s %s |%s| [%p] ",buf,( (now % 1000000)/1000 ),category,subcategory!=NULL ? subcategory : "", levelStr,logger_id,pthread_self());
70-
if (args!=NULL) {
71-
vfprintf( out, fmt, args );
76+
if(logOutputJson) {
77+
fprintf( out, "{\"time\": \"%s.%03ld\", \"channelId\": \"%s\", \"category\": \"%s:%s\", \"logLevel\": \"%s\","
78+
"\"contextId\": \"%s\", \"pthread\":\"%lx\", \"log\": ",buf,( (now % 1000000)/1000 ), channel_id, category,
79+
subcategory!=NULL ? subcategory : "", levelStr,context_id,pthread_self());
80+
stringify_message(out, fmt, args);
81+
fprintf( out, "}\n" );
7282
} else {
73-
fprintf(out,"%s",fmt);
74-
}
75-
if (newLine) {
76-
fprintf( out, "\n" );
83+
fprintf( out, "%s.%03ld %s:%s %s |%s| [%s] [%lx] ",buf,( (now % 1000000)/1000 ),category,subcategory!=NULL ? subcategory : "", levelStr,context_id,channel_id,pthread_self());
84+
if (args!=NULL) {
85+
vfprintf( out, fmt, args );
86+
} else {
87+
fwrite(fmt, strlen(fmt), 1, out);
88+
}
89+
if (newLine) {
90+
fprintf( out, "\n" );
91+
}
7792
}
7893
fflush(out);
7994
pthread_mutex_unlock(&logger_locker); // unlock once you are done
@@ -141,17 +156,149 @@ void log_init(int level)
141156

142157
void set_log_level(const char* loglevel) {
143158
logLevel=parseLoglevel(loglevel);
144-
if(!*logger_id) {
145-
json_get_string(GetConfig(),"logger.id","\0",logger_id,sizeof(logger_id));
159+
if(!*context_id) {
160+
json_get_string(GetConfig(),"logger.contextId","\0",context_id,sizeof(context_id));
161+
}
162+
if (!*channel_id) {
163+
json_get_string(GetConfig(),"logger.channelId","\0",channel_id,sizeof(channel_id));
146164
}
147165
}
148166

149167
int get_log_level(const char* category)
150168
{
151169
return logLevel;
152170
}
171+
172+
void set_log_output_json(bool val)
173+
{
174+
logOutputJson = val;
175+
}
176+
177+
bool get_log_output_json()
178+
{
179+
return logOutputJson;
180+
}
181+
153182
void loggerFlush()
154183
{
155184
fflush(stderr);
156185
fflush(stdout);
157186
}
187+
188+
/*
189+
json logger utils
190+
*/
191+
192+
#define FWRITE_STR(x) fwrite(x,1,sizeof(x)-1,out)
193+
194+
/*
195+
escapes string according to https://tc39.es/ecma262/multipage/structured-data.html#sec-json.stringify
196+
*/
197+
const char *hex = "0123456789ABCDEF";
198+
static size_t json_escape(FILE *out, const char *str) {
199+
const char *start = str;
200+
while (*str) {
201+
char chr = *str;
202+
203+
if (chr == '"' || chr == '\\' || chr == '/') {
204+
FWRITE_STR("\\");
205+
putc(chr,out);
206+
} else if (chr == '\b') {
207+
FWRITE_STR("\\b");
208+
} else if (chr == '\f') {
209+
FWRITE_STR("\\f");
210+
} else if (chr == '\n') {
211+
FWRITE_STR("\\n");
212+
} else if (chr == '\r') {
213+
FWRITE_STR("\\r");
214+
} else if (chr == '\t') {
215+
FWRITE_STR("\\t");
216+
} else if (!isprint(chr)) {
217+
FWRITE_STR("\\u");
218+
for (int i = 0; i < 4; i++) {
219+
int value = (chr >> 12) & 0xf;
220+
if (value >= 0 && value <= 15)
221+
putc(hex[value],out);
222+
chr <<= 4;
223+
}
224+
} else {
225+
putc(chr,out);
226+
}
227+
str++;
228+
}
229+
return str - start;
230+
}
231+
232+
typedef struct {
233+
char *buf;
234+
size_t size;
235+
FILE *fp;
236+
} mem_stream_t;
237+
238+
static mem_stream_t aux_mem_stream = {.buf = NULL,.size = 0,.fp = NULL};
239+
240+
static int open_mem_stream(mem_stream_t *stream) {
241+
if(!stream->fp){
242+
stream->fp = open_memstream(&stream->buf,&stream->size);
243+
}
244+
if(!stream->fp) {
245+
fprintf(stderr,"ERROR: could not open_memstream - os error code %d", errno);
246+
return -1;
247+
}
248+
return 0;
249+
}
250+
251+
/*
252+
stringify_message. prints log message as a json stringified string
253+
NOTE: not thread safe! must be called from within a lock.
254+
*/
255+
static int stringify_message(FILE *out, const char *fmt, va_list args) {
256+
int ret = -1;
257+
FWRITE_STR("\"");
258+
if (args!=NULL) {
259+
if((ret = open_mem_stream(&aux_mem_stream))){
260+
goto error;
261+
}
262+
if((ret = fseek(aux_mem_stream.fp, 0, SEEK_SET))) {
263+
fprintf(stderr,"ERROR: could not fseek %d - os error code %d", ret, errno);
264+
goto error;
265+
}
266+
if( (ret = vfprintf(aux_mem_stream.fp, fmt, args )) > 0){
267+
fflush(aux_mem_stream.fp);
268+
aux_mem_stream.buf[ret] = '\0';
269+
ret = json_escape(out, aux_mem_stream.buf);
270+
} else {
271+
fprintf(stderr,"WARNING: vfprintf error %d. os error code %d", ret, errno);
272+
}
273+
} else {
274+
ret = json_escape(out, fmt);
275+
}
276+
error:
277+
FWRITE_STR("\"");
278+
return ret;
279+
}
280+
281+
/*
282+
runtime test
283+
*/
284+
void logger_unit_test() {
285+
const char *special = "\a\b\t\n\r\f\"\\";
286+
char table [255+sizeof(special)-1],
287+
*walker = table;
288+
memcpy(walker,special,strlen(special));
289+
walker += strlen(special);
290+
for(int i = 1; i < 256; i++) {
291+
*walker++ = (char)i;
292+
}
293+
294+
srand((unsigned) time(NULL));
295+
for (int i = 0; i < 1024; i++) {
296+
int a = rand() % sizeof(table), b = rand() % sizeof(table);
297+
int temp = table[a];
298+
table[a] = table[b];
299+
table[b] = temp;
300+
301+
LOGGER(CATEGORY_DEFAULT,AV_LOG_WARNING,"%s", table);
302+
}
303+
exit(0);
304+
}

0 commit comments

Comments
 (0)