LCOV - code coverage report
Current view: top level - src - mo_logging.F90 (source / functions) Hit Total Coverage
Test: forces coverage Lines: 0 122 0.0 %
Date: 2024-03-13 19:03:28 Functions: 0 18 0.0 %

          Line data    Source code
       1             : #include "logging.h"
       2             : !> \file    mo_logging.F90
       3             : !> \brief   \copybrief mo_logging
       4             : !> \details \copydetails mo_logging
       5             : 
       6             : !> \brief   Module providing a logging framework.
       7             : !> \version 0.1
       8             : !> \authors Daan van Vugt, Sebastian Mueller, Robert Schweppe
       9             : !> \date    Sep 2022
      10             : !> \copyright flogging was originally released under the MIT license.
      11             : !> \details A simple logging framework derived from flogging (https://github.com/DaanVanVugt/flogging).
      12             : !!          To use logging you need to include `logging.h` at the top of your fortran file.
      13             : !!
      14             : !!          \note The file needs to processed by the pre-processor.
      15             : !!
      16             : !!          Afterwards you have a list of logging routines that could be used instead of `write`:
      17             : !!            - `log_fatal(format)`: level 1
      18             : !!            - `log_error(format)`: level 2
      19             : !!            - `log_warn(format)`: level 3
      20             : !!            - `log_info(format)`: level 4
      21             : !!            - `log_debug(format)`: level 5
      22             : !!            - `log_trace(format)`: level 6
      23             : !!            - `log_subtrace(format)`: level 7
      24             : !!          as required.
      25             : !!
      26             : !!          The following example demonstrates the functionality. The `mo_cli` module incorporates logger settings:
      27             : !!          \code{.f90}
      28             : !!          #include "logging.h"
      29             : !!          program test_log
      30             : !!            use mo_logging
      31             : !!            use mo_cli, only : cli_parser
      32             : !!            implicit none
      33             : !!            type(cli_parser) :: parser
      34             : !!            parser = cli_parser( &
      35             : !!              description="Program with cli and logger.", &
      36             : !!              add_help_option=.true., &
      37             : !!              add_logger_options=.true.)
      38             : !!            call parser%parse()
      39             : !!            log_fatal(*) "fatal"
      40             : !!            log_error(*) "error"
      41             : !!            log_warn(*) "warn"
      42             : !!            log_info(*) "info"
      43             : !!            log_debug(*) "debug"
      44             : !!            log_trace(*) "trace"
      45             : !!            log_subtrace(*) "subtrace"
      46             : !!          end program test_log
      47             : !!          \endcode
      48             : !!          You can call the program with:
      49             : !!          \code{.sh}
      50             : !!          $ ./prog --quiet
      51             : !!            test.F90:12    FATAL fatal
      52             : !!            test.F90:13    ERROR error
      53             : !!            test.F90:14     WARN warn
      54             : !!          \endcode
      55             : !!          You can see all cli logger options with:
      56             : !!          \code{.sh}
      57             : !!          $ ./prog -h
      58             : !!          \endcode
      59             : !> \copyright Copyright 2005-\today, the CHS Developers, Sabine Attinger: All rights reserved.
      60             : !! FORCES is released under the LGPLv3+ license \license_note
      61             : module mo_logging
      62             :   ! Copyright (c) 2016 Daan van Vugt
      63             :   !
      64             :   ! Permission is hereby granted, free of charge, to any person
      65             :   ! obtaining a copy of this software and associated documentation
      66             :   ! files (the "Software"), to deal in the Software without
      67             :   ! restriction, including without limitation the rights to use,
      68             :   ! copy, modify, merge, publish, distribute, sublicense, and/or sell
      69             :   ! copies of the Software, and to permit persons to whom the
      70             :   ! Software is furnished to do so, subject to the following
      71             :   ! conditions:
      72             :   !
      73             :   ! The above copyright notice and this permission notice shall be
      74             :   ! included in all copies or substantial portions of the Software.
      75             :   !
      76             :   ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      77             :   ! EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
      78             :   ! OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      79             :   ! NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      80             :   ! HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      81             :   ! WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      82             :   ! FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      83             :   ! OTHER DEALINGS IN THE SOFTWARE.
      84             : 
      85             : #ifdef NAG
      86             :   use f90_unix_env, only: isatty
      87             :   use f90_unix_env, only: gethostname
      88             : #endif
      89             : #ifdef INTEL
      90             :   use ifport, only: isatty
      91             :   use ifport, only: hostnm
      92             : #endif
      93             :   use mo_constants, only: stdout=>nout, stderr=>nerr
      94             : 
      95             :   implicit none
      96             :   ! Log levels
      97             :   integer, public, parameter :: NUM_LOG_LEVELS = 7 !< 1 through 7 (fatal through trace)
      98             :   integer, public, parameter :: LOG_FATAL = LOG_LEVEL_FATAL_DEF !< = 1, Runtime error causing termination
      99             :   integer, public, parameter :: LOG_ERROR = LOG_LEVEL_ERROR_DEF !< = 2, Runtime error
     100             :   integer, public, parameter :: LOG_WARN  = LOG_LEVEL_WARN_DEF !< = 3, Warning, but we can continue
     101             :   integer, public, parameter :: LOG_INFO  = LOG_LEVEL_INFO_DEF !< = 4, Interesting events
     102             :   integer, public, parameter :: LOG_DEBUG = LOG_LEVEL_DEBUG_DEF !< = 5, Detailed debug output, disable by compiling your program with -DDISABLE_LOG_DEBUG
     103             :   integer, public, parameter :: LOG_TRACE = LOG_LEVEL_TRACE_DEF !< = 6, Extremely detailed output, compile your program with -DENABLE_LOG_TRACE to enable
     104             :   integer, public, parameter :: LOG_SUBTRACE = LOG_LEVEL_SUBTRACE_DEF !< = 7, More Extremely detailed output, compile your program with -DENABLE_LOG_TRACE to enable
     105             : 
     106             :   integer, public, save :: log_unit = stdout !< By default, log to stdout for level > 2
     107             :   integer, public, save :: log_unit_error = stderr !< By default, log to stderr for level <= 2
     108             :   integer, public, save :: minimum_log_level = LOG_INFO !< Note that more critical means a lower number
     109             :   logical, public, save :: show_file_and_line = .true. !< show file name and line number in log output
     110             : 
     111             :   public :: log_set_output_hostname
     112             :   public :: log_set_output_severity
     113             :   public :: log_set_output_date
     114             :   public :: log_set_output_time
     115             :   public :: log_set_output_fileline
     116             :   public :: log_set_skip_terminal_check
     117             :   public :: log_set_disable_colors
     118             :   public :: log_set_disable_format
     119             :   public :: log_set_config
     120             : 
     121             :   public :: logu, logp, logl, stput
     122             : 
     123             :   private
     124             :   !> Control start character
     125             :   character(len=*), parameter :: start = achar(27)
     126             :   !> Control reset character
     127             :   character(len=*), parameter :: reset = "0"
     128             :   !> Styles
     129             :   character(len=*), parameter :: bold = "1", dimmed = "2", &
     130             :     underline = "4", blink = "5", invert = "7", hidden = "8"
     131             : 
     132             :   ! Default settings for hostname and severity output
     133             :   logical, save :: output_hostname     = .false.
     134             :   logical, save :: output_severity     = .true.
     135             :   logical, save :: output_date         = .false.
     136             :   logical, save :: output_time         = .false.
     137             :   logical, save :: output_fileline     = .true.
     138             :   logical, save :: skip_terminal_check = .false.
     139             :   logical, save :: disable_colors      = .false.
     140             :   logical, save :: disable_format      = .false.
     141             : 
     142             :   !> These are the color codes corresponding to the loglevels above
     143             :   character(len=*), dimension(NUM_LOG_LEVELS), parameter :: color_codes = &
     144             :       ["31", "31", "33", "32", "35", "36", "36"]
     145             :   !> These are the styles corresponding to the loglevels above
     146             :   character(len=*), dimension(NUM_LOG_LEVELS), parameter :: style_codes = &
     147             :       [bold, reset, reset, reset, reset, reset, reset]
     148             : 
     149             :   !> Colors for other output
     150             :   character(len=*), parameter :: level_color = "20"
     151             : 
     152             : contains
     153             :   !> \brief write format string to given unit
     154           0 :   subroutine tput(lu, code)
     155             :     implicit none
     156             :     integer, intent(in) :: lu !< unit
     157             :     character(len=*), intent(in) :: code !< format code
     158             :     if (.not. disable_format) write(lu, '(a,"[",a,"m")', advance="no") start, code
     159             :   end subroutine tput
     160             : 
     161             :   !> \brief generate format string
     162           0 :   subroutine stput(str, code)
     163             :     implicit none
     164             :     character(len=*), intent(inout) :: str !< pre string
     165             :     character(len=*), intent(in)    :: code !< format code
     166           0 :     if (.not. disable_format) str = trim(str) // start // "[" // trim(code) // "m"
     167           0 :   end subroutine stput
     168             : 
     169             :   !> \brief Set the default for hostname output
     170           0 :   subroutine log_set_output_hostname(bool)
     171             :     logical, intent(in) :: bool
     172           0 :     output_hostname = bool
     173           0 :   end subroutine log_set_output_hostname
     174             : 
     175             :   !> \brief Set the default for severity output
     176           0 :   subroutine log_set_output_severity(bool)
     177             :     logical, intent(in) :: bool
     178           0 :     output_severity = bool
     179           0 :   end subroutine log_set_output_severity
     180             : 
     181             :   !> \brief Set the default for date output
     182           0 :   subroutine log_set_output_date(bool)
     183             :     logical, intent(in) :: bool
     184           0 :     output_date = bool
     185           0 :   end subroutine log_set_output_date
     186             : 
     187             :   !> \brief Set time-only date format
     188           0 :   subroutine log_set_output_time(bool)
     189             :     logical, intent(in) :: bool
     190           0 :     output_time = bool
     191           0 :   end subroutine log_set_output_time
     192             : 
     193             :   !> \brief Set the default for file/line output
     194           0 :   subroutine log_set_output_fileline(bool)
     195             :     logical, intent(in) :: bool
     196           0 :     output_fileline = bool
     197           0 :   end subroutine log_set_output_fileline
     198             : 
     199             :   !> \brief Whether or not to skip the terminal check
     200           0 :   subroutine log_set_skip_terminal_check(bool)
     201             :     logical, intent(in) :: bool
     202           0 :     skip_terminal_check = bool
     203           0 :   end subroutine log_set_skip_terminal_check
     204             : 
     205             :   !> \brief Disable colors altogether
     206           0 :   subroutine log_set_disable_colors(bool)
     207             :     logical, intent(in) :: bool
     208           0 :     disable_colors = bool
     209           0 :   end subroutine log_set_disable_colors
     210             : 
     211             :   !> \brief Disable formatting altogether
     212           0 :   subroutine log_set_disable_format(bool)
     213             :     logical, intent(in) :: bool
     214           0 :     disable_format = bool
     215           0 :   end subroutine log_set_disable_format
     216             : 
     217             :   !> \brief Output unit to log.
     218             :   !> \return unit number.
     219           0 :   function logu(level)
     220             :     integer, intent(in)           :: level     !< The log level of the current message
     221             :     integer                       :: logu      !< unit to log to (stderr for level <=2 else stdout by default)
     222             : 
     223           0 :     if (level .le. LOG_ERROR) then
     224           0 :       logu = log_unit_error
     225             :     else
     226           0 :       logu = log_unit
     227             :     endif
     228           0 :   end function logu
     229             : 
     230             :   !> \brief Output this log statement or not.
     231             :   !> \return true if this log message can be printed.
     232           0 :   function logp(level, only_n)
     233             : #ifdef USE_MPI
     234             :     use mpi
     235             : #endif
     236             :     integer, intent(in)           :: level     !< The log level of the current message
     237             :     integer, intent(in), optional :: only_n    !< Show only if the current mpi rank equals only_n
     238             :     logical                       :: logp      !< Output: true if this log message can be printed
     239             : #ifdef USE_MPI
     240             :     integer :: rank, ierr
     241             : #endif
     242             : 
     243           0 :     if (level .le. minimum_log_level) then
     244             :       logp = .true.
     245             :     else
     246           0 :       logp = .false.
     247             :     endif
     248             : #ifdef USE_MPI
     249             :     if (logp .and. present(only_n)) then
     250             :       call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
     251             :       if (rank .ne. only_n) logp = .false.
     252             :     endif
     253             : #endif
     254           0 :   end function logp
     255             : 
     256             :   !> \brief Write a log lead containing level and optional info.
     257             :   !> \details The name is shortened to allow for longer log messages without needing continuations.
     258             :   !> \return The output log leader.
     259           0 :   function logl(level, filename, linenum)
     260             :     implicit none
     261             :     ! Input parameters
     262             :     integer                    :: level    !< The log level
     263             :     character(len=*), optional :: filename !< An optional filename to add to the log lead
     264             :     integer, optional          :: linenum  !< With line number
     265             :     character(len=300)         :: logl     !< The output log leader
     266             : 
     267             :     ! Internal parameters
     268             :     character(len=50), dimension(6) :: log_tmp !< The different parts of the log lead
     269             :     integer                         :: fn_len  !< Add extra spaces after part i
     270             :     integer       :: i, j, space_cnt !< The counter for the different parts
     271             :     character(4)  :: linenum_lj ! left-justified line number
     272             :     character(len=50) :: basename ! basename stripped from filename
     273             : 
     274             :     logical :: show_colors = .false.
     275             :     logical :: is_terminal = .false.
     276           0 :     i = 1
     277             : 
     278             :     ! Set level to 1 if it is too low, skip if too high
     279           0 :     if (level .lt. 1) level = 1
     280           0 :     if (level .gt. minimum_log_level .or. level .gt. NUM_LOG_LEVELS) return
     281             : 
     282             :     ! only show colors if we are outputting to a terminal
     283           0 :     if (skip_terminal_check) then
     284           0 :       show_colors = .not. disable_colors
     285             :     else
     286             : #ifdef NAG
     287             :       call isatty(stdout, is_terminal)
     288             : #else
     289           0 :       is_terminal = isatty(stdout)
     290             : #endif
     291           0 :       show_colors = is_terminal .and. .not. disable_colors
     292             :     endif
     293             :     ! This works in ifort and gfortran (log_unit is stdout here because log_lead is an internal string)
     294             : 
     295             :     ! Initialize log_tmp
     296           0 :     log_tmp = ""
     297           0 :     fn_len = 0
     298             : 
     299             :     ! Reset the colors if needed
     300           0 :     if (show_colors) call stput(log_tmp(i), reset) ! Do not increment i to add it before the next space
     301             : 
     302             :     ! Write date and time if wanted
     303           0 :     if (output_date .or. output_time) then
     304           0 :       log_tmp(i) = trim(log_tmp(i)) // log_datetime()
     305           0 :       i = i + 1
     306             :     endif
     307             : 
     308             :     ! Write hostname if requested
     309           0 :     if (output_hostname) then
     310           0 :       log_tmp(i) = trim(log_tmp(i)) // log_hostname()
     311           0 :       i = i + 1
     312             :     endif
     313             : 
     314             : #ifdef USE_MPI
     315             :     ! Write mpi id
     316             :     log_tmp(i) = trim(log_tmp(i)) // log_mpi_id()
     317             :     i = i + 1
     318             : #endif
     319             : 
     320           0 :     if (present(filename) .and. output_fileline .and. show_file_and_line) then
     321           0 :       call strip_path(filename, basename)
     322           0 :       log_tmp(i) = trim(log_tmp(i)) // trim(basename)
     323           0 :       if (present(linenum)) then
     324             :         ! Left-justify the line number and cap it to 4 characters
     325           0 :         write(linenum_lj, '(i4)') linenum
     326           0 :         log_tmp(i) = trim(log_tmp(i)) // ":" // adjustl(linenum_lj)
     327             :       endif
     328             :       ! How many extra spaces are needed to fill out to multiple of n characters
     329           0 :       fn_len = fn_len + len_trim(log_tmp(i))
     330           0 :       i = i+1
     331             :     endif
     332             : 
     333             :     ! Output severity level
     334           0 :     if (output_severity) then
     335           0 :       fn_len = fn_len + len_trim(log_severity(level, .false.))
     336             :       ! correctly set spaces when skipping filename/line
     337           0 :       space_cnt = mod(7-fn_len,8)+8
     338           0 :       if (space_cnt >= 8) space_cnt = space_cnt - 8
     339           0 :       log_tmp(i) = trim(log_tmp(i)) // spaces(space_cnt) // log_severity(level, show_colors)
     340             :     endif
     341             : 
     342             :     ! Set color based on severity level
     343           0 :     if (show_colors) then
     344             :       ! Set bold for errors (must go first, resets the color code otherwise)
     345           0 :       call stput(log_tmp(i), style_codes(level))
     346           0 :       call stput(log_tmp(i), color_codes(level))
     347             :     endif
     348             : 
     349             :     ! Concatenate trim(log_tmp(i)) with spaces in between
     350           0 :     logl = log_tmp(1)
     351           0 :     do j=2,i
     352           0 :       logl = trim(logl) // " " // trim(log_tmp(j))
     353             :     enddo
     354           0 :   end function logl
     355             : 
     356             :   !> \brief Get base name of a file path.
     357           0 :   subroutine strip_path(filepath, basename)
     358             :     ! keeping this subroutine to prevent circular dependencies: mo_os -> mo_message -> mo_logging -> mo_os
     359             :     character(len=*), intent(in) :: filepath !< The path to be stripped
     360             :     character(len=*), intent(out) :: basename !< The basename of the filepath
     361             :     integer :: last_sep_idx
     362           0 :     last_sep_idx = index(filepath, "/", .true.)
     363           0 :     basename = filepath(last_sep_idx+1:)
     364           0 :   end subroutine
     365             : 
     366             :   !> \brief Return the hostname in a 50 character string
     367             :   !> \return hostname.
     368           0 :   function log_hostname()
     369             :     character(len=50) log_hostname
     370             : #ifdef INTEL
     371             :     integer :: iError
     372             : #endif
     373             : #ifdef NAG
     374             :     call gethostname(log_hostname)
     375             : #endif
     376             : #ifdef INTEL
     377             :     iError = hostnm(log_hostname)
     378             : #endif
     379             : #ifdef GFORTRAN
     380           0 :     call hostnm(log_hostname)
     381             : #endif
     382           0 :   end function log_hostname
     383             : 
     384             :   !> \brief Return n spaces
     385             :   !> \return n spaces.
     386           0 :   function spaces(n)
     387             :     integer, intent(in) :: n !< Maximum is 30
     388             :     character(len=n)    :: spaces
     389           0 :     spaces = "                              "
     390           0 :   end function spaces
     391             : 
     392             :   !> \brief Return the severity level with colors etc in a 50 char string
     393             :   !> \return severity level.
     394           0 :   function log_severity(level, show_colors)
     395             :     integer, intent(in) :: level
     396             :     logical, intent(in) :: show_colors
     397             :     character(len=50) log_severity
     398             : 
     399           0 :     log_severity = ""
     400           0 :     if (show_colors) call stput(log_severity, level_color)
     401           0 :     if (level .eq. LOG_FATAL) then
     402           0 :       if (show_colors) then
     403           0 :         call stput(log_severity, bold)
     404           0 :         call stput(log_severity, color_codes(level)) ! error has the same color, for reading convenience
     405             :       endif
     406           0 :       log_severity = trim(log_severity) // "FATAL"
     407             :     elseif (level .eq. LOG_ERROR) then
     408           0 :       if (show_colors) call stput(log_severity, bold)
     409           0 :       log_severity = trim(log_severity) // "ERROR"
     410             :     elseif (level .eq. LOG_WARN) then
     411           0 :       log_severity = trim(log_severity) // "WARN"
     412             :     elseif (level .eq. LOG_INFO) then
     413           0 :       log_severity = trim(log_severity) // "INFO"
     414             :     elseif (level .eq. LOG_DEBUG) then
     415           0 :       log_severity = trim(log_severity) // "DEBUG"
     416             :     elseif (level .eq. LOG_TRACE) then
     417           0 :       log_severity = trim(log_severity) // "TRACE"
     418             :     elseif (level .eq. LOG_SUBTRACE) then
     419           0 :       log_severity = trim(log_severity) // "FINE"
     420             :     endif
     421           0 :     if (show_colors) call stput(log_severity, reset)
     422           0 :   end function log_severity
     423             : 
     424             : #ifdef USE_MPI
     425             :   !> \brief Return the mpi id of the current process
     426             :   !> \return MPI id.
     427             :   function log_mpi_id()
     428             :     use mpi
     429             :     character(50) :: log_mpi_id    !< The mpi id part of a log
     430             :     character(6)  :: mpi_id_lj     !< MPI id in string
     431             :     character(4)  :: id_fmt        !< The forhmat to print mpi_id_lj in
     432             :     integer :: rank, n_cpu, ierr
     433             : 
     434             :     call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
     435             :     call MPI_COMM_SIZE(MPI_COMM_WORLD, n_cpu, ierr)
     436             :     if (n_cpu .eq. 1) then
     437             :       log_mpi_id = ""
     438             :     else
     439             :       write(id_fmt, '(A,i1,A)') "(i", ceiling(log10(real(n_cpu))), ")"
     440             :       write(mpi_id_lj,id_fmt) rank
     441             :       write(log_mpi_id, '("#",a)') trim(adjustl(mpi_id_lj))
     442             :     endif
     443             :   end function log_mpi_id
     444             : #endif
     445             : 
     446             :   !> \brief Return the current date, formatted nicely
     447             :   !> \return date.
     448           0 :   function log_datetime()
     449             :     character(50) :: log_datetime !< Output the date here
     450             : 
     451             :     character(8)  :: date
     452             :     character(10) :: time
     453             :     character(5)  :: zone
     454             : 
     455           0 :     call date_and_time(date, time, zone)
     456           0 :     if (output_date .and. output_time) then
     457           0 :       write(log_datetime, '(a,"/",a,"/",a," ",a,":",a,":",a,".",a," ")') date(1:4), date(5:6), date(7:8), &
     458           0 :             time(1:2), time(3:4), time(5:6), time(8:10)
     459             :     else
     460           0 :       if (output_time) then
     461           0 :         write(log_datetime, '(a,":",a,":",a,".",a," ")') time(1:2), time(3:4), time(5:6), time(8:10)
     462             :       endif
     463           0 :       if (output_date) then
     464           0 :         write(log_datetime, '(a,"/",a,"/",a," ")') date(1:4), date(5:6), date(7:8)
     465             :       endif
     466             :     endif
     467           0 :   end function log_datetime
     468             : 
     469             :   !> \brief Set logging configuration
     470           0 :   subroutine log_set_config( &
     471             :     verbose, quiet, log_output_hostname, log_force_colors, log_no_colors, log_output_date, log_output_time, log_no_format)
     472           0 :     use mo_kind, only: i4
     473             :     implicit none
     474             :     integer(i4), optional, intent(in) :: verbose !< increase verbosity level
     475             :     integer(i4), optional, intent(in) :: quiet !< decrease verbosity level
     476             :     logical, optional, intent(in) :: log_output_hostname !< show hostname
     477             :     logical, optional, intent(in) :: log_force_colors !< force colors in output
     478             :     logical, optional, intent(in) :: log_no_colors !< disable colors
     479             :     logical, optional, intent(in) :: log_output_date !< add date to output
     480             :     logical, optional, intent(in) :: log_output_time !< add time to output
     481             :     logical, optional, intent(in) :: log_no_format !< disable formatting
     482             : 
     483           0 :     if ( present(verbose) ) minimum_log_level = min(NUM_LOG_LEVELS, minimum_log_level + verbose)
     484           0 :     if ( present(quiet) ) minimum_log_level = min(NUM_LOG_LEVELS, minimum_log_level - quiet)
     485           0 :     if ( present(log_output_hostname) ) output_hostname = log_output_hostname
     486           0 :     if ( present(log_force_colors) ) skip_terminal_check = log_force_colors
     487           0 :     if ( present(log_no_colors) ) disable_colors = log_no_colors
     488           0 :     if ( present(log_output_date) ) output_date = log_output_date
     489           0 :     if ( present(log_output_time) ) output_time = log_output_time
     490           0 :     if ( present(log_no_format) ) disable_format = log_no_format
     491           0 :   end subroutine log_set_config
     492             : 
     493             : end module mo_logging

Generated by: LCOV version 1.16