Skip to main content

A Python library for constructing wide events

Project description

wevt - A python and typescript library for constructing wide events

When constructing wide events for my services, I've found myself constructing essentially the same library again and again. I end up constructing a mediocre semi-structured wide event library.

The core idea is taken from a wide array of prior art (see below) on wide events. We have structured logs which will eventually be queried. The structured logging part isn't particularly hard, but I've found that it's nice to have a single place where my log structure is defined.

The structure of a wevt WideEvent

The core idea of this library is that we have two bits of information in our wide log.

  1. WideEventBase: contains the service, eventId (unique per wide event), originator (thing that triggered the wide event, contains the spanId)
  2. Any number of WideEventPartials: structured bits of data which are added to our wide event. You can add partials to add application logic, performance logic, etc. This can be things like user information, session ids, function performance info.

We are opinionated in that we define the types of WideEventPartials and other bits of data upfront. Querying structured logs is useful only if:

  1. you know which fields exist
  2. fields are consistently defined (no simultaneous "user-id", "user.id", and "userId" fields)

Yes, most observability interfaces attempt to discover the schemas for you, but I've found that it's not perfect.

Here is an example wide event:

const evt: WideEventLog<Registry> = {
    // WideEventBase attributes
    service: {
        // base info
        name: "my-rest-service",
        version: "1.0.0"

        // additional user defined service info
        pod_id: "v8a4ad"
    },
    eventId: "evnt_V1StGXR8_Z5jdHi6B-myT",
    originator: {
        // ALWAYS contained on an originator
        type: "http",
        spanId: "span_V1StGXR8_Z5jdHi6B-myT",
        
        // HTTP specific originator data
        method: "POST";
        path: "/foo";
        headers: {
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:147.0) Gecko/20100101 Firefox/147.0"
        };
    },

    // WideEventPartial: user
    user: {
        id: "user_V1StGXR8_Z5jdHi6B-myT",
        tier: "pro",
    }

    // WideEventPartial: chat
    chat: {
        chatId: "chat_V1StGXR8_Z5jdHi6B-myT",
        model: "opus",
        messages: 232,
        tokens: 45822,
    },

    // WideEventPartial: chat
    sandbox: {
        sandboxId: "sbox_V1StGXR8_Z5jdHi6B-myT",
        startedAt: 1768868366748,
        startDuration: 5021,
        liveDuration: 116748,
    }
}

Collectors

Collectors flush wide event logs. The goal is that you can adapt the format and flush the logs wherever you want. We provide a few simple collectors, such as a StdioCollector or a FileCollector. It's generally trivial to implement a collector of your own. Just extend the collector interface and implement a flush function. When implementing your own collector, you most likely will want to implement tail sampling and event buffering here.

/**
 * Simple collector to log the event in the console
 */
class StdioCollector implements LogCollectorClient {
    async flush(eventBase: WideEventBase, partials: Map<string, EventPartial<string>>): Promise<void> {
        console.log({
            ...eventBase,
            ...partials
        })
    }
}

WideEventBase

The WideEventBase type contains 3 fields:

  1. eventId, which uniquely identifies your event
  2. originator which is defined broadly as an external thing that triggered your service to do some action. These can include external HTTP requests, websocket messages, cron triggers, etc. Originators have an id and can cross service boundaries. You can think of this as the thing that connects your metrics across service boundaries, much like a traceId. The difference is that originators attach additional information, like HTTP request information
  3. service is where an event is emitted from. Each service should emit one wide event per originator as defined above. A service has a unique name, and can be provided with additional user defined metadata

WideEventPartial

These are partial bits that can be added to a WideEvent via the wevt.log() or wevt.partial() function. These are predefined in the registry type for the reasons mentioned above.

prior art

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

wevt-0.0.1.tar.gz (35.3 kB view details)

Uploaded Source

Built Distribution

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

wevt-0.0.1-py3-none-any.whl (8.8 kB view details)

Uploaded Python 3

File details

Details for the file wevt-0.0.1.tar.gz.

File metadata

  • Download URL: wevt-0.0.1.tar.gz
  • Upload date:
  • Size: 35.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for wevt-0.0.1.tar.gz
Algorithm Hash digest
SHA256 a0e10506521bc78898a3ae06a32985b5465235aa156dbb5bbebdeb62a7c325e9
MD5 3f4a0840ab17540e6d9510dd0b3890ae
BLAKE2b-256 a3fa99491ffe2df4865f07bd652b20c32a95ed4ab6bdcf50ba321ba6bdd2e930

See more details on using hashes here.

File details

Details for the file wevt-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: wevt-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 8.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for wevt-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 81afcde63ff61c3e41bbb06ff225949eaed3348e35c9ac6923127d43a2385996
MD5 6e3a89dcf41008293ca8600cf945a202
BLAKE2b-256 09e1bc4a1078f2e223fef14d53dba781afca716e9aae4dc74f9b9b8b8b169dd7

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