structured_log_cupertino 0.1.4
structured_log_cupertino: ^0.1.4 copied to clipboard
A Cupertino (iOS-style) in-app log viewer for structured_log, built on structured_log_flutter.
structured_log_cupertino #
Читать на русском.
A ready-made Cupertino (iOS-style) log viewer for your Flutter app: open a screen — or dock a panel — and see what the app just logged, with search, filters and every entry's full context, the way iPhone and iPad apps present it.
Why #
Something goes wrong while you're testing on an iPhone, and the explanation
is in logs printed to an Xcode console you aren't attached to. This package
puts those logs on a screen inside the app: every
structured_log entry, newest
first, searchable and filterable by level and category, with a tap to drill
into an entry's full context and copy it into a bug report. Wiring it up is
one extra sink and one widget.
Pick it for apps with an iOS look (CupertinoApp, or Cupertino screens
inside a larger app). For a Material app take
structured_log_material;
for a Windows-style desktop app built on fluent_ui,
structured_log_fluent.
If none of the three matches your design system, build your own on
structured_log_flutter —
the skins share it, so filtering and pausing behave the same everywhere.
Features #
Drop-in #
- A screen or a panel —
CupertinoLogViewerPageis a completeCupertinoPageScaffoldwith a "Logs" navigation bar (and the standard back button when pushed);CupertinoLogVieweris the same viewer with no page chrome, for a tab or a side panel. - iPhone and iPad patterns — it measures its own width, not the
window's: below 700 logical pixels a tap pushes the entry as its own
screen via
CupertinoPageRoute, as Mail and Settings do on iPhone; from 700 up, the list and a detail panel sit side by side, as on iPad, with the newest entry selected.
Finding the entry #
- A live list, newest first — new entries appear as the app logs them.
- Search — a
CupertinoSearchTextFieldover event names and every context value. - Level filter — a
CupertinoSlidingSegmentedControl: All, Debug+, Info+, Warning+, Error+. - Category filter — a scrollable row of pill buttons built from the
categories actually in the buffer, hidden while there are fewer than two;
entries from adapters such as
structured_log_dio(http) orstructured_log_bloc(bloc) become a filter on their own. - Pause and clear — freeze the list while you read; clear it to start a fresh reproduction.
- Familiar rows — a colored level dot, the event, the time and a category tag; a disclosure chevron where a tap drills in, a highlight where it selects.
Reading it #
- Full context — level, time and event on top, then every other field as a key/value pair; when pushed, the event name is the screen's title.
- Copy — one tap puts the fields on the clipboard as
key: valuelines. - Clear empty states — "No logs yet" when nothing was captured, "No logs match the current filter" with a "Clear filters" action when the filters hid everything.
Looks like your app #
- Follows your theme — colors and typography come from
CupertinoThemeandCupertinoColors, light and dark; only the level colors are fixed, and they are the same in every skin. - No Material — the package uses Cupertino widgets and
cupertino_iconsonly. - Parts to compose your own layout —
LogEntryTile,LogCategoryFilterBar,LogEntryDetailPanelandLogViewerEmptyStateare public.
Where it fits #
structured_log writes the
entries;
structured_log_flutter
keeps the recent ones in memory and handles filtering and pausing; this
package is the Cupertino face on top, a sibling of
structured_log_material
and structured_log_fluent.
It works entirely inside your app, with no server; if you also ship logs to
a self-hosted server with
structured_log_remote_sync,
the viewer keeps showing them locally. More in the documentation at
structured-log.openidealab.com and
in the Embedding Guide.
Design and decision history:
openspec/changes/archive/2026-10-01-add-structured-log-cupertino/.
Installation #
dependencies:
structured_log: ^0.3.0
structured_log_flutter: ^0.1.2
structured_log_cupertino: ^0.1.1
Within this monorepo, melos bootstrap resolves both internal packages to
path dependencies instead:
dependencies:
structured_log_flutter:
path: ../structured_log_flutter
structured_log_cupertino:
path: ../structured_log_cupertino
Quick Start #
import 'package:flutter/cupertino.dart';
import 'package:structured_log/structured_log.dart';
import 'package:structured_log_flutter/structured_log_flutter.dart';
import 'package:structured_log_cupertino/structured_log_cupertino.dart';
void main() {
final buffer = LogBuffer();
final controller = LogViewerController(buffer);
StructlogConfiguration.configure(sinks: [
LogSink(name: 'viewer', output: buffer.capture),
]);
runApp(CupertinoApp(
home: CupertinoLogViewerPage(controller: controller),
));
}
See example/ for a full runnable app (including web) — run it
with flutter run -d chrome from that directory.
To embed the viewer inside existing page chrome instead of giving it the
whole screen, use CupertinoLogViewer directly:
Row(
children: [
Expanded(child: MyAppContent()),
SizedBox(
width: 420,
child: CupertinoLogViewer(controller: controller),
),
],
)
CupertinoLogViewer lays itself out from its top edge and keeps no safe
area of its own. Under a translucent CupertinoNavigationBar — the
default — wrap it in a SafeArea, as CupertinoLogViewerPage does, or
its toolbar sits under the bar.
Localization #
Every label the viewer draws — search placeholder, pause/clear, the level and category filters, the page title, both empty states, the detail view's heading and copy action — can be replaced. Two ways, which combine:
Ready-made English and Russian. Register the delegate from
structured_log_flutter (re-exported here); the viewer then follows the app's
locale. English keeps this package's own wording.
CupertinoApp(
localizationsDelegates: const [
LogViewerLocalizations.delegate,
// ...the app's other delegates
],
supportedLocales: const [Locale('en'), Locale('ru')],
// ...
)
Your own labels, for any language or to change one phrase. A field you
set wins over the delegate; a field you leave null falls back to the
delegate, then to the English default.
CupertinoLogViewer(
controller: controller,
labels: LogViewerLabels(
searchHint: context.l10n.logsSearchHint,
levelFilterLabel: (level) =>
level == null ? context.l10n.allLevels : '${level.name}+',
),
)
No flutter_localizations or intl is needed for either.
Confirming a copy. The viewer copies an entry's context silently; pass
onContextCopied to show your own confirmation. It is called after the
clipboard write succeeds, never on failure:
CupertinoLogViewer(
controller: controller,
// iOS has no snack bar: confirm the way the rest of your app does.
onContextCopied: (entry) => showCopiedToast(context),
)
Screenshots #
CupertinoLogViewerPage as the full screen, on a wide/iPad-size
viewport — list and the non-modal detail panel side by side:

CupertinoLogViewer embedded in a side panel next to other app content —
the same widget, no page chrome of its own:

On a phone-width screen — the mobile-style default — the list is on
its own, and tapping an entry pushes LogEntryDetailPanel as its
own screen via CupertinoPageRoute, the standard iOS "drill into
detail" pattern:

API Reference #
| Widget | Description |
|---|---|
CupertinoLogViewer({required LogViewerController controller, LogViewerLabels labels, onContextCopied}) |
The log viewer as an embeddable widget (no page chrome) |
CupertinoLogViewerPage({required LogViewerController controller, LogViewerLabels labels, onContextCopied}) |
The full screen |
LogCategoryFilterBar({required LogViewerController controller, String? allLabel, LogViewerLabels labels}) |
The category-filter pill row |
LogEntryTile({required entry, required onTap, bool selected = false, bool showsDisclosureIndicator = true}) |
One list row |
LogEntryDetailPanel({required entry, labels, onContextCopied}) |
The full-context detail content (pushed or side-by-side) |
LogViewerEmptyState({required hasLogs, required onClearFilters, LogViewerLabels labels}) |
The two-variant empty state |
logLevelColor(LogLevel level, Brightness brightness) |
The canonical level-indicator color — defined once in structured_log_flutter, shared by every skin |
entry throughout is the Map<String, dynamic> shape structured_log
produces directly — no separate typed model.
Related packages #
The rest of the structured_log family:
Core
structured_log— structured JSON logging with context binding, processors and multi-sink routing
In-app log viewer
structured_log_flutter— headless viewer core:LogBufferandLogViewerControllerstructured_log_material— Material 3 log viewerstructured_log_fluent— Fluent UI (WinUI-style) log viewer
Shipping logs to a server
structured_log_remote_sync— batching, retrying sink for a self-hostedstructured_log_server
Integrations
structured_log_bloc—BlocObserverforbloc/flutter_blocstructured_log_dio—diointerceptor that logs HTTP callsstructured_log_http_client—package:httpclient wrapper that logs HTTP callsstructured_log_go_router— logsgo_routernavigationstructured_log_auto_route— logsauto_routenavigationstructured_log_cherrypick— observer for thecherrypickDI containerstructured_log_drift— driftQueryInterceptorthat logs queries, failures and transactionsstructured_log_logging— bridge that routespackage:loggingrecords intostructured_logstructured_log_riverpod—ProviderObserverforriverpod/flutter_riverpod
License #
MIT