1313# limitations under the License.
1414
1515import logging
16+ from datetime import datetime
17+ from typing import Optional
1618
1719from opentelemetry .instrumentation .logging import LoggingInstrumentor
1820from pythonjsonlogger import jsonlogger
1921
2022
23+ # We override JsonFormatter.formatTime() instead of using the datefmt strftime parameter
24+ # because it does not support microsecond precision.
25+
26+
2127# [START opentelemetry_instrumentation_setup_logging]
28+ class JsonFormatter (jsonlogger .JsonFormatter ):
29+ def formatTime (self , record : logging .LogRecord , datefmt : Optional [str ] = None ):
30+ # Format the timestamp as RFC 3339 with microsecond precision
31+ isoformat = datetime .fromtimestamp (record .created ).isoformat ()
32+ return f"{ isoformat } Z"
33+
34+
2235def setup_structured_logging () -> None :
2336 LoggingInstrumentor ().instrument ()
2437
2538 log_handler = logging .StreamHandler ()
26- formatter = jsonlogger . JsonFormatter (
39+ formatter = JsonFormatter (
2740 "%(asctime)s %(levelname)s %(message)s %(otelTraceID)s %(otelSpanID)s %(otelTraceSampled)s" ,
2841 rename_fields = {
2942 "levelname" : "severity" ,
@@ -32,7 +45,6 @@ def setup_structured_logging() -> None:
3245 "otelSpanID" : "logging.googleapis.com/spanId" ,
3346 "otelTraceSampled" : "logging.googleapis.com/trace_sampled" ,
3447 },
35- datefmt = "%Y-%m-%dT%H:%M:%SZ" ,
3648 )
3749 log_handler .setFormatter (formatter )
3850 logging .basicConfig (
0 commit comments