LCOV - code coverage report
Current view: top level - shared - dlt_log.c (source / functions) Hit Total Coverage
Test: dlt_final_coverage.info Lines: 115 130 88.5 %
Date: 2024-12-06 04:41:42 Functions: 15 15 100.0 %

          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          17 : void dlt_log_set_filename(const char *filename)
      56             : {
      57             :     /* check nullpointer */
      58          17 :     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          16 :     logging_filename[NAME_MAX] = 0;
      65             : }
      66             : 
      67          19 : void dlt_log_set_level(int level)
      68             : {
      69          19 :     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             :     }
      75             :     else {
      76          19 :         logging_level = level;
      77             :     }
      78          19 : }
      79             : 
      80          12 : void dlt_log_init(int mode)
      81             : {
      82          12 :     dlt_log_init_multiple_logfiles_support((DltLoggingMode)mode, false, 0, 0);
      83          12 : }
      84             : 
      85             : 
      86          26 : DltReturnValue dlt_log_init_multiple_logfiles_support(const DltLoggingMode mode, const bool enable_multiple_logfiles,
      87             :                                                       const int logging_file_size, const int logging_files_max_size)
      88             : {
      89          26 :     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          26 :     logging_mode = mode;
      95             : 
      96          26 :     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("dlt logging for limits fails with error code=%d, use logging without limits as fallback\n", result);
     106           1 :             result = dlt_log_init_single_logfile();
     107             :         }
     108             :     } else {
     109           3 :         dlt_user_printf("configure dlt logging without file limits\n");
     110           3 :         result = dlt_log_init_single_logfile();
     111             :     }
     112             : 
     113             :     return result;
     114             : }
     115             : 
     116           4 : DltReturnValue dlt_log_init_single_logfile()
     117             : {
     118             :     /* internal logging to file */
     119           4 :     errno = 0;
     120           4 :     logging_handle = fopen(logging_filename, "a");
     121             : 
     122           4 :     if (logging_handle == NULL) {
     123           0 :         dlt_user_printf("Internal log file %s cannot be opened, error: %s\n", logging_filename, strerror(errno));
     124           0 :         return DLT_RETURN_ERROR;
     125             :     }
     126             :     return DLT_RETURN_OK;
     127             : }
     128             : 
     129           4 : DltReturnValue dlt_log_init_multiple_logfiles(const int logging_file_size, const int logging_files_max_size)
     130             : {
     131             :     char path_logging_filename[PATH_MAX + 1];
     132             :     strncpy(path_logging_filename, logging_filename, PATH_MAX);
     133           4 :     path_logging_filename[PATH_MAX] = 0;
     134             : 
     135           4 :     const char *directory = dirname(path_logging_filename);
     136           4 :     if (directory[0]) {
     137             :         char basename_logging_filename[NAME_MAX + 1];
     138             :         strncpy(basename_logging_filename, logging_filename, NAME_MAX);
     139           4 :         basename_logging_filename[NAME_MAX] = 0;
     140             : 
     141           4 :         const char *file_name = basename(basename_logging_filename);
     142             :         char filename_base[NAME_MAX];
     143           4 :         if (!dlt_extract_base_name_without_ext(file_name, filename_base, sizeof(filename_base))) return DLT_RETURN_ERROR;
     144             : 
     145           3 :         const char *filename_ext = get_filename_ext(file_name);
     146           3 :         if (!filename_ext) return DLT_RETURN_ERROR;
     147             : 
     148           3 :         DltReturnValue result = multiple_files_buffer_init(
     149             :                 &multiple_files_ring_buffer,
     150             :                 directory,
     151             :                 logging_file_size,
     152             :                 logging_files_max_size,
     153             :                 false,
     154             :                 true,
     155             :                 filename_base,
     156             :                 filename_ext);
     157             : 
     158           3 :         return result;
     159             :     }
     160             : 
     161             :     return DLT_RETURN_ERROR;
     162             : }
     163             : 
     164        2852 : int dlt_user_printf(const char *format, ...)
     165             : {
     166        2852 :     if (format == NULL) return -1;
     167             : 
     168             :     va_list args;
     169        2852 :     va_start(args, format);
     170             : 
     171             :     int ret = 0;
     172             : 
     173        2852 :     switch (logging_mode) {
     174           8 :         case DLT_LOG_TO_CONSOLE:
     175             :         case DLT_LOG_TO_SYSLOG:
     176             :         case DLT_LOG_TO_FILE:
     177             :         case DLT_LOG_DROPPED:
     178             :         default:
     179           8 :             ret = vfprintf(stdout, format, args);
     180           8 :             break;
     181        2844 :         case DLT_LOG_TO_STDERR:
     182        2844 :             ret = vfprintf(stderr, format, args);
     183        2844 :             break;
     184             :     }
     185             : 
     186        2852 :     va_end(args);
     187             : 
     188        2852 :     return ret;
     189             : }
     190             : 
     191       23267 : DltReturnValue dlt_log(int prio, const char *s)
     192             : {
     193             :     static const char asSeverity[LOG_DEBUG +
     194             :                                  2][11] =
     195             :             { "EMERGENCY", "ALERT    ", "CRITICAL ", "ERROR    ", "WARNING  ", "NOTICE   ", "INFO     ", "DEBUG    ",
     196             :               "         " };
     197             :     static const char sFormatString[] = "[%5u.%06u]~DLT~%5d~%s~%s";
     198             :     struct timespec sTimeSpec;
     199             : 
     200       23267 :     if (s == NULL)
     201             :         return DLT_RETURN_WRONG_PARAMETER;
     202             : 
     203       23266 :     if (logging_level < prio)
     204             :         return DLT_RETURN_OK;
     205             : 
     206       22350 :     if ((prio < 0) || (prio > LOG_DEBUG))
     207             :         prio = LOG_DEBUG + 1;
     208             : 
     209       22350 :     clock_gettime(CLOCK_MONOTONIC, &sTimeSpec);
     210             : 
     211       22350 :     switch (logging_mode) {
     212         525 :         case DLT_LOG_TO_CONSOLE:
     213             :             /* log to stdout */
     214        1050 :             fprintf(stdout, sFormatString,
     215         525 :                     (unsigned int)sTimeSpec.tv_sec,
     216         525 :                     (unsigned int)(sTimeSpec.tv_nsec / 1000),
     217             :                     getpid(),
     218         525 :                     asSeverity[prio],
     219             :                     s);
     220         525 :             fflush(stdout);
     221         525 :             break;
     222       21788 :         case DLT_LOG_TO_STDERR:
     223             :             /* log to stderr */
     224       43576 :             fprintf(stderr, sFormatString,
     225       21788 :                     (unsigned int)sTimeSpec.tv_sec,
     226       21788 :                     (unsigned int)(sTimeSpec.tv_nsec / 1000),
     227             :                     getpid(),
     228       21788 :                     asSeverity[prio],
     229             :                     s);
     230             :             break;
     231           0 :         case DLT_LOG_TO_SYSLOG:
     232             :             /* log to syslog */
     233             : #if !defined (__WIN32__) && !defined(_MSC_VER)
     234           0 :             openlog("DLT", LOG_PID, LOG_DAEMON);
     235           0 :             syslog(prio,
     236             :                    sFormatString,
     237           0 :                    (unsigned int)sTimeSpec.tv_sec,
     238           0 :                    (unsigned int)(sTimeSpec.tv_nsec / 1000),
     239             :                    getpid(),
     240           0 :                    asSeverity[prio],
     241             :                    s);
     242           0 :             closelog();
     243             : #endif
     244           0 :             break;
     245          32 :         case DLT_LOG_TO_FILE:
     246             :             /* log to file */
     247             : 
     248          32 :             if (dlt_is_log_in_multiple_files_active()) {
     249          24 :                 dlt_log_multiple_files_write(sFormatString, (unsigned int)sTimeSpec.tv_sec,
     250          12 :                                              (unsigned int)(sTimeSpec.tv_nsec / 1000), getpid(), asSeverity[prio], s);
     251             :             }
     252          20 :             else if (logging_handle) {
     253          40 :                 fprintf(logging_handle, sFormatString, (unsigned int)sTimeSpec.tv_sec,
     254          20 :                         (unsigned int)(sTimeSpec.tv_nsec / 1000), getpid(), asSeverity[prio], s);
     255          20 :                 fflush(logging_handle);
     256             :             }
     257             : 
     258             :             break;
     259             :         case DLT_LOG_DROPPED:
     260             :         default:
     261             :             break;
     262             :     }
     263             : 
     264             :     return DLT_RETURN_OK;
     265             : }
     266             : 
     267       37165 : DltReturnValue dlt_vlog(int prio, const char *format, ...)
     268             : {
     269       37165 :     char outputString[2048] = { 0 }; /* TODO: what is a reasonable string length here? */
     270             : 
     271             :     va_list args;
     272             : 
     273       37165 :     if (format == NULL)
     274             :         return DLT_RETURN_WRONG_PARAMETER;
     275             : 
     276       37165 :     if (logging_level < prio)
     277             :         return DLT_RETURN_OK;
     278             : 
     279        5693 :     va_start(args, format);
     280             :     vsnprintf(outputString, 2047, format, args);
     281        5693 :     va_end(args);
     282             : 
     283        5693 :     dlt_log(prio, outputString);
     284             : 
     285        5693 :     return DLT_RETURN_OK;
     286             : }
     287             : 
     288       16583 : DltReturnValue dlt_vnlog(int prio, size_t size, const char *format, ...)
     289             : {
     290             :     char *outputString = NULL;
     291             : 
     292             :     va_list args;
     293             : 
     294       16583 :     if (format == NULL)
     295             :         return DLT_RETURN_WRONG_PARAMETER;
     296             : 
     297       16583 :     if ((logging_level < prio) || (size == 0))
     298             :         return DLT_RETURN_OK;
     299             : 
     300       16583 :     if ((outputString = (char *)calloc(size + 1, sizeof(char))) == NULL)
     301             :         return DLT_RETURN_ERROR;
     302             : 
     303       16583 :     va_start(args, format);
     304             :     vsnprintf(outputString, size, format, args);
     305       16583 :     va_end(args);
     306             : 
     307       16583 :     dlt_log(prio, outputString);
     308             : 
     309       16583 :     free(outputString);
     310             :     outputString = NULL;
     311             : 
     312       16583 :     return DLT_RETURN_OK;
     313             : }
     314             : 
     315          12 : void dlt_log_multiple_files_write(const char* format, ...)
     316             : {
     317          12 :     char output_string[2048] = { 0 };
     318             :     va_list args;
     319          12 :     va_start (args, format);
     320             :     vsnprintf(output_string, 2047, format, args);
     321          12 :     va_end (args);
     322          12 :     multiple_files_buffer_write(&multiple_files_ring_buffer, (unsigned char*)output_string, strlen(output_string));
     323          12 : }
     324             : 
     325          15 : void dlt_log_free(void)
     326             : {
     327          15 :     if (logging_mode == DLT_LOG_TO_FILE) {
     328           5 :         if (dlt_is_log_in_multiple_files_active()) {
     329           3 :             dlt_log_free_multiple_logfiles();
     330             :         } else {
     331           2 :             dlt_log_free_single_logfile();
     332             :         }
     333             :     }
     334          15 : }
     335             : 
     336           2 : void dlt_log_free_single_logfile()
     337             : {
     338           2 :     if (logging_handle != NULL) {
     339           2 :         fclose(logging_handle);
     340             :     }
     341           2 : }
     342             : 
     343           3 : void dlt_log_free_multiple_logfiles()
     344             : {
     345           3 :     if (DLT_RETURN_ERROR == multiple_files_buffer_free(&multiple_files_ring_buffer)) return;
     346             : 
     347             :     // reset indicator of multiple files usage
     348           3 :     multiple_files_ring_buffer.ohandle = -1;
     349             : }
     350             : 
     351          37 : bool dlt_is_log_in_multiple_files_active()
     352             : {
     353          37 :     return multiple_files_ring_buffer.ohandle > -1;
     354             : }

Generated by: LCOV version 1.14