Skip to main content

A hassle-free client to send logs to LogWell-service

Project description

LogWell-client

Introduction

LogWell-client is a hassle-free Python client to send logs to an instance of LogWell-service.
LogWell-client is for you, if you are determined to use LogWell-service to stash your logs and want to avoid plain HTTP calls every now and then throughout your code base.

Features

  1. Sync and Async clients for log creation
  2. Blocking and Non-blocking log creation support
  3. Compatible with Python’s built-in logging module through a custom handler

Installation

Install the LogWell-client using the following command:

pip install logwell-client

Log Schema

A log object in the client follows the same type (pydantic.BaseModel) and structure as the service, except for the uid and created_at fields that are generated automatically at the server upon receiving a log instance; therefore, from LogWell-client perspective, a log consists of the following fields:

tenant: str | None = None                                       # an identifier to the creator (service) of the log
log: dict | str = Field(default_factory=dict)                   # the actual log to save
execution_path: dict | None = None                              # the execution path, leading to where the log is introduced
metadata: dict = Field(default_factory=dict)                    # additional metadata to stroe
tag: str | None = None                                          # a custom tag to query a log or a family of logs
level: Level = Level.NOTSET                                     # the level to produce the log; available options are: ["INFO", "TRACE","DEBUG", "WARNING", "ERROR", "CRITICAL", "FATAL", "NOTSET",]
group_path: List[str] | None = None                             # a group path, to register nnested logs

Log creation approaches

LogWell-service supports log creation through the following approaches:

  • Naive (blocking) log creation: LogWell-service keeps the HTTP connection open, while writing the log to the database.
  • Non-blocking log creation using FastAPI builting BackgroundTasks: This way, LogWell-service closes the HTTP connection ASAP and afterwards, the log creation is done as an instance of FastAPI.BackgroundTasks.
  • Advanced non-blocking: In this case, LogWell-service uses a message queue and a celery worker to queue the log as a message and a spearate celery worker takes care of writing it to the database.

In LogWell-client, the log creation approach is specified using the following StrEnum:

class Endpoint(StrEnum):
    Blocking = "/logs/"
    NonBlocking = "/logs/non-blocking/"
    BuiltInNonBlocking = "/logs/non-blocking/builtin/"

Usage

LogWell-client can be used to both create logs and read logs, as follow:

Log creation

LogWell-client can be either used at client-level or as a custom handler -- to be added to an instance of logging.Logger -- to create logs; each of these approaches are discussed separately:

1. Using client(s either sync or async)

  • Synchronous client:
    from logwell_client.client import SyncLogClient
    from logwell_client.schema import LogCreateSchema
    
    client = SyncLogClient(base_url="http://localhost:8000/", api_key="key1", tenant="tenant1")
    
    response = client.create_log(
        log=LogCreateSchema(
            log="hello world",
            metadata={"client_ip": "127.0.0.1"},
            level="INFO",
            tag="tag1",
        )
    )
    
    print(response.json())
    client.close()
    
    >>> OUTPUT:
    {'message': 'Log added successfully', 'data': {'tenant': 'tenant1', 'log': 'hello world', 'execution_path': None, 'metadata': {'client_ip': '127.0.0.1'}, 'tag': 'tag1', 'level': 'INFO', 'group_path': None, 'uid': '680a28ad-88fd-456a-ac81-6d3c42334f33', 'created_at': '2025-08-20T11:21:28.914545'}}
    
  • Asynchronous client:
    import asyncio
    from logwell_client.client import AsyncLogClient, Endpoint
    from logwell_client.schema import LogCreateSchema
    
    async def main():
        client = AsyncLogClient(base_url="http://localhost:8000/", api_key="key1", tenant="tenant1")
        response = await client.create_log(
            log=LogCreateSchema(
                log="hello async world",
                metadata={"client_ip": "127.0.0.1"},
                level="INFO",
                tag="tag2",
            )
        )
        print(response.json())
        await client.aclose()
    
    asyncio.run(main())
    
    >>> OUTPUT:
    {'message': 'Log added successfully', 'data': {'tenant': 'tenant1', 'log': 'hello async world', 'execution_path': None, 'metadata': {'client_ip': '127.0.0.1'}, 'tag': 'tag2', 'level': 'INFO', 'group_path': None, 'uid': '420f3c26-8474-4fe9-a7ff-10ad6683ee38', 'created_at': '2025-08-20T11:22:31.195423'}}
    

2. Using the Logging Handler

LogWell-client also provides a logging.Handler implementation to seamlessly integrate with Python logging:

import logging
from logwell_client.handler import LogServiceHandler

logger = logging.getLogger("my-app")
logger.setLevel(logging.DEBUG)

handler = LogServiceHandler(
    base_url="http://localhost:8000",
    api_key="key1",
    tenant="tenant1",
)
logger.addHandler(handler)

logger.info(
    "Hello world!",
    extra={
        "metadata": {"client_ip": "127.0.0.1"},
        "tag": "tag1",
    },
)

Log retrieval

Using LogWell-client to read logs, requires instanciating from the following LogQuerySchema class:

class QueryParams(BaseModel):
    offset: int | None = 0
    limit: int | None = 10

class GroupPathFlag(StrEnum):
    ExactOnly = "exact_only"
    AllChildren = "all_children"


class LogQuerySchema(BaseModel):
    list: bool | None = None
    uid: str | None = None
    tag: str | None = None
    level: Level | None = None
    group_path: str | None = None
    group_path_flag: GroupPathFlag | None = None
    query_params: QueryParams | None = None

This can be done, either as LogQuerySchema or python dict. Almost all the attributes of LogQuerySchema are self-descriptory, therefore, we avoid defining everyone of them. Followings though, require defining them as below:

  • group_path_flag determines either logs with the exact group_path or all children under the group_path are desired.
  • query_params LogWell-service supports query parameters to retrieve logs from the service; to do so, two attributes of offset and limit can be passed to tune the range of logs supposed to be retrieved.

Attention: Amongst list, uid, tag, level and group_path you are supposed to declare one of them.

  • Synchronous client:

Below, examples to retrieve logs through different query options are provided:

  • Get the whole list:
    from logwell_client.client import SyncLogClient
    
    # instanciate the sync client
    client = SyncLogClient(
        base_url="http://localhost:8000/",
        api_key="api_key",
    )
    
    log_list = client.read_log(
        query={
            "list": True,
        }
    )
    
    print(
        log_list.json()
    )
    
  • Get by UID:
    log = client.read_log(
        query={
            "uid": "desired_uid",
        }
    )
    
    print(log.json())
    
  • Get by tag:
    tag_logs = client.read_log(
        query={
            "tag": "desired_tag",
        }
    )
    
    print(
        tag_logs.json()
    )
    
    Get by level:
    level_logs = client.read_log(
    query={
        "level": "desired_level",
        }
    )
    
    print(
        level_logs.json()
    )
    
    Get by Group path (exact):
    group_path_logs = client.read_log(
    query={
        "group_path": "desired_group_path",
        "group_path_flag": "exact_only",
        }
    )
    
    print(
        group_path_logs.json()
    )
    
    Get by Group path (all children):
    group_path_logs = client.read_log(
    query={
        "group_path": "desired_group_path",
        "group_path_flag": "all_children",
        }
    )
    
    print(
        group_path_logs.json()
    )
    
  • Asynchronous client:

The asynchronous client uses absolutely similar interface to communicate with, except that executing asynchronous functions are more complicated. Below is an example to try out log retrieval using the asynchronous client.

from logwell_client.client import SyncLogClient
import asyncio

AsyncLogClient = AsyncLogClient(
    base_url="http://localhost:8000/",
    api_key="key1"
)


async def main():
    log = await AsyncLogClient.read_log(
        query={
            "uid": "desired_uid",
        }
    )

    print(log.json())


asyncio.run(main())

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

logwell_client-0.1.1.tar.gz (6.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

logwell_client-0.1.1-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

Details for the file logwell_client-0.1.1.tar.gz.

File metadata

  • Download URL: logwell_client-0.1.1.tar.gz
  • Upload date:
  • Size: 6.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for logwell_client-0.1.1.tar.gz
Algorithm Hash digest
SHA256 c824ab9a44d78b5f6e46a5527813a574a7a1200c44cef082a3fb00a96db5e8c7
MD5 5da05a4be7c7393a43c1cd781c0d00b8
BLAKE2b-256 c00a6fac870bca19aaec6ecc0e25cacb429588873d11dba078836e86c6e6d9a6

See more details on using hashes here.

File details

Details for the file logwell_client-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: logwell_client-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 7.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for logwell_client-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a1bd1d1bbc5ee898119529d5fd48141e5391598469db02a4e4e5f417ee838791
MD5 5c2159f2aeedfd3d5545b5d008e544a5
BLAKE2b-256 691637c6641bd8a3de6a03ab4c529ae98133e742f0b1b617da860dce9b53ab05

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page