| /* |
| * 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 <stdarg.h> |
| #include <celix_log_utils.h> |
| #include <assert.h> |
| #include <stdlib.h> |
| |
| #include "celix_err.h" |
| #include "celix_errno.h" |
| #include "celix_log.h" |
| #include "celix_threads.h" |
| #include "celix_array_list.h" |
| |
| #define LOG_NAME "celix_framework" |
| |
| struct celix_framework_logger { |
| celix_thread_mutex_t mutex; //protect below |
| celix_log_level_e activeLogLevel; |
| char *buf; |
| size_t bufSize; |
| FILE* stream; |
| void *logHandle; |
| void (*logFunction)(void* handle, celix_log_level_e level, const char* file, const char *function, int line, const char *format, va_list formatArgs); |
| }; |
| |
| static pthread_mutex_t globalMutex = PTHREAD_MUTEX_INITIALIZER; |
| celix_array_list_t* globalLoggers = NULL; |
| |
| celix_framework_logger_t* celix_frameworkLogger_globalLogger() { |
| celix_framework_logger_t* logger = NULL; |
| pthread_mutex_lock(&globalMutex); |
| if (globalLoggers != NULL) { |
| logger = celix_arrayList_get(globalLoggers, 0); //Not NULL, always 1 entry |
| } |
| pthread_mutex_unlock(&globalMutex); |
| return logger; |
| } |
| |
| celix_framework_logger_t* celix_frameworkLogger_create(celix_log_level_e activeLogLevel) { |
| celix_framework_logger_t* logger = calloc(1, sizeof(*logger)); |
| celixThreadMutex_create(&logger->mutex, NULL); |
| logger->activeLogLevel = activeLogLevel; |
| logger->stream = open_memstream(&logger->buf, &logger->bufSize); |
| |
| pthread_mutex_lock(&globalMutex); |
| if (globalLoggers == NULL) { |
| globalLoggers = celix_arrayList_create(); |
| } |
| celix_arrayList_add(globalLoggers, logger); |
| pthread_mutex_unlock(&globalMutex); |
| |
| return logger; |
| } |
| |
| void celix_frameworkLogger_destroy(celix_framework_logger_t* logger) { |
| if (logger != NULL) { |
| pthread_mutex_lock(&globalMutex); |
| assert(globalLoggers != NULL); |
| for (int i = 0; i < celix_arrayList_size(globalLoggers); ++i) { |
| celix_framework_logger_t *visit = celix_arrayList_get(globalLoggers, i); |
| if (visit == logger) { |
| celix_arrayList_removeAt(globalLoggers, i); |
| break; |
| } |
| } |
| if (celix_arrayList_size(globalLoggers) == 0) { |
| celix_arrayList_destroy(globalLoggers); |
| globalLoggers = NULL; |
| } |
| pthread_mutex_unlock(&globalMutex); |
| |
| celixThreadMutex_destroy(&logger->mutex); |
| fclose(logger->stream); |
| free(logger->buf); |
| free(logger); |
| } |
| } |
| void celix_frameworkLogger_setLogCallback(celix_framework_logger_t* logger, void* logHandle, void (*logFunction)(void* handle, celix_log_level_e level, const char* file, const char *func, int line, const char *format, va_list formatArgs)) { |
| celixThreadMutex_lock(&logger->mutex); |
| logger->logHandle = logHandle; |
| logger->logFunction = logFunction; |
| celixThreadMutex_unlock(&logger->mutex); |
| } |
| |
| |
| static void celix_framework_vlogInternal(celix_framework_logger_t* logger, celix_log_level_e level, celix_status_t optionalStatus, const char* file, const char* function, int line, const char* format, va_list args) { |
| if (level == CELIX_LOG_LEVEL_DISABLED) { |
| return; |
| } |
| celixThreadMutex_lock(&logger->mutex); |
| if (logger->logFunction != NULL) { |
| //note let log function handle active log levels |
| logger->logFunction(logger->logHandle, level, file, function, line, format, args); |
| } else if (level >= logger->activeLogLevel) { |
| if (optionalStatus != CELIX_SUCCESS) { |
| fseek(logger->stream, 0L, SEEK_SET); |
| fprintf(logger->stream, "%s(0x%x): ", celix_strerror(optionalStatus), optionalStatus); |
| vfprintf(logger->stream, format, args); |
| fputc('\0', logger->stream); //note not sure if this is needed |
| fflush(logger->stream); |
| celix_logUtils_logToStdoutDetails(LOG_NAME, level, file, function, line, "%s", logger->buf); |
| } else { |
| celix_logUtils_vLogToStdoutDetails(LOG_NAME, level, file, function, line, format, args); |
| } |
| } |
| celixThreadMutex_unlock(&logger->mutex); |
| } |
| |
| void celix_framework_vlog(celix_framework_logger_t* logger, celix_log_level_e level, const char *func, const char *file, int line, |
| const char *format, va_list formatArgs) { |
| celix_framework_vlogInternal(logger, level, CELIX_SUCCESS, func, file, line, format, formatArgs); |
| } |
| |
| |
| void celix_framework_log(celix_framework_logger_t* logger, celix_log_level_e level, const char *func, const char *file, int line, const char *format, ...) { |
| va_list args; |
| va_start(args, format); |
| celix_framework_vlogInternal(logger, level, CELIX_SUCCESS, file, func, line, format, args); |
| va_end(args); |
| } |
| |
| void celix_framework_logCode(celix_framework_logger_t* logger, celix_log_level_e level, const char *func, const char *file, int line, celix_status_t code, const char *format, ...) { |
| va_list args; |
| va_start(args, format); |
| celix_framework_vlogInternal(logger, level, code, file, func, line, format, args); |
| va_end(args); |
| } |
| |
| void celix_framework_logTssErrors(celix_framework_logger_t* logger, celix_log_level_e level) { |
| char buf[CELIX_ERR_BUFFER_SIZE] = {0}; |
| if (celix_err_dump(buf, sizeof(buf), NULL, NULL) == 0) { |
| // nothing to output |
| return; |
| } |
| celix_err_resetErrors(); |
| celix_framework_log(logger, level, NULL, NULL, 0, "Detected tss errors: %s", buf); |
| } |