PHPackages                             selfwatch/sdk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Logging &amp; Monitoring](/categories/logging)
4. /
5. selfwatch/sdk

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

selfwatch/sdk
=============

PHP client SDK for selfwatch — a self-hosted log/event ingestion platform.

v0.1.0(today)00MITPHPPHP &gt;=8.1

Since Jun 22Pushed todayCompare

[ Source](https://github.com/Proto-Monad/selfwatch-php-sdk)[ Packagist](https://packagist.org/packages/selfwatch/sdk)[ RSS](/packages/selfwatch-sdk/feed)WikiDiscussions main Synced today

READMEChangelogDependenciesVersions (2)Used By (0)

selfwatch PHP SDK
=================

[](#selfwatch-php-sdk)

A small, dependency-free PHP client for [selfwatch](https://github.com/Proto-Monad/selfwatch) — a self-hosted log/event ingestion platform.

It sends events (messages and exceptions) to selfwatch's store endpoint over HTTP(S) using nothing but `curl`. The capture methods **never throw on transport errors**, so adding logging can't crash your app.

- PHP 8.1+
- No third-party runtime dependencies (uses `ext-curl`, `ext-json`)
- PSR-4 namespace `Selfwatch\Sdk`

---

Install
-------

[](#install)

### With Composer

[](#with-composer)

```
composer require selfwatch/sdk
```

```
require 'vendor/autoload.php';
```

### Drop-in, no Composer

[](#drop-in-no-composer)

The SDK is three small files with no external dependencies. Copy `src/` into your project and require the classes directly:

```
require __DIR__ . '/path/to/src/Dsn.php';
require __DIR__ . '/path/to/src/Severity.php';
require __DIR__ . '/path/to/src/Client.php';
```

---

The DSN
-------

[](#the-dsn)

selfwatch identifies your project with a **DSN** (Data Source Name):

```
{scheme}://{TOKEN}@{HOST}/{PROJECT_ID}

```

Example:

```
http://cd9ef67832d31a28fe50260fc1c85bc1f278e8b3734b05a9@localhost:8003/1

```

PartMeaning`scheme``http` or `https``TOKEN`the project's ingestion key`HOST`host, optionally with a port (e.g. `localhost:8003`)`PROJECT_ID`the integer project idThe SDK derives the store endpoint from the DSN:

```
POST {scheme}://{HOST}/api/{PROJECT_ID}/store/

```

> **`http` is only allowed for loopback hosts** (`127.0.0.1`, `::1`, `localhost`). A non-loopback host **must** use `https`, otherwise constructing the `Dsn`throws an `InvalidArgumentException`. This mirrors the server, which rejects insecure transport for everything except loopback.

---

Quick start
-----------

[](#quick-start)

```
use Selfwatch\Sdk\Client;
use Selfwatch\Sdk\Severity;

$client = new Client(getenv('SELFWATCH_DSN'), [
    'environment' => 'production',
    'release'     => '1.4.2',
    'tags'        => ['service' => 'checkout'],
]);

// Send a message — returns the event id (string) or null on failure.
$id = $client->captureMessage('Cache warmed', Severity::INFO);

// Capture an exception (walks the getPrevious() chain automatically).
try {
    doSomethingRisky();
} catch (\Throwable $e) {
    $eventId = $client->captureException($e, Severity::ERROR, [
        'order_id' => 1234,
    ]);

    if ($eventId === null) {
        // Logging never throws by default; inspect what went wrong:
        error_log('selfwatch send failed: ' . $client->getLastError());
    }
}
```

---

Public API
----------

[](#public-api)

### `Selfwatch\Sdk\Client`

[](#selfwatchsdkclient)

```
new Client(Dsn|string $dsn, array $options = [])

captureMessage(string $message, string $level = 'info', array $extra = []): ?string
captureException(\Throwable $e, string $level = 'error', array $extra = []): ?string
captureEvent(array $event): ?string   // low-level: fills defaults, POSTs, parses
getLastError(): ?string               // reason the last capture failed, or null
getDsn(): Dsn
```

All `capture*` methods return the **event id** on success and **`null`** on failure (unless `throw_on_error` is enabled).

### `Selfwatch\Sdk\Severity`

[](#selfwatchsdkseverity)

Level constants: `Severity::FATAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`.

### `Selfwatch\Sdk\Dsn`

[](#selfwatchsdkdsn)

```
new Dsn(string $dsn)            // throws InvalidArgumentException if malformed
Dsn::from(Dsn|string $dsn): Dsn
getScheme(): string
getToken(): string
getHost(): string               // includes port, e.g. "localhost:8003"
getProjectId(): int
getStoreUrl(): string           // {scheme}://{HOST}/api/{PROJECT_ID}/store/
```

---

Options
-------

[](#options)

Passed as the second argument to `new Client($dsn, [...])`.

OptionTypeDefaultDescription`environment``string|null``null`Sets `environment` on every event (e.g. `production`).`release``string|null``null`Sets `release` on every event (e.g. a version or git SHA).`server_name``string|null``gethostname()`Overrides the reported server name.`tags``array``[]`Default tags merged into every event (event tags win on conflict).`timeout``int` (seconds)`5`Connect + transfer timeout for the HTTP request (minimum 1).`verify_ssl``bool``true`Verify the TLS peer/host. Leave `true` in production.`throw_on_error``bool``false`If `true`, capture failures throw `RuntimeException` instead of `null`.---

What the SDK fills in for you
-----------------------------

[](#what-the-sdk-fills-in-for-you)

When you call any `capture*` method, the SDK provides sensible defaults for any field you didn't set:

- `event_id` — 32 lowercase hex chars (from `random_bytes(16)`)
- `timestamp` — current time, RFC3339 UTC (`gmdate('Y-m-d\TH:i:s\Z')`)
- `platform` — `"php"`
- `level` — `"info"` for messages, `"error"` for exceptions
- `server_name` — `gethostname()` (or the `server_name` option)
- `environment` / `release` — from the matching options
- `contexts.runtime` — `{ "name": "php", "version": PHP_VERSION }`
- `tags` — the default tags from options, merged with per-event tags

For exceptions, `exception.values` is built from the whole `getPrevious()` chain (innermost cause **last**, per the wire contract). Each frame carries `filename`, `function`, `lineno` and an `in_app` flag — `in_app` is `true`unless the file lives under a `/vendor/` directory.

---

Error handling
--------------

[](#error-handling)

By default, transport and server errors are swallowed: the capture method returns `null` and the reason is available via `getLastError()`. The server may respond with, among others:

StatusMeaning`401`missing token`403`invalid / mismatched token`400`insecure transport or bad JSON`413`body larger than 2 MiB`429`rate limited (see the `Retry-After` response header)`500`server errorIf you'd rather have failures raise exceptions (handy in tests), construct the client with `['throw_on_error' => true]`.

---

Running the example
-------------------

[](#running-the-example)

```
SELFWATCH_DSN="http://@localhost:8003/1" php examples/basic.php
```

With no `SELFWATCH_DSN` set it falls back to a local dev DSN.

---

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity32

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/295841682?v=4)[ryecomets](/maintainers/ryecomets)[@ryecomets](https://github.com/ryecomets)

---

Top Contributors

[![ryecomets](https://avatars.githubusercontent.com/u/295841682?v=4)](https://github.com/ryecomets "ryecomets (1 commits)")

---

Tags

loggingmonitoringsdkerror-trackingselfwatch

### Embed Badge

![Health badge](/badges/selfwatch-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/selfwatch-sdk/health.svg)](https://phpackages.com/packages/selfwatch-sdk)
```

###  Alternatives

[lordsimal/cakephp-sentry

Sentry plugin for CakePHP

12299.8k](/packages/lordsimal-cakephp-sentry)[muhammadsadeeq/laravel-activitylog-ui

A beautiful, modern UI for Spatie's Activity Log with advanced filtering, analytics, and real-time features.

17814.3k](/packages/muhammadsadeeq-laravel-activitylog-ui)[inspector-apm/inspector-symfony

Code Execution Monitoring for Symfony applications.

2836.4k9](/packages/inspector-apm-inspector-symfony)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
