Streamlit duplicates log messages when stream handler is added

When I add a stream handler to my logger object (so that I can do formatting), streamlit then outputs 2 messages (one formatted and one not)

Any ideas for where I can look to fix this?

Here’s a sample of what’s happening.

import logging
logger = logging.getLogger()
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s>>>%(message)s', "%H:%M:%S")
logger.addHandler(ch)'Start of program')

Now if I run that using python I get the following:

11:24:31-root-INFO>>>Start of program

Which is what i’d expect

But if I run it using streamlit run I get:
2021-08-24 11:24:58.198 Start of program
11:24:58-root-INFO>>>Start of program

There’s a duplicate, unformatted message.

How can I resolve this, so that there is only one (formatted) message?

(NOTE: FileHandler() objects have the expected behavior. I.e. if you add

fh = logging.FileHandler('test.log', 'w')

the output in the log file test.log is as expected. One, properly formatted message, no duplicates)

1 Like

I’m seeing the same behavior. Any progress on this?

Actually, it appears to only duplicate logs when I start the server initially. My guess is that it performs a refresh right at the start which would explain the duplication.

I wrote a create logger function that checks how many handlers are already present, and then also used session state to track if a logger had already been created. I think this is double overkill, but it worked for me!

def create_logger(name, level = 'DEBUG', file = None):
    logger = logging.getLogger(name)
    logger.propagate = False
    #if no streamhandler present, add one
    if sum([isinstance(handler, logging.StreamHandler) for handler in logger.handlers]) == 0:
        ch = logging.StreamHandler()
        ch.setFormatter(logging.Formatter('%(asctime)s.%(msecs)03d-%(name)s-%(levelname)s>>>%(message)s', "%H:%M:%S"))
    #if a file handler is requested, check for existence then add
    if file is not None:
        if sum([isinstance(handler, logging.FileHandler) for handler in logger.handlers]) == 0:
            ch = logging.FileHandler(log_dir/file, 'w')
            ch.setFormatter(logging.Formatter('%(asctime)s.%(msecs)03d-%(name)s-%(levelname)s>>>%(message)s', "%H:%M:%S"))
    return logger

if 'logger' not in st.session_state:
    st.session_state['logger'] = create_logger(name = 'app', level = 'DEBUG', file = 'app.log')
logger = st.session_state['logger']
1 Like