logger_utilities.f90 Source File

This module includes the definition of a class called logger that is used to log messages on the screen during the development or running of a given application


This file depends on

sourcefile~~logger_utilities.f90~~EfferentGraph sourcefile~logger_utilities.f90 logger_utilities.f90 sourcefile~constants_utilities.f90 constants_utilities.f90 sourcefile~logger_utilities.f90->sourcefile~constants_utilities.f90 sourcefile~precision_utilities.f90 precision_utilities.f90 sourcefile~constants_utilities.f90->sourcefile~precision_utilities.f90

Files dependent on this one

sourcefile~~logger_utilities.f90~~AfferentGraph sourcefile~logger_utilities.f90 logger_utilities.f90 sourcefile~som_train_variables.f90 som_train_variables.f90 sourcefile~som_train_variables.f90->sourcefile~logger_utilities.f90

Source Code

!! author: Arjen Markus, Oscar Garcia-Cabrejo
!! date: 06/09/2023
!! version: 0.1
!! This module includes the definition of a class called logger that is used 
!! to log messages on the screen during the development or running of a given 
!! application
module logger_utilities
!
use constants_utilities, only: NUMCHAR;
!
implicit none;
!
private;
!
type logger 
    private
!! The Logger class is used to store all the variables related to the units of 
!! files used to store or print messages during the development (debugging ) or 
!! running
        integer :: fileunit,stdout
        logical :: activate_screen,activate_file,timestamp
        logical :: initialized,stoponerror
        character(len=NUMCHAR) :: level_string_volume,level_string_chapter,level_string_section
        character(len=NUMCHAR) :: level_string_subsection 
    contains
        procedure,public :: create => create_logger
        procedure,public :: destroy => destroy_logger
        procedure,public :: startup
        procedure,public :: shutdown
        procedure,public :: is_initialized
        procedure,public :: message
        procedure,public :: write
        procedure,private :: get_available_unit
        procedure,private :: configure_logical
        procedure,private :: configure_integer
        procedure,private :: configure_character
        generic,public :: configure => configure_logical,configure_integer,configure_character
!        generic,public :: get 
        procedure,public :: get_unit
        procedure,public :: delimiter
        procedure,public :: get_delimiter
        procedure,public :: reset
        procedure,public :: error
end type logger
!
type(logger) :: global_logger;
!
public :: logger,global_logger
!
contains 
!========================================================================================
    subroutine create_logger(current_log)
!========================================================================================
!! logger constructor
        class(logger) :: current_log
!! a logger object
        current_log%initialized=.FALSE.;
        current_log%activate_screen=.TRUE.;
        current_log%activate_file=.TRUE.;
        current_log%timestamp=.FALSE.;
        current_log%fileunit=10;
        current_log%stdout=-1;
        current_log%stoponerror=.TRUE.;
!
    end subroutine create_logger
!========================================================================================
    subroutine destroy_logger(current_log)
!========================================================================================
!! Logger destructor  
        class(logger) :: current_log
!! A logger object
        current_log%level_string_volume=''
        current_log%level_string_chapter=''
        current_log%level_string_section=''
!
    end subroutine destroy_logger
!========================================================================================
    subroutine startup(current_log,log_file,append_)
!========================================================================================
!! Subroutine to initialize a logger object 
        class(logger) :: current_log
!! A logger object
        character(len=*) :: log_file
!! A character variable with the name of the file associated to the logger
        logical,intent(in),optional :: append_
!! A logical (optional) variable to indicate if appending to an existing file 
!!          is desired
!
        logical :: append_real
!
        if(present(append_)) then
            append_real=append_;
        else 
            append_real=.TRUE.;
        endif
        if(current_log%initialized) then 
            call current_log%error('Logger not initialized');
        else 
            current_log%fileunit=current_log%get_available_unit();
            if(append_real) then
                open(current_log%fileunit,file=log_file,status='unknown',action='write',position='append');
            else
                open(current_log%fileunit,file=log_file,status='unknown',action='write',form='formatted'); 
            endif
            current_log%initialized=.TRUE.; 
        endif
!
    end subroutine startup
!========================================================================================
    subroutine shutdown(current_log)
!========================================================================================
!! Subroutine to turn-off the logger
        class(logger) :: current_log
!! A logger object
!
        current_log%initialized=.FALSE.;
!
    end subroutine shutdown
!========================================================================================
    function is_initialized(current_log) result(initialized)
!========================================================================================
!! Function to check if a logger is initialized
        class(logger) :: current_log
!! A logger object
        logical :: initialized
!!  A logical variable 
        initialized=current_log%initialized;
!
    end function is_initialized
!========================================================================================
    subroutine reset(current_log)
!========================================================================================
!! Subroutine to reset the logger
        class(logger) :: current_log
!! A logger object
        current_log%activate_screen=.TRUE.;
        current_log%activate_file=.TRUE.;
        current_log%timestamp=.FALSE.;
!
    end subroutine reset
!========================================================================================
    subroutine message(current_log,msg)
!========================================================================================
!! Subroutine to send a message to the logger
        class(logger) :: current_log
!! A logger object
        character(len=*) :: msg
!! A character variable with the message to send to the logger  
!
        character(len=NUMCHAR) :: date_string
        character(len=NUMCHAR) :: time_string
        character(len=NUMCHAR) :: stamp
!
        if(current_log%timestamp) then 
            call date_and_time(date = date_string, time = time_string);
            write(stamp, '(11A)') date_string(1:4), '-', date_string(5:6), '-', date_string(7:8), ' ',&
            time_string(1:2), ':', time_string(3:4), ':', time_string(5:6);
        else 
            stamp = ' ';
        endif 
        if(current_log%activate_screen) then 
            if(current_log%timestamp) then 
                call current_log%write(current_log%stdout, trim(stamp) // ' ' // trim(msg));
            else 
                call current_log%write(current_log%stdout,trim(msg));
            endif
        endif
        if(current_log%activate_file) then 
            if(current_log%timestamp) then 
                call current_log%write(current_log%fileunit, trim(stamp) // ' ' // trim(msg));
            else 
                call current_log%write(current_log%fileunit,trim(msg));
            endif
        endif
!
    end subroutine message
!========================================================================================
    subroutine write(current_log,unit_,msg)
!========================================================================================
!! Subroutine to write a message in a file associated with the logger
        class(logger) :: current_log
!! A logger object
        integer,intent(in) :: unit_ 
!! An integer variable with the value of the output unit
        character(len=*) :: msg
!! A character variable with the message to be written in the output unit
        character(len=NUMCHAR) :: filename
        integer :: unit1
!
        unit1=unit_;
        if(unit1 == -1) then 
            write(*,'(A)') trim(msg);
        else 
            write(unit1,'(A)') trim(msg);
            inquire(unit1, name = filename);
            close(unit1);
            open(unit1,file=trim(filename),action='write',status='unknown',position='append');
        endif
!
    end subroutine write 
!========================================================================================
    function get_available_unit(current_log) result(un)
!========================================================================================
!! Function to get the next available unit
        class(logger) :: current_log
!! A logger object
        integer :: un
!! An integer variable with the number of the next available unit
!
        logical :: check_unit
        integer :: iunit
!
        if(current_log%fileunit /= 10) then
            inquire(unit = un, opened = check_unit);
            if(.not. check_unit) then
                un = current_log%fileunit;
                return;
            endif
        else
            do iunit=10,99
                inquire(unit = iunit, opened = check_unit)
                if(.not. check_unit) then
                    un=iunit;
                    current_log%fileunit=un;
                    return;
                endif
            enddo
        endif
!
    end function get_available_unit
!========================================================================================
    subroutine configure_logical(current_log,option,value)
!========================================================================================
!! Subroutine to define the logger state
        class(logger) :: current_log
!! A logger object
        character(len=*),intent(in) :: option 
!! A character variable with the name of the state to be defined 
        logical,intent(in) :: value
!! A logical variable 
!
        character(len=NUMCHAR) :: message
!
        select case ( option )
            case ( "timestamp" )
                current_log%timestamp = value;
            case ( "writeonstdout" )
                current_log%activate_screen = value;
            case ( "writeonlogfile" )
                current_log%activate_file = value;
            case ( "stoponerror" )
                current_log%stoponerror = value;
            case default
                write (message,"(A,A,A,l5,A)") "Unknown option ", option, &
                        " for value ", value, " in log_configure_logical"
                call current_log%error(message);
    end select
!
    end subroutine configure_logical
!========================================================================================
    subroutine configure_integer(current_log,option,value)
!========================================================================================
!! Subroutine to define a logger integer state 
        class(logger) :: current_log
!! A logger object
        character(len=*),intent(in) :: option
!! A character variable with the name of the state to be defined 
        integer,intent(in) :: value 
!! An integer variable 
        character(len=NUMCHAR) :: message
!
        select case ( option )
            case ( "logfileunit" )
                current_log%fileunit = value
            case default
                write (message,"(A,A,A,I5,A)") "Unknown option ", option, &
                    " for value ", value, " in log_configure_integer"
            call current_log%error(message);
    end select
!
    end subroutine configure_integer
!========================================================================================
    subroutine configure_character(current_log,option,value)
!========================================================================================
!! Subroutine to define a logger character state 
        class(logger) :: current_log
!! A logger object
        character(len=*),intent(in) :: option 
!! A character variable with the name of the state to be defined 
        character(len=*),intent(in) :: value
!! A character variable
        character (len = NUMCHAR) :: message
!        
        select case ( option )
            case ( "volume" )
                current_log%level_string_volume = value;
            case ( "chapter" )
                current_log%level_string_chapter = value;
            case ( "section" )
                current_log%level_string_section = value;
            case ( "subsection" )
                current_log%level_string_subsection = value;
            case default
                write (message,"(A,A,A,A,A)") "Unknown option ", option, &
                    " for value ", value, " in log_configure_character";
            call current_log%error(message);
        end select
!
    end subroutine configure_character
!========================================================================================
    subroutine delimiter(current_log,level)
!========================================================================================
!! Subroutine that defines the delimiter in a logger repport
        class(logger) :: current_log
!! A logger object        
        character(len=*),optional :: level
!! A character variable with the definition of the delimiter 
!
        character(len=NUMCHAR) :: used_level
        character(len=NUMCHAR) :: msg
!
        if(present(level)) then 
            used_level=level;
        else 
            used_level='volume';
        endif
        call current_log%get_delimiter(used_level,msg);
        call current_log%message(msg(1:30));
!
    end subroutine delimiter
!========================================================================================
    subroutine get_delimiter(current_log,level,msg)
!========================================================================================
!! Subroutine to get the delimiter text
        integer,parameter :: LOG_LEVEL_DELIMITER_LENGTH = 30
        character(len=LOG_LEVEL_DELIMITER_LENGTH),parameter :: log_level_string_volume = "==============================";
        character(len=LOG_LEVEL_DELIMITER_LENGTH),parameter :: log_level_string_chapter = "------------------------------";
        character(len=LOG_LEVEL_DELIMITER_LENGTH),parameter :: log_level_string_section = "******************************";
        character(len=LOG_LEVEL_DELIMITER_LENGTH),parameter :: log_level_string_subsection = "++++++++++++++++++++++++++++++";
        class(logger) :: current_log
!! A logger object   
        character(len=*) :: level 
!! A character variable
        character(len=100) :: msg
!! A character variable
        select case (level)
            case ('volume')
                write(msg,*) trim(log_level_string_volume);
            case ('chapter')
                write(msg,*) trim(log_level_string_chapter);
            case ('section')
                write(msg,*) trim(log_level_string_section);
            case ('subsection')
                write(msg,*)  trim(log_level_string_subsection);
            case default
       ! NOTE :
       ! We do not use m_exception here to limit the dependencies of
       ! such a low level utility.
                write(*,*) "Bad value for the message level:" , level
                write(*,*)
                stop
        end select
!
    end subroutine get_delimiter
!========================================================================================
    function get_unit(current_log) result ( logger_unit )
!========================================================================================
!! Function to get the logger unit
        class(logger) :: current_log
!! A logger object        
        integer :: logger_unit
!! An integer variable with the logger unit
        logger_unit = current_log%fileunit
!
    end function get_unit
!========================================================================================
    subroutine error(current_log,message)
!========================================================================================
!! Subroutine to print an error message
        class(logger) :: current_log
!! A logger object     
        character (len=*), intent(in) :: message
!! A character varaible with the error message        
        write ( 6, "(A)" ) "Error in m_logger."
        write ( 6 , "(A)" ) trim(message)
        stop;
!
    end subroutine error 
!    
end module logger_utilities