pulse_dev 0.1.0
pulse_dev: ^0.1.0 copied to clipboard
Pure Dart core for the Pulse Developer Intelligence SDK. Provides event models, the event pipeline, transport and storage interfaces, privacy sanitization, breadcrumb buffering, performance instrument [...]
pulse_dev #
Pure Dart core for the Pulse Developer Intelligence SDK.
pulse_dev is Flutter-free and works in any Dart project β Flutter apps, CLI tools, or
server-side Dart. It provides the event model, processing pipeline, privacy engine, network
observer, performance instrumentation, and offline storage β all behind clean, replaceable interfaces.
For Flutter applications, use pulse_dev_flutter
which builds on this package and provides the Pulse static API.
Features #
- π¦ Typed event model β
ErrorEvent,ExceptionEvent,BreadcrumbEvent,CustomEvent,NetworkEvent,TransactionEvent - π Composable pipeline β pluggable
EventProcessorchain β sanitizer β transport - π Privacy-first sanitization β recursive PII redaction for 20+ sensitive key patterns out of the box
- π Network monitoring β framework-agnostic
PulseNetworkObserver; adapters fordioandpackage:httpsold separately - β‘ Performance tracking β transactions, spans, and slow operation detection
- πΎ Offline queue β FIFO event queue with exponential backoff, configurable retry, and expiration
- π Pluggable transport β implement
PulseTransportto send events anywhere - π§ͺ Fully testable β injectable
Clock,IdGenerator,PulseTransport, andPulseStorage
Installation #
dependencies:
pulse_dev: ^0.1.0
For Flutter projects, use pulse_dev_flutter instead β it re-exports everything from this package.
Quick Start (pure Dart) #
import 'package:pulse_dev/pulse_dev.dart';
final config = PulseConfig(
dsn: 'https://key@ingest.example.com/1',
environment: 'production',
release: '1.0.0',
transport: MyHttpTransport(),
);
final pipeline = EventPipeline.fromConfig(config);
try {
await riskyOperation();
} catch (e, st) {
await pipeline.process(ExceptionEvent(
id: const UuidGenerator().newId(),
timestamp: const SystemClock().now(),
sdkVersion: kPulseSdkVersion,
appVersion: config.release,
environment: config.environment,
platform: PulsePlatform.dart,
context: PulseContext.empty,
exceptionType: e.runtimeType.toString(),
message: e.toString(),
stackTrace: st.toString(),
breadcrumbs: const [],
handled: true,
));
}
Custom Transport #
Implement PulseTransport to deliver events to your backend:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:pulse_dev/pulse_dev.dart';
final class MyHttpTransport implements PulseTransport {
final Uri _endpoint;
final String _apiKey;
MyHttpTransport({required Uri endpoint, required String apiKey})
: _endpoint = endpoint,
_apiKey = apiKey;
@override
Future<PulseTransportResult> send(PulseEvent event) async {
try {
final response = await http.post(
_endpoint,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $_apiKey',
},
body: jsonEncode(event.toJson()),
);
if (response.statusCode == 429 || response.statusCode >= 500) {
return PulseTransportResult.retryableFailure;
}
if (response.statusCode >= 400) {
return PulseTransportResult.permanentFailure;
}
return PulseTransportResult.success;
} catch (_) {
return PulseTransportResult.retryableFailure;
}
}
@override
Future<void> close() async {}
}
Custom Sanitizer #
Override sensitive data redaction for your organisation's needs:
import 'package:pulse_dev/pulse_dev.dart';
final class MyOrgSanitizer extends DefaultSanitizer {
MyOrgSanitizer()
: super(
config: const PulseSanitizationConfig(
additionalRedactedKeys: {
'employee_id',
'internal_project_code',
'client_secret',
},
),
);
}
Custom Event Processor #
Enrich or filter events before transport:
import 'package:pulse_dev/pulse_dev.dart';
final class EnvironmentTagProcessor implements EventProcessor {
final String region;
const EnvironmentTagProcessor({required this.region});
@override
PulseEvent? process(PulseEvent event) {
if (event is CustomEvent) {
return CustomEvent(
// copy fields and add region tag
properties: {...event.properties, 'region': region},
// ... other fields
);
}
return event; // pass-through for other event types
}
}
Network Monitoring #
import 'package:pulse_dev/pulse_dev.dart';
final observer = PulseNetworkObserver(
pipeline: pipeline,
config: PulseNetworkConfig(
enabled: true,
captureHeaders: false, // never capture headers by default
captureBody: false, // never capture body by default
redactQueryParameters: const {'token', 'api_key'},
),
);
// Use with an HTTP adapter:
// - package:pulse_http β PulseHttpClient
// - package:pulse_dio β PulseDioInterceptor
Performance Tracking #
import 'package:pulse_dev/pulse_dev.dart';
final transaction = pipeline.startTransaction('checkout_flow');
try {
final span = transaction.startSpan('validate_cart');
await validateCart();
span.finish();
final paySpan = transaction.startSpan('process_payment');
await processPayment();
paySpan.finish();
transaction.finish(status: 'ok');
} catch (e, st) {
transaction.finish(status: 'error', error: e);
rethrow;
}
Configuration Reference #
PulseConfig(
dsn: 'https://key@ingest.example.com/1', // required
environment: 'staging', // default: 'production'
release: '2.0.0+42', // app version string
debug: true, // verbose SDK logging
enabled: true, // global kill-switch
sampleRate: 0.25, // drop 75% of events (0.0β1.0)
maxBreadcrumbs: 50, // breadcrumb ring buffer size
transport: MyHttpTransport(), // your delivery implementation
sanitizer: MyOrgSanitizer(), // custom privacy sanitization
logger: MyDebugLogger(), // custom SDK-internal logging
processors: [EnvironmentTagProcessor()], // event enrichment chain
network: PulseNetworkConfig(...), // network monitoring options
performance: PulsePerformanceConfig(...), // performance monitoring options
sanitization: PulseSanitizationConfig(...), // sanitization options
)
Related Packages #
| Package | Description |
|---|---|
pulse_dev_flutter |
Flutter integration β Pulse static API, error hooks, debug inspector |
pulse_http |
package:http network adapter |
pulse_dio |
package:dio network interceptor |
Contributing #
See CONTRIBUTING.md.
License #
MIT β see LICENSE.