splash/optilog
Splash OptiLog is a lightweight logging package for Laravel and PHP applications. It helps you capture structured application events, add contextual metadata, and keep logging simple, readable, and performance-friendly with minimal configuration. Designed for developers who want clear insight into r...
composer require splash/optilog. It is an embedded Splash connector, so it assumes splash/connector (or splash/core) is already installed in your Splash API host project. Confirm the version constraint in composer.json matches your Splash major (2.x vs 3.x — these are not compatible).config/bundles.php if not auto-registered by Flex:
Splash\Optilog\OptilogBundle::class => ['all' => true],
splash_optilog in config/packages/splash_optilog.yaml), sourced from env vars: OPTILOG_API_URL, OPTILOG_USERNAME, OPTILOG_PASSWORD/OPTILOG_API_KEY, and often a company/site identifier because Optilog is a WMS/TMS style system scoped per warehouse.splash.yaml entity list. First use case: pull reference data (Products, ThirdParties) from Optilog into Splash, then push transactional data (Orders, Shipments, Stock) back. Most teams start with products because it exercises auth, pagination, and the mapping layer with the least business risk.bin/console splash:connector:test optilog or splash:connector:walk products depending on your Splash version. A walk prints the normalized Splash payload for one entity, which is the fastest way to sanity-check field mapping.src/Connectors/ — the class implementing ConnectorInterface; this is your entry point for entity-level sync logic.src/Services/ — the HTTP client wrapper around Optilog's REST endpoints (auth, pagination, error decoding).src/Resources/config/ — DI wiring, service aliases, and the default config tree.src/Mapping/ (or src/Fields/) — the field translation between Splash's canonical model and Optilog's payload shape.One connector per entity, one client for everything. Keep ProductsConnector, OrdersConnector, etc. thin — they should only orchestrate "fetch page → map → yield entity." All HTTP, retry, and auth logic belongs in the Services/ layer so it can be reused and unit-tested in isolation.
Pull with a cursor, not offsets. Optilog endpoints in this family are typically {id}, ?updatedSince=…, or paginated via a link. Drive incremental syncs off a Splash-stored lastSync timestamp, and store the highest updatedAt you actually saw — not now() — so midnight boundary and clock skew issues do not silently skip records.
Push in bounded chunks. Optilog usually accepts 100–500 lines per call but rejects the entire batch on a single bad row. Pattern:
foreach (array_chunk($orders, 100) as $chunk) {
$result = $this->client->postOrders($chunk);
// Optilog returns per-line acceptance; map failures back to Splash entities
$this->handlePartialFailures($chunk, $result);
}
Emit per-entity success/failure back to Splash rather than throwing on the first error, otherwise Splash retries the whole batch and you duplicate orders.
Mapping belongs in config, not code. Expose status codes (OrderStatus, ShipmentStatus) and warehouse IDs via the bundle config so a deployment to a new Optilog tenant does not require a code change. Default mappings in code, override in splash.yaml.
Use Symfony's HttpClientInterface decorator chain (the bundle typically wires one). This lets you inject a mock MockHttpClient in tests and add a Logger/RetryableHttpClient middleware without touching connector code. If the bundle hardcodes file_get_contents or a raw curl handle, that's a red flag — wrap it yourself before doing anything else.
Event subscriber for pre-push enrichment. Register an Events\OrderPushEvent (or the Splash equivalent) subscriber in src/EventListener/ to inject fields Optilog requires but Splash does not carry — e.g. warehouseCode, carrierCode, or a customerRef derived from the third-party. Keeping this out of the connector class means you can vary behavior per host without forking.
Test fixtures beat live calls. Build a Fixtures/ set of representative Optilog responses (a full page, an empty page, a 429, a 401, a 200-with-error-body) and write integration tests against MockHttpClient. For a zero-star package this is the single highest-value investment you can make.
"splash/optilog": "1.2.3") and diff the repo against your Splash core version before upgrading either side. Splash's connector interfaces change between majors.200 OK with {"status":"error","messages":[…]}. If you only check $response->getStatusCode(), failed orders will be marked as synced in Splash and you will never retry them. Decode the body and assert on an explicit success field before returning.Authorization headers and hope; implement a memoized token fetch with refresh-on-401 in the API client. Caching the token in Symfony's cache pool across workers avoids re-authenticating per entity.updatedAt-based cursors, and de-duplicate by Optilog's id when yielding to Splash.RateLimiter middleware or a simple usleep backoff with exponentiation; Splash's own retry will hammer the endpoint and can get your IP/account blocked.Configuration tree usually does not strict-type everything. If a value appears ignored, dump the resolved config (bin/console debug:config splash_optilog) rather than guessing.Authorization header and any password field are redacted in your Services/ client before they get logged — this bites during incident triage.services.yaml alias (not by editing vendor), extend the abstract connector if one exists, and add custom EventListener subscribers. Avoid forking the bundle — with no upstream activity, your fork will never receive fixes.warehouseCode dimension into your mapping or you will sum stock across sites and produce nonsense.walk loops and full re-syncs need memory_limit and max_execution_time raised, and should be chunked with generator-based iteration so a 200k-SKU catalog does not OOM.PATCHES.md describing any local edits, so you can reapply them after an eventual update.How can I help you explore Laravel packages today?