Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ Setting and getting correlation ID
""""""""""""""""""""""""""""""""""

When using cf_logging in a web application you don't need to set the correlation ID, because the logging library will fetch it from the HTTP headers and set it.
For non web applications you could set the correlation ID manually, so that the log entries can be filtered later on based on the correlation_id.
For non web applications you could set the correlation ID manually, so that the log entries can be filtered later on based on the ``correlation_id`` log property.
In this case the correlation ID is kept in a thread local variable and each thread should set its own correlation ID.

Setting and getting the correlation_id can be done via:

Expand All @@ -168,11 +169,7 @@ Setting and getting the correlation_id can be done via:
cf_logging.FRAMEWORK.context.get_correlation_id()
cf_logging.FRAMEWORK.context.set_correlation_id(value)

Whenever a correlation id is set after initializing cf_logging without a specific framework (ex: cf_logging.init()) - this same correlation ID would be used for each log record.

If you need a *thread safe* correlation ID, you can reuse the ``cf_logging.job_loffing.framework.JobFramework`` and provide your own context implementation that is *thread safe*.

If you need to get the correlation_id in a web application, take into account the framework you are using.
If you need to get the correlation ID in a web application, take into account the framework you are using.
In async frameworks like Sanic and Falcon the context is stored into the request object and you need to provide the request to the call:

.. code:: python
Expand Down
4 changes: 3 additions & 1 deletion sap/cf_logging/job_logging/context.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
""" Job logging context - used by the logging package to keep log data """
import threading
from sap.cf_logging.core.context import Context


class JobContext(Context):
class JobContext(Context, threading.local):
""" Stores logging context in dict """

def __init__(self):
super(JobContext, self).__init__()
self._mem_store = {}

def set(self, key, value, request):
Expand Down
30 changes: 30 additions & 0 deletions tests/test_job_logging.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
""" Module to test the cf_logging library """
import uuid
import logging
import time
import threading
from json import JSONDecoder
import pytest
from json_validator.validator import JsonValidator
Expand Down Expand Up @@ -42,3 +45,30 @@ def test_set_correlation_id():
assert error == {}
assert log_json['correlation_id'] == correlation_id
assert cf_logging.FRAMEWORK.context.get_correlation_id() == correlation_id

def test_thread_safety():
""" test context keeps separate correlation ID per thread """
class _SampleThread(threading.Thread):
def __init__(self):
super(_SampleThread, self).__init__()
self.correlation_id = str(uuid.uuid1())
self.read_correlation_id = ''

def run(self):
cf_logging.FRAMEWORK.context.set_correlation_id(self.correlation_id)
time.sleep(0.1)
self.read_correlation_id = cf_logging.FRAMEWORK.context.get_correlation_id()

cf_logging.init(level=logging.DEBUG)

thread_one = _SampleThread()
thread_two = _SampleThread()

thread_one.start()
thread_two.start()

thread_one.join()
thread_two.join()

assert thread_one.correlation_id == thread_one.read_correlation_id
assert thread_two.correlation_id == thread_two.read_correlation_id