-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add correlation_id to context to follow distributed tasks (#27)
- Loading branch information
Showing
10 changed files
with
187 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,46 @@ | ||
# (c) Nelen & Schuurmans | ||
|
||
import time | ||
from typing import Tuple | ||
|
||
from asgiref.sync import sync_to_async | ||
from fluent.sender import FluentSender | ||
|
||
from clean_python import Gateway | ||
from clean_python import Json | ||
from clean_python import SyncGateway | ||
|
||
__all__ = ["FluentbitGateway", "SyncFluentbitGateway"] | ||
|
||
|
||
def unpack_item(item: Json) -> Tuple[str, float, Json]: | ||
data = item.copy() | ||
label = data.pop("tag_suffix", "") | ||
timestamp = data.pop("time", None) | ||
if timestamp is None: | ||
timestamp = time.time() | ||
return label, timestamp, data | ||
|
||
__all__ = ["FluentbitGateway"] | ||
|
||
class SyncFluentbitGateway(SyncGateway): | ||
def __init__(self, tag: str, host: str, port: int): | ||
self._sender = FluentSender( | ||
tag, host=host, port=port, nanosecond_precision=True | ||
) | ||
|
||
def add(self, item: Json): | ||
label, timestamp, data = unpack_item(item) | ||
self._sender.emit_with_time(label, timestamp, data) | ||
return {**data, "time": timestamp, "tag_suffix": label} | ||
|
||
|
||
class FluentbitGateway(Gateway): | ||
def __init__(self, tag: str, host: str, port: int): | ||
self._sender = FluentSender(tag, host=host, port=port) | ||
self._sync_gateway = SyncFluentbitGateway(tag, host, port) | ||
|
||
@sync_to_async | ||
def add(self, item: Json) -> Json: | ||
self._sender.emit(item.pop("tag_suffix", ""), item) | ||
return item | ||
def _add(self, item: Json) -> Json: | ||
return self._sync_gateway.add(item) | ||
|
||
async def add(self, item: Json) -> Json: | ||
return await self._add(item) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
from http import HTTPStatus | ||
from uuid import UUID | ||
from uuid import uuid4 | ||
|
||
import pytest | ||
from fastapi.testclient import TestClient | ||
|
||
from clean_python import ctx | ||
from clean_python import InMemoryGateway | ||
from clean_python.fastapi import get | ||
from clean_python.fastapi import Resource | ||
from clean_python.fastapi import Service | ||
from clean_python.fastapi import v | ||
|
||
|
||
class FooResource(Resource, version=v(1), name="testing"): | ||
@get("/context") | ||
def context(self): | ||
return { | ||
"path": str(ctx.path), | ||
"user": ctx.user, | ||
"tenant": ctx.tenant, | ||
"correlation_id": str(ctx.correlation_id), | ||
} | ||
|
||
|
||
@pytest.fixture | ||
def app(): | ||
return Service(FooResource()).create_app( | ||
title="test", | ||
description="testing", | ||
hostname="testserver", | ||
access_logger_gateway=InMemoryGateway([]), | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def client(app): | ||
return TestClient(app) | ||
|
||
|
||
def test_default_context(app, client: TestClient): | ||
response = client.get(app.url_path_for("v1/context")) | ||
|
||
assert response.status_code == HTTPStatus.OK | ||
|
||
body = response.json() | ||
|
||
assert body["path"] == "http://testserver/v1/context" | ||
assert body["user"] == {"id": "DEV", "name": "dev"} | ||
assert body["tenant"] is None | ||
UUID(body["correlation_id"]) # randomly generated uuid | ||
|
||
assert ctx.correlation_id is None | ||
|
||
|
||
def test_x_correlation_id_header(app, client: TestClient): | ||
uid = str(uuid4()) | ||
response = client.get( | ||
app.url_path_for("v1/context"), | ||
headers={"X-Correlation-Id": uid}, | ||
) | ||
|
||
assert response.status_code == HTTPStatus.OK | ||
|
||
body = response.json() | ||
|
||
assert body["correlation_id"] == uid | ||
|
||
assert ctx.correlation_id is None |
File renamed without changes.
Oops, something went wrong.