feat: Added flushes/close functionality to logging handlers#917
feat: Added flushes/close functionality to logging handlers#917gkevinzheng merged 11 commits intomainfrom
Conversation
| if self.transport is None: | ||
| self.transport = self._transport_cls( | ||
| self.client, self.name, resource=self.resource | ||
| ) |
There was a problem hiding this comment.
Wouldn't this mean the handler has been closed? Why not just raise an error, instead of re-creating the transport?
There was a problem hiding this comment.
I based this off of some logging handlers I saw in the Python standard library, which will reopen a closed connection if that connection is closed.
There was a problem hiding this comment.
Personally I think this adds extra complexity, so I'd prefer to keep them permanently closed if we can get away with that
But if you think this behavior would help us integrate with the standard library, it makes sense to keep it.
| def close(self): | ||
| """Closes the log handler and cleans up all Transport objects used.""" | ||
| self.transport.close() | ||
| self.transport = None |
There was a problem hiding this comment.
I don't like the idea of using transport == None as a way to check if the handler is closed. That makes the types quite a bit more complicated.
Can't we use a new flag for this?
| _CLOSE_THREAD_SHUTDOWN_ERROR_MSG = ( | ||
| "CloudLoggingHandler shutting down, cannot send logs entries to Cloud Logging due to " | ||
| "inconsistent threading behavior at shutdown. To avoid this issue, flush the logging handler " | ||
| "manually or switch to StructuredLogHandler." |
There was a problem hiding this comment.
Maybe mention client.close or handler.close too?
|
|
||
| # Print different messages to the user depending on whether or not the | ||
| # program is shutting down. This is because this function now handles both | ||
| # the atexit handler and the regular close. |
There was a problem hiding this comment.
Can we decouple this? Maybe let the caller pass in a message or something?
|
I am not fully sure this will solve googleapis/google-cloud-python#15408 and #855. I see 2 possible scenarios:
Have you considered flushing the queue at termination? Something like the following (conceptually):
I wonder if the atexit hook should remain. I believe the main thread will be in a state where is_alive may return true, but underneath it would still error out because it can’t create new threads (this is a guess). What do you think about letting users explicitly calling the teardown/close? |
db3be06 to
b46779e
Compare
No region tags are edited in this PR.This comment is generated by snippet-bot.
|
Part of this PR is also adding functionality to explicitly let users call teardown/close for clients. Flushing the queue at termination is not an option because in order to send log entries over the wire to Cloud Logging, gRPC threads are needed, which we cannot create new ones at shutdown, causing the two bugs. |
| self.client = client | ||
| client._handlers.add(self) | ||
| self.transport = transport(client, name, resource=resource) | ||
| self.transport_open = True |
There was a problem hiding this comment.
Can this be made private?
…pened There was a recent release (3.12.0) that included the changes introduced in googleapis#917. The newly introduced close method seems to be called by AppEngine Python runtime at shutdown, so if you would call it explicitly before the runtime does it, then the close function throws an exception because transport is None.
…pened (#990) There was a recent release (3.12.0) that included the changes introduced in #917. The newly introduced close method seems to be called by AppEngine Python runtime at shutdown, so if you would call it explicitly before the runtime does it, then the close function throws an exception because transport is None.
For design doc see go/python-logging-background-thread
Fixes #<issue_number_goes_here> 🦕