Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'<' not supported between instances of 'str' and 'datetime.datetime' #159

Open
dephiros opened this issue Aug 5, 2024 · 7 comments
Open

Comments

@dephiros
Copy link

dephiros commented Aug 5, 2024

Sentry SDK: 2.12.0
structlog-sentry: 2.1.0

Run into this error when trying to upgrade sentry-sdk and structlog-sentry
'<' not supported between instances of 'str' and 'datetime.datetime'

I manage to track it down to getsentry/sentry-python#3307 which is included in sentry-sdk 2.11 release.

  • The change sorts the breadcrumb data by timestamp before sending
  • It seems like Sentry expects the timestamp to be a datetime instead of string?
  • Our structlog configuration use structlog.processors.TimeStamper(fmt="iso"),
  • This line seems to just forward the timestamp from structlog to Sentry breadcrumb which could be string. Maybe we can convert timestamp first to datetime?

Appreciate your help

@antonpirker
Copy link

Hey,

sentry-sdk maintainer here.

I tried to reproduce this with this example:

import logging
import os

import sentry_sdk
import structlog
from structlog_sentry import SentryProcessor


def main():
    sentry_sdk.init(
        dsn=os.environ.get("SENTRY_DSN"),
        traces_sample_rate=1.0,
        debug=True,
    )

    structlog.configure(
        processors=[
            structlog.processors.TimeStamper(fmt="iso"),
            structlog.stdlib.add_logger_name,  # optional, must be placed before SentryProcessor()
            structlog.stdlib.add_log_level,  # required before SentryProcessor()
            SentryProcessor(event_level=logging.ERROR),
        ],
        logger_factory=structlog.stdlib.LoggerFactory(),
        wrapper_class=structlog.stdlib.BoundLogger,
    )

    log = structlog.get_logger()

    try:
        1/0
    except ZeroDivisionError:
        log.error("zero division")


if __name__ == "__main__":
    main()

And I get a TypeError: Logger.error() missing 1 required positional argument: 'msg' so it seems I am too stupid to use structlog in the first place.

Can anyone show me what I am doing wrong?

@dbowring
Copy link

@antonpirker Try adding structlog.stdlib.ProcessorFormatter.wrap_for_formatter to the end of your processors.

@antonpirker
Copy link

@dbowring thanks for the help, that did the trick!

@antonpirker
Copy link

@dephiros

I have now this example app:
https://github.com/antonpirker/testing-sentry/tree/main/test-structlog-sentry

But I do not get the '<' not supported between instances of 'str' and 'datetime.datetime'.
Can you help me reproduce this?

@dephiros
Copy link
Author

@antonpirker , super appreciated you help create the example.

It seems like the I am able to recreate the error by just reraise the exception:

https://github.com/dephiros/testing-sentry/blob/main/test-structlog-sentry/main.py#L34

 [sentry] DEBUG: [Profiling] Setting up continuous profiler in thread mode
{'event': 'zero division', 'timestamp': '2024-08-13T11:19:07.795262Z', 'logger': '__main__', 'level': 'error'}
 [sentry] ERROR: Internal error in sentry_sdk
Traceback (most recent call last):
  File "/Users/annguyen/works/testing-sentry/test-structlog-sentry/.venv/lib/python3.11/site-packages/sentry_sdk/integrations/excepthook.py", line 66, in 
sentry_sdk_excepthook
    sentry_sdk.capture_event(event, hint=hint)
  File "/Users/annguyen/works/testing-sentry/test-structlog-sentry/.venv/lib/python3.11/site-packages/sentry_sdk/api.py", line 162, in capture_event
    return get_current_scope().capture_event(event, hint, scope=scope, **scope_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/annguyen/works/testing-sentry/test-structlog-sentry/.venv/lib/python3.11/site-packages/sentry_sdk/scope.py", line 1135, in capture_event
    event_id = self.get_client().capture_event(event=event, hint=hint, scope=scope)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/annguyen/works/testing-sentry/test-structlog-sentry/.venv/lib/python3.11/site-packages/sentry_sdk/client.py", line 743, in capture_event
    event_opt = self._prepare_event(event, hint, scope)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/annguyen/works/testing-sentry/test-structlog-sentry/.venv/lib/python3.11/site-packages/sentry_sdk/client.py", line 452, in _prepare_event
    event_ = scope.apply_to_event(event, hint, self.options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/annguyen/works/testing-sentry/test-structlog-sentry/.venv/lib/python3.11/site-packages/sentry_sdk/scope.py", line 148, in wrapper
    return fn(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/annguyen/works/testing-sentry/test-structlog-sentry/.venv/lib/python3.11/site-packages/sentry_sdk/scope.py", line 1442, in apply_to_event
    self._apply_breadcrumbs_to_event(event, hint, options)
  File "/Users/annguyen/works/testing-sentry/test-structlog-sentry/.venv/lib/python3.11/site-packages/sentry_sdk/scope.py", line 1299, in _apply_breadcrum
bs_to_event
    event["breadcrumbs"]["values"].sort(key=lambda crumb: crumb["timestamp"])
TypeError: '<' not supported between instances of 'datetime.datetime' and 'str'
Traceback (most recent call last):
  File "/Users/annguyen/works/testing-sentry/test-structlog-sentry/main.py", line 38, in <module>
    main()
  File "/Users/annguyen/works/testing-sentry/test-structlog-sentry/main.py", line 31, in main
    1/0
    ~^~
ZeroDivisionError: division by zero
 [sentry] DEBUG: atexit: got shutdown signal
 [sentry] DEBUG: atexit: shutting down client

@antonpirker
Copy link

Hey @dephiros ! Now I can reproduce! Thanks for your help!

The errors happens because one breadcrumb has a datetime and the other one a string. But I think I fix this in the SDK to always parse the timestamp if it is a string.

@Barsoomx
Copy link

Barsoomx commented Aug 19, 2024

log.error("zero division", timestamp=datetime.datetime.now())
seems like this also occurs if you do this and try to send an event? Event without TimeStamper you can manually pass different types into logger events (which turn into breadcrumbs)

import logging
import os

import sentry_sdk
import structlog
from structlog_sentry import SentryProcessor
import datetime


def main():
    sentry_sdk.init(
        dsn="http://abc@localhost/1",
        traces_sample_rate=1.0,
        debug=True,
        environment='debug'
    )

    structlog.configure(
        processors=[
            #structlog.processors.TimeStamper(fmt="iso", key='date'),
            structlog.stdlib.add_logger_name,
            structlog.stdlib.add_log_level,
            SentryProcessor(event_level=logging.ERROR),
            structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
        ],
        logger_factory=structlog.stdlib.LoggerFactory(),
        wrapper_class=structlog.stdlib.BoundLogger,
    )

    log = structlog.get_logger()

    try:
        1/0
    except ZeroDivisionError:
        log.error("zero division", timestamp=datetime.datetime.now())
        log.error("zero division", timestamp=datetime.datetime.now().isoformat())


if __name__ == "__main__":
    main()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants