s3_logger.f90 Source File


Source Code

!> Logging module for S3 accessor library.
!>
!> Provides configurable logging with multiple severity levels to help
!> diagnose issues and understand library behavior.
!>
!> ## Log Levels
!>
!> - **NONE (0)**: No logging output
!> - **ERROR (1)**: Critical errors only
!> - **WARN (2)**: Warnings and errors
!> - **INFO (3)**: General information, warnings, and errors
!> - **DEBUG (4)**: Detailed debugging information
!> - **TRACE (5)**: Very detailed tracing (includes curl commands, responses)
!>
!> ## Usage
!>
!> ```fortran
!> use s3_logger
!>
!> ! Set log level (default is ERROR)
!> call s3_set_log_level(S3_LOG_LEVEL_DEBUG)
!>
!> ! Log messages at different levels
!> call s3_log_error('Failed to download object')
!> call s3_log_warn('Retrying connection')
!> call s3_log_info('Initialized S3 connection')
!> call s3_log_debug('Built URL: https://...')
!> call s3_log_trace('curl command: curl -s ...')
!> ```
!>
!> ## Environment Variable
!>
!> Log level can be set via environment variable `S3_LOG_LEVEL`:
!> ```bash
!> export S3_LOG_LEVEL=DEBUG
!> ./my_program
!> ```
!>
!> Valid values: NONE, ERROR, WARN, INFO, DEBUG, TRACE (case-insensitive)
module s3_logger
    implicit none
    private

    ! Public procedures
    public :: s3_set_log_level
    public :: s3_get_log_level
    public :: s3_log_error
    public :: s3_log_warn
    public :: s3_log_info
    public :: s3_log_debug
    public :: s3_log_trace
    public :: s3_init_logger

    ! Log level constants (public)
    integer, parameter, public :: S3_LOG_LEVEL_NONE = 0
    integer, parameter, public :: S3_LOG_LEVEL_ERROR = 1
    integer, parameter, public :: S3_LOG_LEVEL_WARN = 2
    integer, parameter, public :: S3_LOG_LEVEL_INFO = 3
    integer, parameter, public :: S3_LOG_LEVEL_DEBUG = 4
    integer, parameter, public :: S3_LOG_LEVEL_TRACE = 5

    ! Current log level (default ERROR)
    integer, save :: current_log_level = S3_LOG_LEVEL_ERROR

contains

    !> Initialize logger from environment variable.
    !>
    !> Reads S3_LOG_LEVEL environment variable and sets log level accordingly.
    !> If not set or invalid, defaults to ERROR level.
    !>
    !> Called automatically by s3_init(), but can be called manually.
    subroutine s3_init_logger()
        character(len=256) :: env_value
        integer :: status

        call get_environment_variable('S3_LOG_LEVEL', env_value, status=status)
        if (status == 0 .and. len_trim(env_value) > 0) then
            call parse_log_level(trim(env_value), current_log_level)
        end if
    end subroutine s3_init_logger

    !> Set the current log level.
    !>
    !> @param[in] level Log level (S3_LOG_LEVEL_NONE to S3_LOG_LEVEL_TRACE)
    subroutine s3_set_log_level(level)
        integer, intent(in) :: level
        if (level >= S3_LOG_LEVEL_NONE .and. level <= S3_LOG_LEVEL_TRACE) then
            current_log_level = level
        end if
    end subroutine s3_set_log_level

    !> Get the current log level.
    !>
    !> @return Current log level
    function s3_get_log_level() result(level)
        integer :: level
        level = current_log_level
    end function s3_get_log_level

    !> Log an error message.
    !>
    !> @param[in] message Error message to log
    subroutine s3_log_error(message)
        character(len=*), intent(in) :: message
        if (current_log_level >= S3_LOG_LEVEL_ERROR) then
            write(*, '(A,A)') '[S3 ERROR] ', trim(message)
        end if
    end subroutine s3_log_error

    !> Log a warning message.
    !>
    !> @param[in] message Warning message to log
    subroutine s3_log_warn(message)
        character(len=*), intent(in) :: message
        if (current_log_level >= S3_LOG_LEVEL_WARN) then
            write(*, '(A,A)') '[S3 WARN]  ', trim(message)
        end if
    end subroutine s3_log_warn

    !> Log an informational message.
    !>
    !> @param[in] message Info message to log
    subroutine s3_log_info(message)
        character(len=*), intent(in) :: message
        if (current_log_level >= S3_LOG_LEVEL_INFO) then
            write(*, '(A,A)') '[S3 INFO]  ', trim(message)
        end if
    end subroutine s3_log_info

    !> Log a debug message.
    !>
    !> @param[in] message Debug message to log
    subroutine s3_log_debug(message)
        character(len=*), intent(in) :: message
        if (current_log_level >= S3_LOG_LEVEL_DEBUG) then
            write(*, '(A,A)') '[S3 DEBUG] ', trim(message)
        end if
    end subroutine s3_log_debug

    !> Log a trace message (very detailed).
    !>
    !> @param[in] message Trace message to log
    subroutine s3_log_trace(message)
        character(len=*), intent(in) :: message
        if (current_log_level >= S3_LOG_LEVEL_TRACE) then
            write(*, '(A,A)') '[S3 TRACE] ', trim(message)
        end if
    end subroutine s3_log_trace

    !> Parse log level from string.
    !>
    !> @param[in] level_str Log level as string (NONE, ERROR, WARN, INFO, DEBUG, TRACE)
    !> @param[out] level Parsed log level constant
    subroutine parse_log_level(level_str, level)
        character(len=*), intent(in) :: level_str
        integer, intent(out) :: level
        character(len=256) :: upper_str
        integer :: i

        ! Convert to uppercase
        upper_str = level_str
        do i = 1, len_trim(upper_str)
            if (upper_str(i:i) >= 'a' .and. upper_str(i:i) <= 'z') then
                upper_str(i:i) = char(ichar(upper_str(i:i)) - 32)
            end if
        end do

        select case (trim(upper_str))
        case ('NONE', '0')
            level = S3_LOG_LEVEL_NONE
        case ('ERROR', '1')
            level = S3_LOG_LEVEL_ERROR
        case ('WARN', 'WARNING', '2')
            level = S3_LOG_LEVEL_WARN
        case ('INFO', '3')
            level = S3_LOG_LEVEL_INFO
        case ('DEBUG', '4')
            level = S3_LOG_LEVEL_DEBUG
        case ('TRACE', '5')
            level = S3_LOG_LEVEL_TRACE
        case default
            level = S3_LOG_LEVEL_ERROR  ! Default to ERROR
            write(*, '(A,A,A)') '[S3 WARN] Unknown log level "', trim(level_str), &
                '", defaulting to ERROR'
        end select
    end subroutine parse_log_level

end module s3_logger