Skip to content

Commit

Permalink
Merge pull request #87 from akiva-skolnik/master
Browse files Browse the repository at this point in the history
Fixed DeprecationWarning & improved code format
  • Loading branch information
ralongit authored Feb 25, 2024
2 parents 73adf14 + a464412 commit 98b41e2
Show file tree
Hide file tree
Showing 16 changed files with 154 additions and 107 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/auto-release.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: Pypi Release
on:
workflow_run:
workflows: ["CI Tests"]
branches: [master]
workflows: [ "CI Tests" ]
branches: [ master ]
types:
- completed
# Allows you to run this workflow manually from the Actions tab
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: CI Tests
on: [push]
on: [ push ]
jobs:
run-tests:
runs-on: ubuntu-latest
Expand Down
190 changes: 114 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

### Deprecation announcement

Version 3.0.0 of this project ends support for Python 2.7, 3.3, and 3.4. We recommend migrating your projects to Python 3.5 or newer as soon as possible. We'll be happy to answer any questions you have in [a GitHub issue](https://github.com/logzio/logzio-python-handler/issues).
Version 3.0.0 of this project ends support for Python 2.7, 3.3, and 3.4. We recommend migrating your projects to Python
3.5 or newer as soon as possible. We'll be happy to answer any questions you have
in [a GitHub issue](https://github.com/logzio/logzio-python-handler/issues).

Thanks! <br>
The Logz.io Integrations team
Expand All @@ -15,31 +17,38 @@ The Logz.io Integrations team

This is a Python handler that sends logs in bulk over HTTPS to Logz.io.
The handler uses a subclass named LogzioSender (which can be used without this handler as well, to ship raw data).
The LogzioSender class opens a new Thread, that consumes from the logs queue. Each iteration (its frequency of which can be configured by the logs_drain_timeout parameter), will try to consume the queue in its entirety.
The LogzioSender class opens a new Thread, that consumes from the logs queue. Each iteration (its frequency of which can
be configured by the logs_drain_timeout parameter), will try to consume the queue in its entirety.
Logs will get divided into separate bulks, based on their size.
LogzioSender will check if the main thread is alive. In case the main thread quits, it will try to consume the queue one last time, and then exit. So your program can hang for a few seconds, until the logs are drained.
In case the logs failed to be sent to Logz.io after a couple of tries, they will be written to the local file system. You can later upload them to Logz.io using curl.

LogzioSender will check if the main thread is alive. In case the main thread quits, it will try to consume the queue one
last time, and then exit. So your program can hang for a few seconds, until the logs are drained.
In case the logs failed to be sent to Logz.io after a couple of tries, they will be written to the local file system.
You can later upload them to Logz.io using curl.

## Installation

```bash
pip install logzio-python-handler
```

If you'd like to use [Trace context](#trace-context), you need to install the OpenTelemetry logging instrumentation dependency by running the following command:
If you'd like to use [Trace context](#trace-context), you need to install the OpenTelemetry logging instrumentation
dependency by running the following command:

```bash
pip install logzio-python-handler[opentelemetry-logging]
```

## Tested Python Versions

Travis CI will build this handler and test against:
- "3.5"
- "3.6"
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"

- "3.5"
- "3.6"
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"

We can't ensure compatibility to any other version, as we can't test it automatically.

Expand All @@ -53,46 +62,56 @@ $ tox
```

## Python configuration

#### Config File

```python
[handlers]
keys=LogzioHandler
keys = LogzioHandler

[handler_LogzioHandler]
class=logzio.handler.LogzioHandler
formatter=logzioFormat


class =logzio.handler.LogzioHandler


formatter = logzioFormat

# Parameters must be set in order. Replace these parameters with your configuration.
args=('<<LOG-SHIPPING-TOKEN>>', '<<LOG-TYPE>>', <<TIMEOUT>>, 'https://<<LISTENER-HOST>>:8071', <<DEBUG-FLAG>>,<<NETWORKING-TIMEOUT>>,<<RETRY-LIMIT>>,<<RETRY-TIMEOUT>>)
args = ('<<LOG-SHIPPING-TOKEN>>', '<<LOG-TYPE>>',
<< TIMEOUT >>, 'https://<<LISTENER-HOST>>:8071', << DEBUG-FLAG >>, << NETWORKING-TIMEOUT >>, << RETRY-LIMIT >>, << RETRY-TIMEOUT >>)

[formatters]
keys=logzioFormat
keys = logzioFormat

[loggers]
keys=root
keys = root

[logger_root]
handlers=LogzioHandler
level=INFO
handlers = LogzioHandler
level = INFO

[formatter_logzioFormat]
format={"additional_field": "value"}
format = {"additional_field": "value"}
```

*args=() arguments, by order*
- Your logz.io token
- Log type, for searching in logz.io (defaults to "python")
- Time to sleep between draining attempts (defaults to "3")
- Logz.io Listener address (defaults to "https://listener.logz.io:8071")
- Debug flag. Set to True, will print debug messages to stdout. (defaults to "False")
- Backup logs flag. Set to False, will disable the local backup of logs in case of failure. (defaults to "True")
- Network timeout, in seconds, int or float, for sending the logs to logz.io. (defaults to 10)
- Retries number (retry_no, defaults to 4).
- Retry timeout (retry_timeout) in seconds (defaults to 2).

Please note, that you have to configure those parameters by this exact order.
i.e. you cannot set Debug to true, without configuring all of the previous parameters as well.

- Your logz.io token
- Log type, for searching in logz.io (defaults to "python")
- Time to sleep between draining attempts (defaults to "3")
- Logz.io Listener address (defaults to "https://listener.logz.io:8071")
- Debug flag. Set to True, will print debug messages to stdout. (defaults to "False")
- Backup logs flag. Set to False, will disable the local backup of logs in case of failure. (defaults to "True")
- Network timeout, in seconds, int or float, for sending the logs to logz.io. (defaults to 10)
- Retries number (retry_no, defaults to 4).
- Retry timeout (retry_timeout) in seconds (defaults to 2).

Please note, that you have to configure those parameters by this exact order.
i.e. you cannot set Debug to true, without configuring all of the previous parameters as well.

#### Dict Config

```python
LOGGING = {
'version': 1,
Expand Down Expand Up @@ -125,24 +144,33 @@ LOGGING = {
}
}
```

Replace:

* <<LOGZIO-TOKEN>> - your logz.io account token.
* <<LOGZIO-URL>> - logz.io url, as described [here](https://docs.logz.io/user-guide/accounts/account-region.html#regions-and-urls).
* <<LOGZIO-URL>> - logz.io url, as
described [here](https://docs.logz.io/user-guide/accounts/account-region.html#regions-and-urls).

#### Serverless platforms

If you're using a serverless function, you'll need to import and add the LogzioFlusher annotation before your sender function. To do this, in the code sample below, uncomment the `import` statement and the `@LogzioFlusher(logger)` annotation line.
**Note:** For the LogzioFlusher to work properly, you'll need to make sure that the Logz.io. handler is added to the root logger. See the configuration above for an example.
If you're using a serverless function, you'll need to import and add the LogzioFlusher annotation before your sender
function. To do this, in the code sample below, uncomment the `import` statement and the `@LogzioFlusher(logger)`
annotation line.
**Note:** For the LogzioFlusher to work properly, you'll need to make sure that the Logz.io. handler is added to the
root logger. See the configuration above for an example.

#### Dynamic Extra Fields

If you prefer, you can add extra fields to your logs dynamically, and not pre-defining them in the configuration.
This way, you can allow different logs to have different extra fields.
Example in the code below.
Example in the code below.

#### Code Example

```python
import logging
import logging.config

# If you're using a serverless function, uncomment.
# from logzio.flusher import LogzioFlusher

Expand All @@ -153,55 +181,62 @@ import logging.config
logging.config.dictConfig(LOGGING)
logger = logging.getLogger('superAwesomeLogzioLogger')


# If you're using a serverless function, uncomment.
# @LogzioFlusher(logger)
def my_func():
logger.info('Test log')
logger.warn('Warning')
logger.warning('Warning')

try:
1/0
1 / 0
except:
logger.exception("Supporting exceptions too!")

# Example additional code that demonstrates how to dynamically add/remove fields within the code, make sure class is imported.
# Example additional code that demonstrates how to dynamically add/remove fields within the code, make sure class is imported.

logger.info("Test log") # Outputs: {"message":"Test log"}
extra_fields = {"foo":"bar","counter":1}

extra_fields = {"foo": "bar", "counter": 1}
logger.addFilter(ExtraFieldsLogFilter(extra_fields))
logger.warning("Warning test log") # Outputs: {"message":"Warning test log","foo":"bar","counter":1}
error_fields = {"err_msg":"Failed to run due to exception.","status_code":500}

error_fields = {"err_msg": "Failed to run due to exception.", "status_code": 500}
logger.addFilter(ExtraFieldsLogFilter(error_fields))
logger.error("Error test log") # Outputs: {"message":"Error test log","foo":"bar","counter":1,"err_msg":"Failed to run due to exception.","status_code":500}

logger.error(
"Error test log") # Outputs: {"message":"Error test log","foo":"bar","counter":1,"err_msg":"Failed to run due to exception.","status_code":500}

# If you'd like to remove filters from future logs using the logger.removeFilter option:
logger.removeFilter(ExtraFieldsLogFilter(error_fields))
logger.debug("Debug test log") # Outputs: {"message":"Debug test log","foo":"bar","counter":1}
logger.debug("Debug test log") # Outputs: {"message":"Debug test log","foo":"bar","counter":1}

```

#### Extra Fields
In case you need to dynamic metadata to a speific log and not [dynamically to the logger](#dynamic-extra-fields), other than the constant metadata from the formatter, you can use the "extra" parameter.
All key values in the dictionary passed in "extra" will be presented in Logz.io as new fields in the log you are sending.

In case you need to dynamic metadata to a speific log and not [dynamically to the logger](#dynamic-extra-fields), other
than the constant metadata from the formatter, you can use the "extra" parameter.
All key values in the dictionary passed in "extra" will be presented in Logz.io as new fields in the log you are
sending.
Please note, that you cannot override default fields by the python logger (i.e. lineno, thread, etc..)
For example:

```python
logger.info('Warning', extra={'extra_key':'extra_value'})
logger.info('Warning', extra={'extra_key': 'extra_value'})
```

#### Trace context

If you're sending traces with OpenTelemetry instrumentation (auto or manual), you can correlate your logs with the trace context.
If you're sending traces with OpenTelemetry instrumentation (auto or manual), you can correlate your logs with the trace
context.
That way, your logs will have traces data in it, such as service name, span id and trace id.

Make sure to install the OpenTelemetry logging instrumentation dependecy by running the following command:

```shell
pip install logzio-python-handler[opentelemetry-logging]
```

To enable this feature, set the `add_context` param in your handler configuration to `True`, like in this example:

```python
Expand Down Expand Up @@ -239,6 +274,7 @@ LOGGING = {
```

#### Django configuration

```python
LOGGING = {
'version': 1,
Expand Down Expand Up @@ -284,49 +320,50 @@ LOGGING = {

```


## Release Notes

- 4.1.2
- Fix DeprecationWarning
- Adjusted tests to logging:3.12
- 4.1.1
- Fix flusher issues with serverless
- Fix flusher issues with serverless
- 4.1.0
- Add ability to dynamically attach extra fields to the logs.
- Import opentelemetry logging dependency only if trace context is enabled and dependency is installed manually.
- Updated `opentelemetry-instrumentation-logging==0.39b0`
- Updated `setuptools>=68.0.0`
- Added tests for Python versions: 3.9, 3.10, 3.11
- Add ability to dynamically attach extra fields to the logs.
- Import opentelemetry logging dependency only if trace context is enabled and dependency is installed manually.
- Updated `opentelemetry-instrumentation-logging==0.39b0`
- Updated `setuptools>=68.0.0`
- Added tests for Python versions: 3.9, 3.10, 3.11
- 4.0.2
- Fix bug for logging exceptions ([#76](https://github.com/logzio/logzio-python-handler/pull/76))
- Fix bug for logging exceptions ([#76](https://github.com/logzio/logzio-python-handler/pull/76))
- 4.0.1
- Updated `protobuf>=3.20.2`.
- Added dependency `setuptools>=65.5.1`

- 4.0.0
- Add ability to automatically attach trace context to the logs.
- Updated `protobuf>=3.20.2`.
- Added dependency `setuptools>=65.5.1`

- 4.0.0
- Add ability to automatically attach trace context to the logs.

<details>
<summary markdown="span"> Expand to check old versions </summary>


- 3.1.1
- Bug fixes (issue #68, exception message formatting)
- Added CI: Tests and Auto release
- Bug fixes (issue #68, exception message formatting)
- Added CI: Tests and Auto release

- 3.1.0
- Bug fixes
- Retry number and timeout is now configurable

- 3.0.0
- Deprecated `python2.7` & `python3.4`
- Changed log levels on `_flush_queue()` method (@hilsenrat)

- 2.0.15
- Added flusher decorator for serverless platforms(@mcmasty)
- Add support for `python3.7` and `python3.8`
- Add support for `python3.7` and `python3.8`

- 2.0.13
- 2.0.13
- Add support for `pypy` and `pypy3`(@rudaporto-olx)
- Add timeout for requests.post() (@oseemann)
- Add timeout for requests.post() (@oseemann)
- 2.0.12 - Support disable logs local backup
- 2.0.11 - Completely isolate exception from the message
- 2.0.10 - Not ignoring formatting on exceptions
Expand All @@ -340,11 +377,12 @@ LOGGING = {
- 2.0.2 - Support for formatted messages (Thanks @johnraz!)
- 2.0.1 - Added __all__ to __init__.py, so support * imports
- 2.0.0 - Production, stable release.
- *BREAKING* - Configuration option logs_drain_count was removed, and the order of the parameters has changed for better simplicity. Please review the parameters section above.
- Introducing the LogzioSender class, which is generic and can be used without the handler wrap to ship raw data to Logz.io. Just create a new instance of the class, and use the append() method.
- *BREAKING* - Configuration option logs_drain_count was removed, and the order of the parameters has changed for
better simplicity. Please review the parameters section above.
- Introducing the LogzioSender class, which is generic and can be used without the handler wrap to ship raw data to
Logz.io. Just create a new instance of the class, and use the append() method.
- Simplifications and Robustness
- Full testing framework
- 1.X - Beta versions


</details>
1 change: 1 addition & 0 deletions logzio/flusher.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ def wrapper(*args, **kwargs):
raise
finally:
[h.flush() for h in self.logger.handlers]

return wrapper
Loading

0 comments on commit 98b41e2

Please sign in to comment.