blob: 51f4861dfda1dd2d907aecff80c7ebeacb6d8ab7 [file] [log] [blame]
/**
*Licensed to the Apache Software Foundation (ASF) under one
*or more contributor license agreements. See the NOTICE file
*distributed with this work for additional information
*regarding copyright ownership. The ASF licenses this file
*to you under the Apache License, Version 2.0 (the
*"License"); you may not use this file except in compliance
*with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing,
*software distributed under the License is distributed on an
*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
*specific language governing permissions and limitations
*under the License.
*/
#include "celix_compiler.h"
#include "celix_log_utils.h"
#include <stdbool.h>
#include <stdarg.h>
#ifndef __UCLIBC__
#include <execinfo.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
const char* celix_logUtils_logLevelToString(celix_log_level_e level) { return celix_logLevel_toString(level); }
celix_log_level_e celix_logUtils_logLevelFromString(const char* str, celix_log_level_e fallbackLogLevel) {
return celix_logLevel_fromString(str, fallbackLogLevel);
}
celix_log_level_e celix_logUtils_logLevelFromStringWithCheck(const char* str,
celix_log_level_e fallbackLogLevel,
bool* convertedSuccessfully) {
return celix_logLevel_fromStringWithCheck(str, fallbackLogLevel, convertedSuccessfully);
}
#ifndef __UCLIBC__
static inline void celix_logUtils_inlinePrintBacktrace(FILE *stream) {
void *bbuf[64];
int nrOfTraces = backtrace(bbuf, 64);
char **lines = backtrace_symbols(bbuf, nrOfTraces);
for (int i = 0; i < nrOfTraces; ++i) {
char *line = lines[i];
fprintf(stream, "%s\n", line);
}
free(lines);
fflush(stream);
}
#else /* __UCLIBC__ */
static inline void celix_logUtils_inlinePrintBacktrace(FILE *stream CELIX_UNUSED) {
//nop
}
#endif /* __UCLIBC__ */
void celix_logUtils_printBacktrace(FILE* stream) {
celix_logUtils_inlinePrintBacktrace(stream);
}
void celix_logUtils_logToStdout(const char *logName, celix_log_level_e level, const char *format, ...) {
va_list args;
va_start(args, format);
celix_logUtils_vLogToStdout(logName, level, format, args);
va_end(args);
}
void celix_logUtils_logToStdoutDetails(const char *logName, celix_log_level_e level, const char* file, const char* function, int line, const char *format, ...) {
va_list args;
va_start(args, format);
celix_logUtils_vLogToStdoutDetails(logName, level, file, function, line, format, args);
va_end(args);
}
void celix_logUtils_vLogToStdout(const char *logName, celix_log_level_e level, const char *format, va_list formatArgs) {
celix_logUtils_vLogToStdoutDetails(logName, level, NULL, NULL, 0, format, formatArgs);
}
static pthread_mutex_t globalMutex = PTHREAD_MUTEX_INITIALIZER;
void celix_logUtils_vLogToStdoutDetails(const char *logName, celix_log_level_e level, const char* file, const char* function, int line, const char *format, va_list formatArgs) {
if (level == CELIX_LOG_LEVEL_DISABLED) {
//silently ignore
return;
}
//get printable time
time_t t = time(NULL);
struct tm local;
localtime_r(&t, &local);
FILE *out = stdout;
if (level == CELIX_LOG_LEVEL_WARNING || level == CELIX_LOG_LEVEL_ERROR || level == CELIX_LOG_LEVEL_FATAL) {
out = stderr;
}
pthread_mutex_lock(&globalMutex);
fprintf(out, "[%i-%02i-%02iT%02i:%02i:%02i] ", local.tm_year + 1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
if (file != NULL && function != NULL) {
(void)file; //note not using file
fprintf(out, "[%7s] [%s] [%s:%i] ", celix_logUtils_logLevelToString(level), logName, function, line);
} else {
fprintf(out, "[%7s] [%s] ", celix_logUtils_logLevelToString(level), logName);
}
vfprintf(out, format, formatArgs);
fprintf(out, "\n");
if (level >= CELIX_LOG_LEVEL_FATAL) {
fprintf(out, "Backtrace:\n");
celix_logUtils_inlinePrintBacktrace(out);
}
fflush(out);
pthread_mutex_unlock(&globalMutex);
}