You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Aug 13, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Aug 13, 2026. It is now read-only.
Logging: support sending structured logs to stackdriver via stdlib 'logging'. #13
I want to send structured logs to stackdriver from Python using the standard logging module. You can integrate structured logging to the Python logging module with either https://github.com/madzak/python-json-logger or http://www.structlog.org/en/stable/. Would be great to preserve those structures as part of jsonPayload when sent to stackdriver. Currently, these get stringified and sent as jsonPayload.message instead.
Reacted by Malcolm White, Connor Macdougall, N. Troy de Freitas , Lynn Root, helixlabs-ai, Andrew Rumble, Parth Mishra, Aemil Estvold, John Carter, Sacha and 25 more
changed the title [-]Logging: Can't send structured logs to stackdriver with Python Logger Module[/-][+]Logging: support ending structured logs to stackdriver via stdlib 'logging'.[/+]on Dec 7, 2018
What is the status of this request? I know the root issue is that the formatter must know the attributes of the extra arguments passed into the stdlib logger, but is it too much of hassle to the point of being won't fix? My hesitation with the log_struct() method is the synchronous nature of it, perhaps an asynchronous transport mechanism for it could be a useful workaround?
I wanted to do something similar in order to have errors show up in Stackdriver Error Reporting, which is possible according to this issue I opened. I ended up doing it like this, but I think it would be neater if you could subclass _Worker and inject it into CloudLoggingHandler alongside the transport. Anyway, this works:
changed the title [-]Logging: support ending structured logs to stackdriver via stdlib 'logging'.[/-][+]Logging: support sending structured logs to stackdriver via stdlib 'logging'.[/+]on Jun 19, 2019
thanks @crazystick, that almost worked for me... but I'm seeing logs from the background thread itself in my logs (ie. "submitted 1 logs" etc.) Is there any way to exclude that logger? google.cloud.logging.handlers.transports.background_thread
There is a setup_logging function which you're supposed to use which excludes some internal logging. That function messes around with the root logger, so I do it manually like this. I find that adding the NullHandler is necessary or you end up with an extra StreamHandler which you might not want.
EXCLUDED_LOGGER_DEFAULTS= ("google.cloud", "google.auth", "google_auth_httplib2")
# don't propagate excluded loggers (and don't send them to stderr either)forlogger_nameinEXCLUDED_LOGGER_DEFAULTS:
logging.getLogger(logger_name).propagate=Falselogging.getLogger(logger_name).addHandler(logging.NullHandler())
# add cloud handler to root loggerlogging.getLogger().addHandler(cloud_handler)
Based on @crazystick 's answer, I use the following bodge to log custom objects as info payload. It derives more from the original _Worker.enqueue and supports passing custom fields.
I tried to implement @Voyz solution on a Cloud Function and I couldn't make it work.
I think there is a strange behaviour with CF and monkey patching the module.
Doesn't care how you use structlog, no particular naming constraints on extended attributes
Results in structured + searchable JSON in stackdriver
Preconfigured and works out of the box on GCP Debian 10 images with google-fluentd installed as per GCP instructions.
Its used like so:
importgoogle_structloggoogle_structlog.setup(log_name="here-is-mylilapp")
# Now you can use structlog to get searchable json details in stackdriver...importstructloglogger=structlog.get_logger()
logger.error("Uhoh, something bad did", moreinfo="it was bad", years_back_luck=5)
# Of course, you can still use plain ol' logging stdlib to get { "message": ... } objectsimportlogginglogger=logging.getLogger("yoyo")
logger.error("Regular logging calls will work happily too")
# Now you can search stackdriver with the query:# logName: 'here-is-mylilapp'
Which will produce a nice structured / searchable log inside GCP stackdriver:
Main difference with what @Voyz had posted is its somewhat structlog specific, and doesn't care what sort of extra values you pass. It also includes all the pre-canned bells and whistles to run out of the box, and shows you what to search for in GCP so you can work backwards to something that works for you but is working by default.
If there's interest, I can polish it a little further and put something up on pypi.
Reacted by Sam Wilson, Varun Malyala, Bradley Lewis, Guillaume Lachaud, Stephen Batifol, Cam Sweeney, Aaron, eyalpeleg1101, Yuan Gao, Dave Budd and 5 more
Reacted by voyz, Cam Sweeney, Aaron, eyalpeleg1101, Dave Budd, Joe Ravesloot, David Asaf and Eugenio Contreras
Seems like this would be something obvious and cough idiomatic to be included in this library. Stack Driver doesn't looks so hot next to Sentry without this capability out of the box.
Reacted by Seth Nickell, Nimish Telang, Bogdan Ribitskiy and Rushil Srivastava
Yeah, its a little frustrating to have "structured logging" with no simple ability to get in on it and inject your own domain-specific fields. That's where structured starts paying for its "not as easy to scan" downsides. The system provided structure fields are sort of 🤷♂️ compared to domain specific info that's super easy to create in code, and frustratingly hard to get into the log analysis tools in GCP.
Reacted by Cam Sweeney, Nimish Telang, Jon Cotton, Pietro De Nicolao and Rushil Srivastava
I'm not using cloud functions, so it'd be really cool if somebody who was could figure out how to make it work "least surprise" in that context too. I'm mostly using python apps running on GKE, for which this works reasonably well for me.
Hopefully somebody at Google will take this off our hands, but until then I think starting with a repo and refining it with issues etc is probably warranted at this level of complexity.
I took a look. It seems like most things the default stdout logger sends can be provided except for trace id. So it's not a huge deal -- the nodejs lib for gcp logging does it -- but it's not complete.
importgoogle.cloud.logging# Instantiates a clientclient=google.cloud.logging.Client()
# Connects the logger to the root logging handler; by default this captures# all logs at INFO level and higherclient.setup_logging()
logger=logging.getLogger(__name__)
logger.info("Google setup 4")
Hi, I recently came across the issue with structured logging for Google Cloud.
My initial idea was to use structlog with two different renderers: One for console (local development) and one for AppEngine (prod) - inspired by https://github.com/kiwicom/kiwi-structlog-config.
However when I ran it in app engine standard, nothing showed up in logs... 🤨
Note: Logs written to stdout and stderr are automatically sent to Cloud Logging for you, without needing to use Cloud Logging library for Python.
I used this example for writing structured logs, but nothing shows in the Cloud Logging Explorer.
Did something change and the docs are no longer up-to-date? Any idea what could I be doing wrong?
Is the stdout logging no longer supported and that's why you are using google.cloud.logging library?
I tried to implement @Voyz solution on a Cloud Function and I couldn't make it work. I think there is a strange behaviour with CF and monkey patching the module.
I would expect some error if logging.info("hello") does not have the error_fields keys. Is there any update if this will be implemented?
No errors :(
This question here is not for a cloud function, there, you have to use google.cloud.logging instead of the stdlib Python logging.
This question here is just about getting it to work in a local Python script, using the GOOGLE_APPLICATION_CREDENTIALS to connect to GCP and drop the logs there.
Activity
[-]Logging: Can't send structured logs to stackdriver with Python Logger Module[/-][+]Logging: support ending structured logs to stackdriver via stdlib 'logging'.[/+]parthmishra commentedon Jun 8, 2019
What is the status of this request? I know the root issue is that the formatter must know the attributes of the extra arguments passed into the stdlib logger, but is it too much of hassle to the point of being won't fix? My hesitation with the
log_struct()method is the synchronous nature of it, perhaps an asynchronous transport mechanism for it could be a useful workaround?tseaver commentedon Jun 11, 2019
@parthmishra The request as it stands (extract the "extra" fields from stdlib's
LogRecordand convert them tolog_struct) is unlikely to be implemented in this library. This comment on issue googleapis/google-cloud-python#6488 suggests one possibility for working around it.To deal just with the synchronous bit, you could interact directly with the "background thread handler" transport. Its main worker method just polls the queue for lists of dicts to be pushed to the API: https://github.com/googleapis/google-cloud-python/blob/a14ffbaa50f7823c2792e91413a37cbc3ce687f5/logging/google/cloud/logging/handlers/transports/background_thread.py#L134-L152
crazystick commentedon Jun 14, 2019
I wanted to do something similar in order to have errors show up in Stackdriver Error Reporting, which is possible according to this issue I opened. I ended up doing it like this, but I think it would be neater if you could subclass
_Workerand inject it intoCloudLoggingHandleralongside the transport. Anyway, this works:[-]Logging: support ending structured logs to stackdriver via stdlib 'logging'.[/-][+]Logging: support sending structured logs to stackdriver via stdlib 'logging'.[/+]skunkwerk commentedon Oct 7, 2019
thanks @crazystick, that almost worked for me... but I'm seeing logs from the background thread itself in my logs (ie. "submitted 1 logs" etc.) Is there any way to exclude that logger? google.cloud.logging.handlers.transports.background_thread
crazystick commentedon Oct 8, 2019
There is a
setup_loggingfunction which you're supposed to use which excludes some internal logging. That function messes around with the root logger, so I do it manually like this. I find that adding the NullHandler is necessary or you end up with an extra StreamHandler which you might not want.Voyz commentedon Feb 6, 2020
Based on @crazystick 's answer, I use the following bodge to log custom objects as info payload. It derives more from the original
_Worker.enqueueand supports passing custom fields.Then
Resulting in:

Which then makes it much easier to filter according to these custom_fields.
Naturally, it would be great if this would be naively supported - thanks in advance!
a-mpch commentedon Apr 16, 2020
I tried to implement @Voyz solution on a Cloud Function and I couldn't make it work.
I think there is a strange behaviour with CF and monkey patching the module.
And the function...
I would expect some error if
logging.info("hello")does not have theerror_fieldskeys.Is there any update if this will be implemented?
No errors :(
snickell commentedon May 21, 2020
EDIT TO UPDATE, I've moved the gist into a repo and uploaded it to pypi:
https://github.com/snickell/google_structlog
ORIGINAL for historical purposes:
I've extended @Voyz / @crazystick 's work, and built a pre-canned gist
google_structlog:https://gist.github.com/snickell/3b664c668b8a94d1ca6e31b0498a8697
structlog(https://www.structlog.org/en/stable/)Its used like so:
Which will produce a nice structured / searchable log inside GCP stackdriver:

Main difference with what @Voyz had posted is its somewhat structlog specific, and doesn't care what sort of extra values you pass. It also includes all the pre-canned bells and whistles to run out of the box, and shows you what to search for in GCP so you can work backwards to something that works for you but is working by default.
If there's interest, I can polish it a little further and put something up on pypi.
numbsafari commentedon May 21, 2020
Seems like this would be something obvious and cough idiomatic to be included in this library. Stack Driver doesn't looks so hot next to Sentry without this capability out of the box.
snickell commentedon May 21, 2020
Yeah, its a little frustrating to have "structured logging" with no simple ability to get in on it and inject your own domain-specific fields. That's where structured starts paying for its "not as easy to scan" downsides. The system provided structure fields are sort of 🤷♂️ compared to domain specific info that's super easy to create in code, and frustratingly hard to get into the log analysis tools in GCP.
5 remaining items
nimish commentedon Jun 19, 2020
I took a look. It seems like most things the default stdout logger sends can be provided except for trace id. So it's not a huge deal -- the nodejs lib for gcp logging does it -- but it's not complete.
caiolopes commentedon Nov 6, 2020
@snickell your solution is not working for me on Google App Engine, runtime
python37... Do you have any thoughts on why?I really enjoy
structloglib and was hoping I could use your proposed setup!Some tests I made:
Doing the proposed setup in here https://cloud.google.com/logging/docs/setup/python works, but not for structured data of course
HynekBlahaDev commentedon Dec 4, 2020
Hi, I recently came across the issue with structured logging for Google Cloud.
My initial idea was to use structlog with two different renderers: One for console (local development) and one for AppEngine (prod) - inspired by https://github.com/kiwicom/kiwi-structlog-config.
However when I ran it in app engine standard, nothing showed up in logs... 🤨
The official documentation says that everything logged to stdout will be send to Cloud Logging.
I used this example for writing structured logs, but nothing shows in the Cloud Logging Explorer.
Did something change and the docs are no longer up-to-date? Any idea what could I be doing wrong?
Is the stdout logging no longer supported and that's why you are using google.cloud.logging library?
Thanks a lot!
meseta commentedon Feb 4, 2021
are we getting structured logging!? woohoo!
lorenzznerol commentedon Feb 28, 2022
This question here is not for a cloud function, there, you have to use google.cloud.logging instead of the stdlib Python logging.
This question here is just about getting it to work in a local Python script, using the GOOGLE_APPLICATION_CREDENTIALS to connect to GCP and drop the logs there.