# Better Stack Python logging


## Start logging in 3 steps

Where do you want to collect your logs from?

- [Django application](#logging-from-django)
- [Python code](#logging-from-python)
- [RQ workers](#logging-from-rq-workers)
- [AWS Lambda](https://betterstack.com/docs/logs/aws-lambda/#logging-in-aws-lambda-running-python)

## Logging from Django

Collect logs from your Django application.

### 1. Install

Install Better Stack Python PyPI package:

```bash
[label Install logtail-python]
pip3 install logtail-python
```

### 2. Setup

Set up Django Better Stack handler in `settings.py`:

```python
[label Set up Better Stack handler]
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    'handlers': {
        'logtail': {
            'class': 'logtail.LogtailHandler',
            'source_token': '$SOURCE_TOKEN',
            'host': 'https://$INGESTING_HOST',
        },
    },
    "loggers": {
        "": {
            "handlers": [
                "logtail",
            ],
            "level": "INFO",
        },
    },
}
```

### 3. Start logging

Use Python logger as usual:

```python
[label Send logs to Better Stack]
import logging
logger = logging.getLogger(__name__)
logger.error('Something bad happened.')
logger.info('Log message with structured logging.', extra={
    'item': "Orange Soda",
    'price': 100.00
})
```

You should see your logs in [Better Stack → Live tail](https://telemetry.betterstack.com/team/0/tail ";_blank").

[warning]
#### Python 3.10 or higher is required
Pip version 20.0.2 or higher is required.
[/warning]


## Logging from Python

Collect logs from your Python code.

### 1. Install

Install Better Stack Python PyPI package:

```bash
[label Install logtail-python]
pip3 install logtail-python
```

### 2. Setup

Set up Python logger with Better Stack:

```python
[label Set up Better Stack handler]
from logtail import LogtailHandler
import logging

handler = LogtailHandler(
    source_token='$SOURCE_TOKEN', 
    host='https://$INGESTING_HOST',
)
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.handlers = []
logger.addHandler(handler)
``` 



### 3. Start logging

Use Python logger as usual:

```python
[label Send logs to Better Stack]
logger.error('Something bad happened.')
logger.info('Log message with structured logging.', extra={
    'item': "Orange Soda",
    'price': 100.00
})
```

You should see your logs in [Better Stack → Live tail](https://telemetry.betterstack.com/team/0/tail ";_blank").

[warning]
#### Python 3.10 or higher is required
Pip version 20.0.2 or higher is required.
[/warning]


## Logging from RQ workers

RQ runs each job in a forked process that exits without the usual Python shutdown, so logs written inside a job would never be sent. The Better Stack worker class sends them before the job process exits.

### 1. Setup

Configure the `logtail` handler as in the [Django](#logging-from-django) or [Python](#logging-from-python) setup above.

### 2. Start the worker

Start RQ with the Better Stack worker class:

```bash
[label Start an RQ worker]
rq worker --worker-class logtail.rq.Worker
```

With django-rq, set the worker class in `settings.py` instead:

```python
[label Set the worker class for django-rq]
RQ = {
    "WORKER_CLASS": "logtail.rq.Worker",
}
```

Logs from the worker process itself are sent as usual.

[warning]
#### logtail-python 0.4.1 or higher is required
Older versions do not include the worker class.
[/warning]


## Need help?

Please let us know at hello@betterstack.com.  
We're happy to help! 🙏


## Additional information

Interested in learning more about **Python log levels** and **using formatters** to customize your logs? 
Check out our [Comprehensive Guide to Logging in Python](https://betterstack.com/community/guides/logging/how-to-start-logging-with-python/).

### Missing logs from the end of your application run?

Make sure your application terminates gracefully, giving the logger enough time to finish the request to Better Stack.

Use `sys.exit()` to end your application.

Using `os._exit()` would terminate all threads immediately, potentially dropping your logs.

### Logs not arriving at all?

Errors while building a log record are dropped together with the record by default, so a misconfiguration can leave you with no logs and no error message. While debugging, set `raise_exceptions` to `True` to see the exception instead:

```python
[label Raise handler errors while debugging]
handler = LogtailHandler(
    source_token='$SOURCE_TOKEN',
    host='https://$INGESTING_HOST',
    raise_exceptions=True,
)
```

In Django, add `'raise_exceptions': True` to the `logtail` handler in `LOGGING`.

### Enrich log context

Add custom data to multiple log lines using `with` block:

```python
[label Enrich logs with context]

with logtail.context(user={ 'id': 123 }):
    logger.info('User logged in.')
    # More code here ...
    logger.info('User bought a python.')
```

### Log exceptions

Use `logger.exception()` to log exceptions with traceback:

```python
[label Log exception traceback]
try:
    nonexisting_function()
except Exception as Argument:
    logger.exception("Error occurred while calling non-existing function.")
```

### Handler options

Pass these as keyword arguments to `LogtailHandler`, or as keys of the `logtail` handler in Django `LOGGING`:

| Option | Default | Description |
| --- | --- | --- |
| `host` | EU region | Ingesting host of your source. |
| `timeout` | `30` | Seconds to wait for each request to Better Stack. |
| `buffer_capacity` | `1000` | Logs are sent in batches of up to this many records. |
| `flush_interval` | `1` | Seconds after which a batch is sent even if it is not full. |
| `drop_extra_events` | `True` | Drop new logs while the buffer is full. Set to `False` to block the application instead. |
| `include_extra_attributes` | `True` | Send every value passed in `extra`. Set to `False` to send only dictionaries. |
| `raise_exceptions` | `False` | Raise errors while building a log record instead of dropping the record. |

### Example project

Want to try a more detailed example?  
See our [Python example project on GitHub](https://github.com/logtail/logtail-python/tree/master/example-project).
