async-worker / aiologger

Asynchronous logging for Python and asyncio
https://async-worker.github.io/aiologger/
MIT License
129 stars 13 forks source link

aiologger closes sys.stdout #4

Open mbrancato opened 2 years ago

mbrancato commented 2 years ago

Why does aiologger close sys.stdout or any handler it doesn't open()?

import asyncio
import aiologger

async def testaiolog():
    logger = aiologger.Logger.with_default_handlers(name="my-logger")
    await logger.info("foo")

print("works")
asyncio.run(testaiolog())
print("doesn't work")

results in:

Traceback (most recent call last):
  File "/Users/mike/Documents/.../aiologgertest.py", line 12, in <module>
    print("doesn't work")
ValueError: I/O operation on closed file.
works
foo
louis030195 commented 2 years ago

Why does aiologger close sys.stdout or any handler it doesn't open()?

import asyncio
import aiologger

async def testaiolog():
    logger = aiologger.Logger.with_default_handlers(name="my-logger")
    await logger.info("foo")

print("works")
asyncio.run(testaiolog())
print("doesn't work")

results in:

Traceback (most recent call last):
  File "/Users/mike/Documents/.../aiologgertest.py", line 12, in <module>
    print("doesn't work")
ValueError: I/O operation on closed file.
works
foo

Any chance you found a solution?

nikita-krokosh commented 2 years ago

Any updates on this issue?

adalundhe commented 1 year ago

Hello there! I think I've got a semi-reasonable workaround for anyone that's curious. Rather than directly passing sys.stdout or sys.stderr, we create a dup of either and pass that. Example below:

import os
import sys
from aiologger.handlers.streams import AsyncStreamHandler

AsyncStreamHandler(
    stream=os.fdopen(
        os.dup(sys.__stdout__.fileno())
))

Full credit to this StackOverflow answer for the idea: https://stackoverflow.com/a/40845164. Hope this helps!

Quick Edit: This workaround assumes you won't be attempting to re-use the same instance of the Hander/Logger later. I'd recommend creating a logger factory if you plan on passing the same logger between different calls to asyncio.run()/etc.