0

I have a config file here:

log:
  filename: 'log'
  format: '%(levelname)s:%(message)s'
  level: 'logging.INFO'

Which I am trying to use in my logging configuration here:

logging.basicConfig(
    filename=str(config['log']['filename']),
    format=str(config['log']['format']),
    level=str(config['log']['level'])
)

However, I get this error presumably because I am passing in a string, but the logging level needs a path within the logging module.

ValueError: Unknown level: 'logging.INFO'

How can I convert this to a module path or is there a different approach I should use?

Garrett
  • 1,576
  • 4
  • 27
  • 51

2 Answers2

1

You can use logging.getLevelName('INFO') to convert from a string to a log level (which is an integer code). So as long as you can change your config file to:

log:
  filename: 'log'
  format: '%(levelname)s:%(message)s'
  level: 'INFO'

This should work

logging.basicConfig(
    filename=str(config['log']['filename']),
    format=str(config['log']['format']),
    level=logging.getLevelName(config['log']['level'])
)

PS Do you need the str() casts?

David Waterworth
  • 2,214
  • 1
  • 21
  • 41
0

Quick and hacky way:

You can use eval(). It executes python code in strings. (Docs)

Example:

import logging

logging.basicConfig(
    level=eval('logging.INFO')
)

logging.info('Works!')

Outputs:

INFO:root:Works!

Although this works, using eval is considered bad practice because you can execute any Python code so it's not secure i.e. can pass anything in config and it will be executed in your application. More info here.


Safer approach:

In your config file you can pass 'your' defined level keywords such as info or warning etc. (All levels)

Example config:

log:
  filename: 'log'
  format: '%(levelname)s:%(message)s'
  level: 'info'

In code, you can create a mapping between those words and actual logging level and then instantiate the logger with that.

import logging

#Create mappings
level_mapping = {'info': logging.INFO, 'warning': logging.WARNING}

#Read your config file
config = {} 

#When passed logging level doesn't exist in mappings, raise an exception
if config['log']['level'] not in level_mapping:
    raise ValueError('Invalid logging level passed in config!!!')

#Instantiate
logging.basicConfig(
    level=level_mapping[config['log']['level']]
)

This way you have a whitelist of accepted levels in your application.

Rithin Chalumuri
  • 1,739
  • 7
  • 19