# Upgrade Guide

## Upgrading to 9.0+

### Minimum requirements

- requires python 3.9+

- django 4.2 and 5.0+ are supported

### Type hints

`django-structlog` now uses python type hints and is being validated with mypy `--strict`.

### For `drf-standardized-errors` users

Now unhandled exceptions when using drf-standardized-errors will be intercepted and the exception logged properly.

If you also use structlog-sentry, the exception will now be propagated as expected.

Other libraries alike may be affected by this change.

### Internal changes in how `RequestMiddleware` handles exceptions

This only affects you if you implemented a middleware inheriting from `RequestMiddleware` and you overrided the `process_exception` method.

Did you?

If so:

> - `RequestMiddleware.process_exception` was renamed to `RequestMiddleware._process_exception`, you should to the same in the middleware.

## Upgrading to 8.0+

A new keyword argument `log_kwargs` was added to the the optional signals:

  - `django_structlog.signals.bind_extra_request_metadata`;

  - `django_structlog.signals.bind_extra_request_finished_metadata`;

  - `django_structlog.signals.bind_extra_request_failed_metadata`.

It should not affect you if you have a `**kwargs` in the signature of your receivers.

`log_kwargs` is a dictionary containing the log metadata that will be added to their respective logs (`"request_started"`, `"request_finished"`, `"request_failed"`).

If you use any of these signals, you may need to update your receiver to accept this new argument:

    from django.contrib.sites.shortcuts import get_current_site
    from django.dispatch import receiver
    from django_structlog import signals
    import structlog

    @receiver(signals.bind_extra_request_metadata)
    def my_receiver(request, logger, log_kwargs, **kwargs): # <- add `log_kwargs` if necessary
        ...

    @receiver(signals.bind_extra_request_finished_metadata)
    def my_receiver_finished(request, logger, response, log_kwargs, **kwargs): # <- add `log_kwargs` if necessary
        ...

    @receiver(signals.bind_extra_request_failed_metadata)
    def my_receiver_failed(request, logger, exception, log_kwargs, **kwargs): # <- add `log_kwargs` if necessary
        ...

## Upgrading to 7.0+

The dependency django-ipware was upgraded to version 6. This library is used to retrieve the request’s ip address.

Version 6 may have some breaking changes if you did customizations.

It should not affect most of the users but if you did some customizations, you might need to update your configurations.

## Upgrading to 6.0+

### Minimum requirements

- requires python 3.8+

### Changes to do

#### Add `django_structlog` to installed app

    INSTALLED_APP = [
        # ...
        "django_structlog",
        # ...
    ]

#### Make sure you use `django_structlog.middlewares.RequestMiddleware`

If you used any of the experimental async or sync middlewares, you do not need to anymore. Make sure you use `django_structlog.middlewares.RequestMiddleware` instead of any of the other request middlewares commented below:

    MIDDLEWARE += [
        # "django_structlog.middlewares.request_middleware_router", # <- remove
        # "django_structlog.middlewares.requests.SyncRequestMiddleware", # <- remove
        # "django_structlog.middlewares.requests.AsyncRequestMiddleware", # <- remove
        "django_structlog.middlewares.RequestMiddleware", # <- make sure you use this one
    ]

#### (If you use celery) Make sure you use `DJANGO_STRUCTLOG_CELERY_ENABLED = True`

It is only applicable if you use celery integration.

`django_structlog.middlewares.CeleryMiddleware` has been remove in favor of a django settings.

    MIDDLEWARE += [
        "django_structlog.middlewares.RequestMiddleware",
        # "django_structlog.middlewares.CeleryMiddleware",  # <- remove this
    ]

    DJANGO_STRUCTLOG_CELERY_ENABLED = True # <-- add this

## Upgrading to 5.0+

### Minimum requirements

- requires asgiref 3.6+

## Upgrading to 4.0+

`django-structlog` drops support of django below 3.2.

### Minimum requirements

- requires django 3.2+

- requires python 3.7+

- requires structlog 21.4.0+

- (optionally) requires celery 5.1+

### Changes if you use `celery`

You can now install `django-structlog` explicitly with `celery` extra in order to validate the compatibility with your version of `celery`.

    django-structlog[celery]==4.0.0

See Installing “Extras” for more information about this `pip` feature.

## Upgrading to 3.0+

`django-structlog` now use structlog.contextvars.bind_contextvars instead of `threadlocal`.

### Minimum requirements

- requires python 3.7+

- requires structlog 21.4.0+

### Changes you need to do

#### 1. Update structlog settings

- add `structlog.contextvars.merge_contextvars` as first `processors`

- remove `context_class=structlog.threadlocal.wrap_dict(dict),`

- (if you use standard loggers) add `structlog.contextvars.merge_contextvars` in foreign_pre_chain

- (if you use standard loggers) remove `django_structlog.processors.inject_context_dict,`

    structlog.configure(
        processors=[
            structlog.contextvars.merge_contextvars, # <---- add this
            structlog.stdlib.filter_by_level,
            structlog.processors.TimeStamper(fmt="iso"),
            structlog.stdlib.add_logger_name,
            structlog.stdlib.add_log_level,
            structlog.stdlib.PositionalArgumentsFormatter(),
            structlog.processors.StackInfoRenderer(),
            structlog.processors.format_exc_info,
            structlog.processors.UnicodeDecoder(),
            structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
        ],
        # context_class=structlog.threadlocal.wrap_dict(dict), # <---- remove this
        logger_factory=structlog.stdlib.LoggerFactory(),
        cache_logger_on_first_use=True,
    )

    # If you use standard logging
    LOGGING = {
        "version": 1,
        "disable_existing_loggers": False,
        "formatters": {
            "json_formatter": {
                "()": structlog.stdlib.ProcessorFormatter,
                "processor": structlog.processors.JSONRenderer(),
                "foreign_pre_chain": [
                    structlog.contextvars.merge_contextvars, # <---- add this
                    # django_structlog.processors.inject_context_dict, # <---- remove this
                    structlog.processors.TimeStamper(fmt="iso"),
                    structlog.stdlib.add_logger_name,
                    structlog.stdlib.add_log_level,
                    structlog.stdlib.PositionalArgumentsFormatter(),
                ],
            },
        },
        ...
     }

#### 2. Replace all `logger.bind` with `structlog.contextvars.bind_contextvars`

    @receiver(bind_extra_request_metadata)
    def bind_domain(request, logger, **kwargs):
        current_site = get_current_site(request)
        # logger.bind(domain=current_site.domain)
        structlog.contextvars.bind_contextvars(domain=current_site.domain)

## Upgrading to 2.0+

`django-structlog` was originally developed using the debug configuration ExceptionPrettyPrinter which led to incorrect handling of exception.

- remove `structlog.processors.ExceptionPrettyPrinter(),` of your processors.

- make sure you have `structlog.processors.format_exc_info,` in your processors if you want appropriate exception logging.