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 fc479ae commit cfdb468
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 5 deletions.
21 changes: 19 additions & 2 deletions lib/src/client/spinify.dart
Original file line number Diff line number Diff line change
Expand Up @@ -723,8 +723,10 @@ base mixin SpinifyRPCMixin on SpinifyBase, SpinifyErrorsMixin {
/// Responsible for metrics.
/// {@nodoc}
@internal
base mixin SpinifyMetricsMixin on SpinifyBase {
int _connectsTotal = 0, _connectsSuccessful = 0;
base mixin SpinifyMetricsMixin on SpinifyBase, SpinifyStateMixin {
int _connectsTotal = 0, _connectsSuccessful = 0, _disconnects = 0;
DateTime? _lastDisconnectTime, _lastConnectTime;
({int? code, String? reason})? _lastDisconnect;

@override
Future<void> connect(String url) async {
Expand All @@ -734,10 +736,19 @@ base mixin SpinifyMetricsMixin on SpinifyBase {

@override
void _onConnected(SpinifyState$Connected state) {
_lastConnectTime = DateTime.now().toUtc();
super._onConnected(state);
_connectsSuccessful++;
}

@override
void _onDisconnected(SpinifyState$Disconnected state) {
_lastDisconnectTime = DateTime.now().toUtc();
super._onDisconnected(state);
_lastDisconnect = (code: state.closeCode, reason: state.closeReason);
_disconnects = 0;
}

/// Get metrics of Spinify client.
@override
SpinifyMetrics get metrics {
Expand All @@ -751,11 +762,17 @@ base mixin SpinifyMetricsMixin on SpinifyBase {
client: _clientSubscriptionManager.count,
server: _serverSubscriptionManager.count,
),
speed: _transport.speed,
state: state,
receivedCount: wsMetrics.receivedCount,
receivedSize: wsMetrics.receivedSize,
transferredCount: wsMetrics.transferredCount,
transferredSize: wsMetrics.transferredSize,
lastConnectTime: _lastConnectTime,
lastDisconnectTime: _lastDisconnectTime,
disconnects: _disconnects,
lastDisconnect: _lastDisconnect,
isRefreshActive: _refreshTimer?.isActive ?? false,
);
}
}
Expand Down
45 changes: 44 additions & 1 deletion lib/src/model/metrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,15 @@ final class SpinifyMetrics implements Comparable<SpinifyMetrics> {
required this.receivedSize,
required this.reconnects,
required this.subscriptions,
required this.speed,
required this.transferredCount,
required this.receivedCount,
required this.lastUrl,
required this.lastConnectTime,
required this.lastDisconnectTime,
required this.disconnects,
required this.lastDisconnect,
required this.isRefreshActive,
});

/// Timestamp of the metrics.
Expand All @@ -54,6 +60,12 @@ final class SpinifyMetrics implements Comparable<SpinifyMetrics> {
SpinifySubscriptionCount server
}) subscriptions;

/// The speed of the request/response in milliseconds.
/// - min - minimum speed
/// - avg - average speed
/// - max - maximum speed
final ({int min, int avg, int max}) speed;

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

Expand All @@ -63,12 +75,27 @@ final class SpinifyMetrics implements Comparable<SpinifyMetrics> {
/// The last URL used to connect.
final String? lastUrl;

/// The time of the last connect.
final DateTime? lastConnectTime;

/// The time of the last disconnect.
final DateTime? lastDisconnectTime;

/// The total number of times the connection has been disconnected.
final int disconnects;

/// The last disconnect reason.
final ({int? code, String? reason})? lastDisconnect;

/// Is refresh active.
final bool isRefreshActive;

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

/// Convert metrics to JSON.
Map<String, Object?> toJson() => <String, Object?>{
'timestamp': timestamp,
'timestamp': timestamp.toIso8601String(),
'state': state.toJson(),
'reconnects': <String, int>{
'successful': reconnects.successful,
Expand All @@ -88,11 +115,27 @@ final class SpinifyMetrics implements Comparable<SpinifyMetrics> {
'subscribed': subscriptions.server.subscribed,
},
},
'speed': <String, int>{
'min': speed.min,
'avg': speed.avg,
'max': speed.max,
},
'transferredSize': transferredSize,
'receivedSize': receivedSize,
'transferredCount': transferredCount,
'receivedCount': receivedCount,
'lastUrl': lastUrl,
'lastConnectTime': lastConnectTime?.toIso8601String(),
'lastDisconnectTime': lastDisconnectTime?.toIso8601String(),
'disconnects': disconnects,
'lastDisconnect': switch (lastDisconnect) {
(:int? code, :String? reason) => <String, Object?>{
'code': code,
'reason': reason,
},
_ => null,
},
'isRefreshActive': isRefreshActive,
};

@override
Expand Down
4 changes: 4 additions & 0 deletions lib/src/transport/transport_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ abstract interface class ISpinifyTransport {
/// {@nodoc}
WebSocketMetrics get metrics;

/// Message response timeout in milliseconds.
/// {@nodoc}
({int min, int avg, int max}) get speed;

/// Connect to the server.
/// [url] is a URL of endpoint.
/// [subs] is a list of server-side subscriptions to subscribe on connect.
Expand Down
16 changes: 14 additions & 2 deletions lib/src/transport/ws_protobuf_transport.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import 'package:spinify/src/transport/transport_interface.dart';
import 'package:spinify/src/transport/transport_protobuf_codec.dart';
import 'package:spinify/src/util/logger.dart' as logger;
import 'package:spinify/src/util/notifier.dart';
import 'package:spinify/src/util/speed_meter.dart';
import 'package:ws/ws.dart';

/// {@nodoc}
Expand Down Expand Up @@ -209,6 +210,10 @@ base mixin SpinifyWSPBSenderMixin
static const Converter<pb.Command, List<int>> _commandEncoder =
TransportProtobufEncoder();

/// Speed meter of the connection.
final SpinifySpeedMeter _speedMeter = SpinifySpeedMeter(15);
({int min, int avg, int max}) get speed => _speedMeter.speed;

/// Counter for messages.
/// {@nodoc}
int _messageId = 1;
Expand All @@ -224,8 +229,15 @@ base mixin SpinifyWSPBSenderMixin
final command = _createCommand(request, false);
// Send command and wait for response.
final future = _awaitReply(command.id);
await _sendCommand(command);
final reply = await future;
final stopwatch = Stopwatch()..start();
pb.Reply reply;
try {
await _sendCommand(command);
reply = await future;
_speedMeter.add(stopwatch.elapsedMilliseconds);
} finally {
stopwatch.stop();
}
if (reply.hasError()) {
throw SpinifyReplyException(
replyCode: reply.error.code,
Expand Down
38 changes: 38 additions & 0 deletions lib/src/util/speed_meter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'dart:math' as math;

import 'package:meta/meta.dart';

/// {@nodoc}
@internal
class SpinifySpeedMeter {
/// {@nodoc}
SpinifySpeedMeter(this.size) : _speeds = List.filled(size, 0);

/// Size of the speed meter
/// {@nodoc}
final int size;
final List<int> _speeds;
int _pointer = 0;
int _count = 0;

/// Add new speed in ms
/// {@nodoc}
void add(num speed) {
_speeds[_pointer] = speed.toInt();
_pointer = (_pointer + 1) % size;
if (_count < size) _count++;
}

/// Get speed in ms
/// {@nodoc}
({int min, int avg, int max}) get speed {
if (_count == 0) return (min: 0, avg: 0, max: 0);
var sum = _speeds.first, min = sum, max = sum;
for (final value in _speeds) {
min = math.min<int>(min, value);
max = math.max<int>(max, value);
sum += value;
}
return (min: min, avg: sum ~/ _count, max: max);
}
}

0 comments on commit cfdb468

Please sign in to comment.