LCOV - code coverage report
Current view: top level - shared - dlt_log.c (source / functions) Coverage Total Hit
Test: dlt_final_coverage.info Lines: 89.1 % 128 114
Test Date: 2026-08-27 10:11:10 Functions: 100.0 % 15 15

            Line data    Source code
       1              : /*
       2              :  * SPDX license identifier: MPL-2.0
       3              :  *
       4              :  * Copyright (C) 2024, Mercedes Benz Tech Innovation GmbH
       5              :  *
       6              :  * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
       7              :  *
       8              :  * This Source Code Form is subject to the terms of the
       9              :  * Mozilla Public License (MPL), v. 2.0.
      10              :  * If a copy of the MPL was not distributed with this file,
      11              :  * You can obtain one at http://mozilla.org/MPL/2.0/.
      12              :  *
      13              :  * For further information see https://www.covesa.global/.
      14              :  */
      15              : 
      16              : /*!
      17              :  * \author
      18              :  * Daniel Weber <daniel.w.weber@mercedes-benz.com>
      19              :  *
      20              :  * \copyright Copyright © 2024 Mercedes Benz Tech Innovation GmbH. \n
      21              :  * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
      22              :  *
      23              :  * \file dlt_log.c
      24              :  */
      25              : 
      26              : #include "dlt_log.h"
      27              : #include "dlt_common.h"
      28              : #include "dlt_multiple_files.h"
      29              : #include <syslog.h>
      30              : #include <errno.h>
      31              : #include <libgen.h> /* dirname */
      32              : #include <limits.h> /* for NAME_MAX */
      33              : #include <string.h> /* for strlen() */
      34              : #include <stdlib.h> /* for calloc(), free() */
      35              : #include <stdarg.h> /* va_list, va_start */
      36              : 
      37              : /* internal logging parameters */
      38              : static int logging_level = LOG_INFO;
      39              : static char logging_filename[NAME_MAX + 1] = "";
      40              : DltLoggingMode logging_mode = DLT_LOG_TO_STDERR;
      41              : FILE* logging_handle = NULL;
      42              : 
      43              : // use ohandle as an indicator that multiple files logging is active
      44              : MultipleFilesRingBuffer multiple_files_ring_buffer = {
      45              :     .directory = {0},
      46              :     .filename = {0},
      47              :     .fileSize = 0,
      48              :     .maxSize = 0,
      49              :     .filenameTimestampBased = false,
      50              :     .filenameBase = {0},
      51              :     .filenameExt = {0},
      52              :     .ohandle = -1};
      53              : 
      54              : 
      55            9 : void dlt_log_set_filename(const char* filename)
      56              : {
      57              :     /* check nullpointer */
      58            9 :     if (filename == NULL) {
      59            1 :         dlt_log(LOG_WARNING, "Wrong parameter: filename is NULL\n");
      60            1 :         return;
      61              :     }
      62              : 
      63              :     strncpy(logging_filename, filename, NAME_MAX);
      64            8 :     logging_filename[NAME_MAX] = 0;
      65              : }
      66              : 
      67           11 : void dlt_log_set_level(int level)
      68              : {
      69           11 :     if ((level < 0) || (level > LOG_DEBUG)) {
      70            0 :         if (logging_level < LOG_WARNING)
      71            0 :             logging_level = LOG_WARNING;
      72              : 
      73            0 :         dlt_vlog(LOG_WARNING, "Wrong parameter for level: %d\n", level);
      74              :     } else {
      75           11 :         logging_level = level;
      76              :     }
      77           11 : }
      78              : 
      79           12 : DltReturnValue dlt_log_init(int mode)
      80              : {
      81           12 :     return dlt_log_init_multiple_logfiles_support((DltLoggingMode)mode, false, 0, 0);
      82              : }
      83              : 
      84              : 
      85           18 : DltReturnValue dlt_log_init_multiple_logfiles_support(
      86              :     const DltLoggingMode mode, const bool enable_multiple_logfiles, const int logging_file_size,
      87              :     const int logging_files_max_size)
      88              : {
      89           18 :     if ((mode < DLT_LOG_TO_CONSOLE) || (mode > DLT_LOG_DROPPED)) {
      90            0 :         dlt_vlog(LOG_WARNING, "Wrong parameter for mode: %d\n", mode);
      91            0 :         return DLT_RETURN_WRONG_PARAMETER;
      92              :     }
      93              : 
      94           18 :     logging_mode = mode;
      95              : 
      96           18 :     if (logging_mode != DLT_LOG_TO_FILE) {
      97              :         return DLT_RETURN_OK;
      98              :     }
      99              : 
     100              :     DltReturnValue result;
     101            7 :     if (enable_multiple_logfiles) {
     102            4 :         dlt_user_printf("configure dlt logging using file limits\n");
     103            4 :         result = dlt_log_init_multiple_logfiles(logging_file_size, logging_files_max_size);
     104            4 :         if (result != DLT_RETURN_OK) {
     105            1 :             dlt_user_printf(
     106              :                 "dlt logging for limits fails with error code=%d, use logging without limits as fallback\n", result);
     107            1 :             result = dlt_log_init_single_logfile();
     108              :         }
     109              :     } else {
     110            3 :         dlt_user_printf("configure dlt logging without file limits\n");
     111            3 :         result = dlt_log_init_single_logfile();
     112              :     }
     113              : 
     114              :     return result;
     115              : }
     116              : 
     117            4 : DltReturnValue dlt_log_init_single_logfile()
     118              : {
     119              :     /* internal logging to file */
     120            4 :     errno = 0;
     121            4 :     logging_handle = fopen(logging_filename, "a");
     122              : 
     123            4 :     if (logging_handle == NULL) {
     124            0 :         dlt_user_printf("Internal log file %s cannot be opened, error: %s\n", logging_filename, strerror(errno));
     125            0 :         return DLT_RETURN_ERROR;
     126              :     }
     127              :     return DLT_RETURN_OK;
     128              : }
     129              : 
     130            4 : DltReturnValue dlt_log_init_multiple_logfiles(const int logging_file_size, const int logging_files_max_size)
     131              : {
     132              :     char path_logging_filename[PATH_MAX + 1];
     133              :     strncpy(path_logging_filename, logging_filename, PATH_MAX);
     134            4 :     path_logging_filename[PATH_MAX] = 0;
     135              : 
     136            4 :     const char* directory = dirname(path_logging_filename);
     137            4 :     if (directory[0]) {
     138              :         char basename_logging_filename[NAME_MAX + 1];
     139              :         strncpy(basename_logging_filename, logging_filename, NAME_MAX);
     140            4 :         basename_logging_filename[NAME_MAX] = 0;
     141              : 
     142            4 :         const char* file_name = basename(basename_logging_filename);
     143              :         char filename_base[NAME_MAX];
     144            4 :         if (!dlt_extract_base_name_without_ext(file_name, filename_base, sizeof(filename_base)))
     145              :             return DLT_RETURN_ERROR;
     146              : 
     147            3 :         const char* filename_ext = get_filename_ext(file_name);
     148            3 :         if (!filename_ext)
     149              :             return DLT_RETURN_ERROR;
     150              : 
     151            3 :         DltReturnValue result = multiple_files_buffer_init(
     152              :             &multiple_files_ring_buffer, directory, logging_file_size, logging_files_max_size, false, true,
     153              :             filename_base, filename_ext);
     154              : 
     155            3 :         return result;
     156              :     }
     157              : 
     158              :     return DLT_RETURN_ERROR;
     159              : }
     160              : 
     161         2852 : int dlt_user_printf(const char* format, ...)
     162              : {
     163         2852 :     if (format == NULL)
     164              :         return -1;
     165              : 
     166              :     va_list args;
     167         2852 :     va_start(args, format);
     168              : 
     169              :     int ret = 0;
     170              : 
     171         2852 :     switch (logging_mode) {
     172            8 :     case DLT_LOG_TO_CONSOLE:
     173              :     case DLT_LOG_TO_SYSLOG:
     174              :     case DLT_LOG_TO_FILE:
     175              :     case DLT_LOG_DROPPED:
     176              :     default:
     177            8 :         ret = vfprintf(stdout, format, args);
     178            8 :         break;
     179         2844 :     case DLT_LOG_TO_STDERR:
     180         2844 :         ret = vfprintf(stderr, format, args);
     181         2844 :         break;
     182              :     }
     183              : 
     184         2852 :     va_end(args);
     185              : 
     186         2852 :     return ret;
     187              : }
     188              : 
     189         5619 : DltReturnValue dlt_log(int prio, const char* s)
     190              : {
     191              :     static const char asSeverity[LOG_DEBUG + 2][11] = {"EMERGENCY", "ALERT    ", "CRITICAL ", "ERROR    ", "WARNING  ",
     192              :                                                        "NOTICE   ", "INFO     ", "DEBUG    ", "         "};
     193              :     static const char sFormatString[] = "[%5u.%06u]~DLT~%5d~%s~%s";
     194              :     struct timespec sTimeSpec;
     195              : 
     196         5619 :     if (s == NULL)
     197              :         return DLT_RETURN_WRONG_PARAMETER;
     198              : 
     199         5618 :     if (logging_level < prio)
     200              :         return DLT_RETURN_OK;
     201              : 
     202         5535 :     if ((prio < 0) || (prio > LOG_DEBUG))
     203              :         prio = LOG_DEBUG + 1;
     204              : 
     205         5535 :     clock_gettime(CLOCK_MONOTONIC, &sTimeSpec);
     206              : 
     207         5535 :     switch (logging_mode) {
     208          118 :     case DLT_LOG_TO_CONSOLE:
     209              :         /* log to stdout */
     210          236 :         fprintf(
     211          118 :             stdout, sFormatString, (unsigned int)sTimeSpec.tv_sec, (unsigned int)(sTimeSpec.tv_nsec / 1000), getpid(),
     212          118 :             asSeverity[prio], s);
     213          118 :         fflush(stdout);
     214          118 :         break;
     215         5380 :     case DLT_LOG_TO_STDERR:
     216              :         /* log to stderr */
     217        10760 :         fprintf(
     218         5380 :             stderr, sFormatString, (unsigned int)sTimeSpec.tv_sec, (unsigned int)(sTimeSpec.tv_nsec / 1000), getpid(),
     219         5380 :             asSeverity[prio], s);
     220              :         break;
     221            0 :     case DLT_LOG_TO_SYSLOG:
     222              :         /* log to syslog */
     223              : #if !defined(__WIN32__) && !defined(_MSC_VER)
     224            0 :         openlog("DLT", LOG_PID, LOG_DAEMON);
     225            0 :         syslog(
     226            0 :             prio, sFormatString, (unsigned int)sTimeSpec.tv_sec, (unsigned int)(sTimeSpec.tv_nsec / 1000), getpid(),
     227            0 :             asSeverity[prio], s);
     228            0 :         closelog();
     229              : #endif
     230            0 :         break;
     231           32 :     case DLT_LOG_TO_FILE:
     232              :         /* log to file */
     233              : 
     234           32 :         if (dlt_is_log_in_multiple_files_active()) {
     235           24 :             dlt_log_multiple_files_write(
     236           12 :                 sFormatString, (unsigned int)sTimeSpec.tv_sec, (unsigned int)(sTimeSpec.tv_nsec / 1000), getpid(),
     237           12 :                 asSeverity[prio], s);
     238           20 :         } else if (logging_handle) {
     239           40 :             fprintf(
     240           20 :                 logging_handle, sFormatString, (unsigned int)sTimeSpec.tv_sec, (unsigned int)(sTimeSpec.tv_nsec / 1000),
     241           20 :                 getpid(), asSeverity[prio], s);
     242           20 :             fflush(logging_handle);
     243              :         }
     244              : 
     245              :         break;
     246              :     case DLT_LOG_DROPPED:
     247              :     default:
     248              :         break;
     249              :     }
     250              : 
     251              :     return DLT_RETURN_OK;
     252              : }
     253              : 
     254        29140 : DltReturnValue dlt_vlog(int prio, const char* format, ...)
     255              : {
     256        29140 :     char outputString[2048] = {0}; /* TODO: what is a reasonable string length here? */
     257              : 
     258              :     va_list args;
     259              : 
     260        29140 :     if (format == NULL)
     261              :         return DLT_RETURN_WRONG_PARAMETER;
     262              : 
     263        29140 :     if (logging_level < prio)
     264              :         return DLT_RETURN_OK;
     265              : 
     266         5482 :     va_start(args, format);
     267              :     vsnprintf(outputString, 2047, format, args);
     268         5482 :     va_end(args);
     269              : 
     270         5482 :     dlt_log(prio, outputString);
     271              : 
     272         5482 :     return DLT_RETURN_OK;
     273              : }
     274              : 
     275            3 : DltReturnValue dlt_vnlog(int prio, size_t size, const char* format, ...)
     276              : {
     277              :     char* outputString = NULL;
     278              : 
     279              :     va_list args;
     280              : 
     281            3 :     if (format == NULL)
     282              :         return DLT_RETURN_WRONG_PARAMETER;
     283              : 
     284            3 :     if ((logging_level < prio) || (size == 0))
     285              :         return DLT_RETURN_OK;
     286              : 
     287            3 :     if ((outputString = (char*)calloc(size + 1, sizeof(char))) == NULL)
     288              :         return DLT_RETURN_ERROR;
     289              : 
     290            3 :     va_start(args, format);
     291              :     vsnprintf(outputString, size, format, args);
     292            3 :     va_end(args);
     293              : 
     294            3 :     dlt_log(prio, outputString);
     295              : 
     296            3 :     free(outputString);
     297              :     outputString = NULL;
     298              : 
     299            3 :     return DLT_RETURN_OK;
     300              : }
     301              : 
     302           12 : void dlt_log_multiple_files_write(const char* format, ...)
     303              : {
     304           12 :     char output_string[2048] = {0};
     305              :     va_list args;
     306           12 :     va_start(args, format);
     307              :     vsnprintf(output_string, 2047, format, args);
     308           12 :     va_end(args);
     309           12 :     multiple_files_buffer_write(&multiple_files_ring_buffer, (unsigned char*)output_string, (int)strlen(output_string));
     310           12 : }
     311              : 
     312            7 : void dlt_log_free(void)
     313              : {
     314            7 :     if (logging_mode == DLT_LOG_TO_FILE) {
     315            5 :         if (dlt_is_log_in_multiple_files_active()) {
     316            3 :             dlt_log_free_multiple_logfiles();
     317              :         } else {
     318            2 :             dlt_log_free_single_logfile();
     319              :         }
     320              :     }
     321            7 : }
     322              : 
     323            2 : void dlt_log_free_single_logfile()
     324              : {
     325            2 :     if (logging_handle != NULL) {
     326            2 :         fclose(logging_handle);
     327              :     }
     328            2 : }
     329              : 
     330            3 : void dlt_log_free_multiple_logfiles()
     331              : {
     332            3 :     if (DLT_RETURN_ERROR == multiple_files_buffer_free(&multiple_files_ring_buffer))
     333              :         return;
     334              : 
     335              :     // reset indicator of multiple files usage
     336            3 :     multiple_files_ring_buffer.ohandle = -1;
     337              : }
     338              : 
     339           37 : bool dlt_is_log_in_multiple_files_active()
     340              : {
     341           37 :     return multiple_files_ring_buffer.ohandle > -1;
     342              : }
        

Generated by: LCOV version 2.0-1