Skip to content

Commit

Permalink
Add metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
PlugFox committed Aug 3, 2023
1 parent 6b96736 commit d82894f
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 2 deletions.
1 change: 1 addition & 0 deletions lib/spinify.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export 'package:spinify/src/model/exception.dart';
export 'package:spinify/src/model/history.dart';
export 'package:spinify/src/model/jwt.dart';
export 'package:spinify/src/model/message.dart';
export 'package:spinify/src/model/metrics.dart';
export 'package:spinify/src/model/presence.dart';
export 'package:spinify/src/model/presence_stats.dart';
export 'package:spinify/src/model/publication.dart';
Expand Down
40 changes: 39 additions & 1 deletion lib/src/client/spinify.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import 'package:spinify/src/model/event.dart';
import 'package:spinify/src/model/exception.dart';
import 'package:spinify/src/model/history.dart';
import 'package:spinify/src/model/message.dart';
import 'package:spinify/src/model/metrics.dart';
import 'package:spinify/src/model/presence.dart';
import 'package:spinify/src/model/presence_stats.dart';
import 'package:spinify/src/model/publication.dart';
Expand Down Expand Up @@ -65,7 +66,8 @@ final class Spinify extends SpinifyBase
SpinifyPresenceMixin,
SpinifyHistoryMixin,
SpinifyRPCMixin,
SpinifyQueueMixin {
SpinifyQueueMixin,
SpinifyMetricsMixin {
/// {@macro spinify}
Spinify([SpinifyConfig? config]) : super(config ?? SpinifyConfig.byDefault());

Expand Down Expand Up @@ -713,6 +715,42 @@ base mixin SpinifyRPCMixin on SpinifyBase, SpinifyErrorsMixin {
}
}

/// Responsible for metrics.
/// {@nodoc}
@internal
base mixin SpinifyMetricsMixin on SpinifyBase {
int _connectsTotal = 0, _connectsSuccessful = 0;

@override
Future<void> connect(String url) async {
_connectsTotal++;
return super.connect(url);
}

@override
void _onConnected(SpinifyState$Connected state) {
super._onConnected(state);
_connectsSuccessful++;
}

/// Get metrics of Spinify client.
@override
SpinifyMetrics get metrics {
final timestamp = DateTime.now().toUtc();
final wsMetrics = _transport.metrics;
return SpinifyMetrics(
timestamp: timestamp,
lastUrl: wsMetrics.lastUrl,
reconnects: (successful: _connectsSuccessful, total: _connectsTotal),
state: state,
receivedCount: wsMetrics.receivedCount,
receivedSize: wsMetrics.receivedSize,
transferredCount: wsMetrics.transferredCount,
transferredSize: wsMetrics.transferredSize,
);
}
}

/// Mixin responsible for queue.
/// SHOULD BE LAST MIXIN.
/// {@nodoc}
Expand Down
10 changes: 9 additions & 1 deletion lib/src/client/spinify_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'dart:async';
import 'package:spinify/src/client/state.dart';
import 'package:spinify/src/client/states_stream.dart';
import 'package:spinify/src/model/history.dart';
import 'package:spinify/src/model/metrics.dart';
import 'package:spinify/src/model/presence.dart';
import 'package:spinify/src/model/presence_stats.dart';
import 'package:spinify/src/model/pushes_stream.dart';
Expand All @@ -22,7 +23,8 @@ abstract interface class ISpinify
ISpinifyClientSubscriptionsManager,
ISpinifyPresenceOwner,
ISpinifyHistoryOwner,
ISpinifyRemoteProcedureCall {
ISpinifyRemoteProcedureCall,
ISpinifyMetricsOwner {
/// Connect to the server.
/// [url] is a URL of endpoint.
Future<void> connect(String url);
Expand Down Expand Up @@ -128,3 +130,9 @@ abstract interface class ISpinifyRemoteProcedureCall {
/// Send arbitrary RPC and wait for response.
Future<List<int>> rpc(String method, List<int> data);
}

/// Spinify metrics interface.
abstract interface class ISpinifyMetricsOwner {
/// Get metrics of Spinify client.
SpinifyMetrics get metrics;
}
67 changes: 67 additions & 0 deletions lib/src/model/metrics.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import 'package:meta/meta.dart';
import 'package:spinify/src/client/state.dart';

/// {@template metrics}
/// Metrics of Spinify client.
/// {@endtemplate}
/// {@category Client}
/// {@category Entity}
@immutable
final class SpinifyMetrics implements Comparable<SpinifyMetrics> {
/// {@macro metrics}
const SpinifyMetrics({
required this.timestamp,
required this.state,
required this.transferredSize,
required this.receivedSize,
required this.reconnects,
required this.transferredCount,
required this.receivedCount,
required this.lastUrl,
});

/// Timestamp of the metrics.
final DateTime timestamp;

/// The current state of the client.
final SpinifyState state;

/// The total number of bytes sent.
final BigInt transferredSize;

/// The total number of bytes received.
final BigInt receivedSize;

/// The total number of times the connection has been re-established.
final ({int successful, int total}) reconnects;

/// The total number of messages sent.
final BigInt transferredCount;

/// The total number of messages received.
final BigInt receivedCount;

/// The last URL used to connect.
final String? lastUrl;

@override
int compareTo(SpinifyMetrics other) => timestamp.compareTo(other.timestamp);

/// Convert metrics to JSON.
Map<String, Object?> toJson() => <String, Object?>{
'timestamp': timestamp,
'state': state.toJson(),
'reconnects': <String, int>{
'successful': reconnects.successful,
'total': reconnects.total,
},
'transferredSize': transferredSize,
'receivedSize': receivedSize,
'transferredCount': transferredCount,
'receivedCount': receivedCount,
'lastUrl': lastUrl,
};

@override
String toString() => 'SpinifyMetrics{}';
}
5 changes: 5 additions & 0 deletions lib/src/transport/transport_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:spinify/src/subscription/server_subscription_manager.dart';
import 'package:spinify/src/subscription/subcibed_on_channel.dart';
import 'package:spinify/src/subscription/subscription_config.dart';
import 'package:spinify/src/util/notifier.dart';
import 'package:ws/ws.dart';

/// Class responsible for sending and receiving data from the server.
/// {@nodoc}
Expand All @@ -29,6 +30,10 @@ abstract interface class ISpinifyTransport {
/// {@nodoc}
abstract final SpinifyListenable<SpinifyEvent> events;

/// Get web socket metrics.
/// {@nodoc}
WebSocketMetrics get metrics;

/// Connect to the server.
/// [url] is a URL of endpoint.
/// [subs] is a list of server-side subscriptions to subscribe on connect.
Expand Down
3 changes: 3 additions & 0 deletions lib/src/transport/ws_protobuf_transport.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ abstract base class SpinifyWSPBTransportBase implements ISpinifyTransport {
final SpinifyChangeNotifier<SpinifyEvent> events =
SpinifyChangeNotifier<SpinifyEvent>();

@override
WebSocketMetrics get metrics => _webSocket.metrics;

/// Init transport, override this method to add custom logic.
/// {@nodoc}
@protected
Expand Down

0 comments on commit d82894f

Please sign in to comment.