Loguru: Use pm2 with loguru

Created on 27 Oct 2020  路  6Comments  路  Source: Delgan/loguru

Hello!

I have been very appreciated to use loguru where a friend of mine has showed me and its been what I have been looking for in ages!

I have some issues with it and I wouldn't say its a bug or so, maybe a new feature or something I might have missed?

What I have done is super simple script such as:

from loguru import logger
logger.info("hello world")

and I tried to run it with something called PM2 which looks like this:

image

The only issue is that it marks it as a "error" with the red line which shouldn't. How is when I change it to a normal print:

print("hello world")

image

So my question is simple as, is it possible to do something similar where logger.info would mark it as a "green" success color in the pm2 while exception/debug could be red?

As I mentioned, its probably maybe not an issue but maybe a cool feature for those who uses pm2 and if there is anything I can help you out, please let me know! :)

Most helpful comment

Thanks for the write-up!

Usually I would configure the logger inside an if __name__ == "__main__" block in case the app is used as a library. However, as you call .remove() before .add(), even if the module happens to be re-imported for some reason, it should not be noticeable.

Glad you found a solution. I wish a good day to both of you too. :+1:

All 6 comments

Hello!

The only difference between logger.info() and print() is that the former writes on sys.stderr while the later writes on sys.stdout. I guess this explains why you're seeing different colors.

It's possible to configure the logger so that it writes to stdout, simply remove the default handler first:

logger.remove()
logger.add(sys.stdout)

However in such case, errors and debug will be colored in green too. So there are two solutions. You can either use a custom sink that will choose where to write the output depending on the log level:

def pm2_sink(message):
    if message.record["level"].name == "INFO":
        sys.stdout.write(message)
    else:
        sys.stderr.write(message)

logger.remove()
logger.add(pm2_sink)

Or you can use two sinks with a filter:

logger.remove()
logger.add(sys.stdout, filter=lambda record: record["level"].name == "INFO")
logger.add(sys.stderr, filter=lambda record: record["level"].name != "INFO")

Hello!

The only difference between logger.info() and print() is that the former writes on sys.stderr while the later writes on sys.stdout. I guess this explains why you're seeing different colors.

It's possible to configure the logger so that it writes to stdout, simply remove the default handler first:

logger.remove()
logger.add(sys.stdout)

However in such case, errors and debug will be colored in green too. So there are two solutions. You can either use a custom sink that will choose where to write the output depending on the log level:

def pm2_sink(message):
    if message.record["level"].name == "INFO":
        sys.stdout.write(message)
    else:
        sys.stderr.write(message)

logger.remove()
logger.add(pm2_sink)

Or you can use two sinks with a filter:

logger.remove()
logger.add(sys.stdout, filter=lambda record: record["level"].name == "INFO")
logger.add(sys.stderr, filter=lambda record: record["level"].name != "INFO")

Hello! Appreciate the answer which I did a quick test and it seems to work! In that case it would be better to wrap it to a wrapper if I am going to use it in multiple scripts at the same time.

However my knowledge is not good enough to know how to wrap the logger to a wrapper :'( But however the solution you gave me seem to work. I just need to figure out myself how to fix the wrapper

How do you imagine such a wrapper?

If you want to repetitively use such configuration, you can indeed export it to another file. Then, if you import the file it will automatically configure the logger right?

Also, note that you can use the logger across multiple modules without needing to re-configure it (because it's always the same logger object).

How do you imagine such a wrapper?

If you want to repetitively use such configuration, you can indeed export it to another file. Then, if you import the file it will automatically configure the logger right?

Also, note that you can use the logger across multiple modules without needing to re-configure it (because it's always the same logger object).

Yupp I just realized that about the multiple modules. It worked very well and it was not much that needed to be configured with was really nice! Appreciate the help! Have a wonderful day!

Was giving advise to @BarryThrill in a side channel, this is what we came up with:

shunt the pm2 sink & logger configuration to a module, that executes the necessary loguru configuration calls on import.
this has two major effects:

  • this code only ever executes once unless dynamic module reloading hackery is employed
  • this code can be re-used by multiple executables under the same project, without special effort.

Specifically we shunted it to the package's top-level __init__.py, so it executes on startup as a natural result of executing anything under the package via -m.

This does have the unfortunate side effect of working too well, im not sure we can do an entry-point check on __init__.py to prevent the logger reconfiguration if the project is imported by something else; though in this application thats not important (as its not a library).

Thanks for the write-up!

Usually I would configure the logger inside an if __name__ == "__main__" block in case the app is used as a library. However, as you call .remove() before .add(), even if the module happens to be re-imported for some reason, it should not be noticeable.

Glad you found a solution. I wish a good day to both of you too. :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

af6140 picture af6140  路  5Comments

sergree picture sergree  路  3Comments

rightx2 picture rightx2  路  3Comments

flybaozi picture flybaozi  路  4Comments

zhouxiaomao picture zhouxiaomao  路  6Comments