60

I'm trying to create a basic logger that will be colored without external packages,

# these have to be the first functions so I can use it in the logger settings
def create_log_name(log_path="{}/log", filename="zeus-log-{}.log"):
    if not os.path.exists(log_path.format(os.getcwd())):
        os.mkdir(log_path.format(os.getcwd()))
    find_file_amount = len(os.listdir(log_path.format(os.getcwd())))
    full_log_path = "{}/{}".format(log_path.format(os.getcwd()), filename.format(find_file_amount + 1))
    return full_log_path


def set_color_value(levelname):
    log_set = {
        "INFO": "\033[92m{}\033[0m",
        "WARNING": "\033[93m{}\033[0m",
        "DEBUG": "\033[94m{}\033[0m",
        "ERROR": "\033[91m{}\033[0m",
        "CRITICAL": "\033[91m{}\033[0m"
    }
    return log_set[levelname].format(levelname)

logger = logging.getLogger("zeus-log")
logger.setLevel(logging.DEBUG)
file_handler = logging.FileHandler(
    filename=create_log_name(), mode="a+"
)
file_handler.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
file_format = logging.Formatter(
    '%(asctime)s;%(name)s;%(levelname)s;%(message)s'
)
console_format = logging.Formatter(
    "[%(asctime)s {}] %(message)s".format(set_color_value()), "%H:%M:%S"
)
file_handler.setFormatter(file_format)
console_handler.setFormatter(console_format)
logger.addHandler(console_handler)
logger.addHandler(file_handler)

So as of right now, all I need to do is get the current log level that will be set in the logging.Formatter and send it to my little function:

console_format = logging.Formatter(
    "[%(asctime)s {}] %(message)s".format(set_color_value()), "%H:%M:%S"
)

Is it possible to get the current log level from the logging package?


For example, lets say I pass logger.INFO("test") I need a way to get that INFO part in as a string, from there, set_color_value("INFO") should return:

enter image description here

1
  • Have you found a solution ? I also need to get the levelname for each incoming message in the log. Commented Dec 28, 2024 at 16:17

5 Answers 5

61

If you're using the root logger, for example because you called logging.basicConfig() then you can use

import logging
logging.root.level

For example

if logging.DEBUG >= logging.root.level:
    # Do something
Sign up to request clarification or add additional context in comments.

1 Comment

It is better to use the isEnabledFor() function instead of an explicit comparision. See here: docs.python.org/3/howto/logging.html#optimization
37

Yes, you can check the logger level by

level = logger.level

6 Comments

Doesn't this just show the level that the current logger is set to? I need a way to get the logging information from each string passed from the logger, for example, lets say that I pass logger.FATAL("test") I need that FATAL part passed as a string
This answer answers what the question asked. Your question needs improvement since I arrived here looking for this answer.
Agreed. The content of your question is at odds with the title of your question, @wahwahwah. The latter is likely of more interest to StackOverflowers (including myself). It is oddly non-orthogonal that the logging API defines setLevel() and getEffectiveLevel() methods but no getLevel() method, when they could have simply defined a trivial getLevel(self): return self.level method. </sigh>
Whether I set this to INFO or DEBUG e.g. like this logging.basicConfig(stream=sys.stdout, level='DEBUG') the logger.level always shows me 0, not helpful. @CecilCurry What does "oddly non-orthogonal" mean? In the context of this definition of orthogonality I am not sure
@CecilCurry Seconding your opinion. The documentation page of logging doesn't mention level could be directly accessed through the logger object. It only mentions getEffectiveLevel as the way to get the current log level. Nothing else could be found to achieve the same purpose.
|
32
+50

As explained in this walk through the source code logger.level is often wrong.

You want logger.getEffectiveLevel()

To quote the source:

Here’s the takeaway: don’t rely on .level. If you haven’t explicitly set a level on your logger object, and you’re depending on .level for some reason, then your logging setup will likely behave differently than you expected it to.

Comments

12

In your logger instance you can check it like this, as @Milán Vásárhelyi said:

myLogger.level

That will return the level as int. if you prefer to show the name, as string, you can do:

logging.getLevelName(myLogger.level)

Comments

8

I decided to do this a different way and add color through the string itself with a level number:

def set_color(org_string, level=None):
    color_levels = {
        10: "\033[36m{}\033[0m",       # DEBUG
        20: "\033[32m{}\033[0m",       # INFO
        30: "\033[33m{}\033[0m",       # WARNING
        40: "\033[31m{}\033[0m",       # ERROR
        50: "\033[7;31;31m{}\033[0m"   # FATAL/CRITICAL/EXCEPTION
    }
    if level is None:
        return color_levels[20].format(org_string)
    else:
        return color_levels[int(level)].format(org_string)

So for example:

logger.info(set_color("test"))
logger.debug(set_color("test", level=10))
logger.warning(set_color("test", level=30))
logger.error(set_color("test", level=40))
logger.fatal(set_color("test", level=50))

Will output:

enter image description here

1 Comment

You can also replace the default logging.Formatter with ColorFormatter subclass that has format method ``` COLOR_MAP = { DEBUG : 'white', <...> ERROR : 'red', } def format(self, record): msg = logging.Formatter.format(self, record) # Now set color based on our level, if mapped. Else leave as is if record.levelno in ColorFormatter.COLOR_MAP: msg = termcolor.colored(msg, ColorFormatter.COLOR_MAP[record.levelno]) return msg ```

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.