From a2245353f359217d1102d97bdcd679de10c3563d Mon Sep 17 00:00:00 2001 From: Rapougnac Date: Wed, 13 Mar 2024 15:16:49 +0100 Subject: [PATCH] Initial commit --- CHANGELOG.md | 3 + README.md | 3 + analysis_options.yaml | 30 ++ bin/nyxx_utils.dart | 0 lib/nyxx_analytics.dart | 0 lib/nyxx_analytics/nyxx_analytics.dart | 165 +++++++++ lib/nyxx_utils.dart | 0 pubspec.lock | 461 +++++++++++++++++++++++++ pubspec.yaml | 16 + test/nyxx_utils_test.dart | 0 10 files changed, 678 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 analysis_options.yaml create mode 100644 bin/nyxx_utils.dart create mode 100644 lib/nyxx_analytics.dart create mode 100644 lib/nyxx_analytics/nyxx_analytics.dart create mode 100644 lib/nyxx_utils.dart create mode 100644 pubspec.lock create mode 100644 pubspec.yaml create mode 100644 test/nyxx_utils_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d40b303 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# nyxx_utils + +A collection of utilities for the nyxx library. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/bin/nyxx_utils.dart b/bin/nyxx_utils.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/nyxx_analytics.dart b/lib/nyxx_analytics.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/nyxx_analytics/nyxx_analytics.dart b/lib/nyxx_analytics/nyxx_analytics.dart new file mode 100644 index 0000000..b39f721 --- /dev/null +++ b/lib/nyxx_analytics/nyxx_analytics.dart @@ -0,0 +1,165 @@ +import 'dart:async'; + +import 'package:nyxx/nyxx.dart'; +import 'package:prometheus_client/prometheus_client.dart'; +import 'package:prometheus_client_shelf/shelf_handler.dart'; +import 'package:shelf/shelf.dart'; +import 'package:shelf/shelf_io.dart' as io; +import 'package:shelf_router/shelf_router.dart'; +import 'package:prometheus_client_shelf/shelf_metrics.dart' as shelf_metrics; +import 'package:prometheus_client/runtime_metrics.dart' as runtime_metrics; + +// final logger = Logger('Analytics'); + +/// A global instance of the [Analytics] plugin. +final analytics = Analytics(); + +class Analytics extends NyxxPlugin { + @override + String get name => 'Analytics'; + + /// Whether to include runtime metrics in the analytics. + final bool includeDefaultMetrics; + + /// The port to bind the analytics server to. + final int port; + + /// The analytics route. + final String route; + + /// The refresh interval for the analytics. + final Duration refreshInterval; + + /// Custom gauges for the analytics. It's up to you to update these. + final List gauges; + + /// Custom counters for the analytics. + final List counters; + + /// Custom summaries for the analytics. + final List summaries; + + /// Custom histograms for the analytics. + final List histograms; + + Analytics({ + this.includeDefaultMetrics = true, + this.port = 4242, + this.route = '/analytics', + this.refreshInterval = const Duration(seconds: 5), + this.gauges = const [], + this.counters = const [], + this.summaries = const [], + this.histograms = const [], + }); + + @override + Future beforeConnect( + ApiOptions apiOptions, + ClientOptions clientOptions, + ) async { + final router = Router(); + + router.get('/', (req) => Response.found(route)); + router.get(route, prometheusHandler()); + + final pipeline = const Pipeline(); + + if (includeDefaultMetrics) { + runtime_metrics.register(); + pipeline.addMiddleware(shelf_metrics.register()); + } + + final server = await io.serve( + pipeline.addHandler(router.call), + '0.0.0.0', + port, + ); + + // this.s + + logger.info('Serving analytics at http://${server.address.host}:${server.port}$route'); + } + + @override + NyxxPluginState createState() => AnalyticsPluginState(this); +} + +class AnalyticsPluginState extends NyxxPluginState { + late final Timer timer; + + AnalyticsPluginState(super.plugin); + + @override + Future afterConnect(NyxxRest client) async { + await super.afterConnect(client); + registerPeriodicMetrics(client); + registerCustomMetrics(); + } + + void registerCustomMetrics() { + final m = [plugin.gauges, plugin.counters, plugin.summaries, plugin.histograms].expand((e) => e); + + if (m.isEmpty) return; + + for (dynamic metric in m) { + metric.register(); + } + } + + void registerPeriodicMetrics(NyxxRest client) { + final cachedUsers = Gauge(name: 'nyxx_analytics_cached_users', help: 'The number of cached users')..register(); + final cachedGuilds = Gauge(name: 'nyxx_analytics_cached_guilds', help: 'The number of cached guilds')..register(); + final cachedChannels = Gauge(name: 'nyxx_analytics_cached_channels', help: 'The number of cached channels') + ..register(); + final cachedMessages = Gauge(name: 'nyxx_analytics_cached_messages', help: 'The total number of cached messages') + ..register(); + final restLatency = Gauge( + name: 'nyxx_analytics_rest_latency', + help: 'The average REST latency', + labelNames: ['client_id'], + )..register(); + final realRestLatency = Gauge( + name: 'nyxx_analytics_real_rest_latency', + help: 'The real average REST latency', + labelNames: ['client_id'], + )..register(); + + Gauge? gatewayLatency; + Gauge? shardGatewayLatency; + + if (client is NyxxGateway) { + gatewayLatency = Gauge( + name: 'nyxx_analytics_gateway_latency', + help: 'The average gateway latency', + labelNames: ['client_id'], + )..register(); + shardGatewayLatency = Gauge( + name: 'nyxx_analytics_shard_gateway_latency', + help: 'The average gateway latency per shard', + labelNames: ['client_id', 'shard_id'], + )..register(); + } + + Timer.periodic(plugin.refreshInterval, (timer) { + cachedUsers.value = client.users.cache.length.toDouble(); + cachedGuilds.value = client.guilds.cache.length.toDouble(); + cachedChannels.value = client.channels.cache.length.toDouble(); + cachedMessages.value = client.channels.cache.values + .whereType() + .fold(0, (count, channel) => count + channel.messages.cache.length) + .toDouble(); + restLatency.labels([client.user.id.toString()]).value = client.httpHandler.latency.inMilliseconds.toDouble(); + realRestLatency.labels([client.user.id.toString()]).value = + client.httpHandler.realLatency.inMilliseconds.toDouble(); + + if (client case final NyxxGateway client) { + gatewayLatency!.labels([client.user.id.toString()]).value = client.gateway.latency.inMilliseconds.toDouble(); + for (final shard in client.gateway.shards) { + shardGatewayLatency!.labels([client.user.id.toString(), shard.id.toString()]).value = + shard.latency.inMilliseconds.toDouble(); + } + } + }); + } +} diff --git a/lib/nyxx_utils.dart b/lib/nyxx_utils.dart new file mode 100644 index 0000000..e69de29 diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..398832f --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,461 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + url: "https://pub.dev" + source: hosted + version: "1.7.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + eterl: + dependency: transitive + description: + name: eterl + sha256: "8669e5e766e6a1cb5593a0bee6ede7085c1a103056f1ea55cc227ee1ff32f6f7" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + http: + dependency: transitive + description: + name: http + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + http_methods: + dependency: transitive + description: + name: http_methods + sha256: "6bccce8f1ec7b5d701e7921dca35e202d425b57e317ba1a37f2638590e29e566" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + lints: + dependency: "direct dev" + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + meta: + dependency: transitive + description: + name: meta + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + nyxx: + dependency: "direct main" + description: + name: nyxx + sha256: "4e2ba8df35e0ee0de5c3dc61f4545f3caf8e8386be410e0257f8be8d831396c1" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + oauth2: + dependency: transitive + description: + name: oauth2 + sha256: c4013ef62be37744efdc0861878fd9e9285f34db1f9e331cc34100d7674feb42 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + prometheus_client: + dependency: "direct main" + description: + name: prometheus_client + sha256: "994b731e5b35f4666f50e804bc88a32f55ddcbc6dd2db707f4b8b3374c38f115" + url: "https://pub.dev" + source: hosted + version: "1.0.0+1" + prometheus_client_shelf: + dependency: "direct main" + description: + name: prometheus_client_shelf + sha256: "62e6911e97dccd9fbe8104ca0af47a631fae62d7eae7542278258cf5ca1633e9" + url: "https://pub.dev" + source: hosted + version: "1.0.0+1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + retry: + dependency: transitive + description: + name: retry + sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + runtime_type: + dependency: transitive + description: + name: runtime_type + sha256: "00e431718064e4512012a46e74ed94977ea4d86d83ae416e635092c50ad1397e" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + shelf: + dependency: "direct main" + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_router: + dependency: "direct main" + description: + name: shelf_router + sha256: f5e5d492440a7fb165fe1e2e1a623f31f734d3370900070b2b1e0d0428d59864 + url: "https://pub.dev" + source: hosted + version: "1.1.4" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" + url: "https://pub.dev" + source: hosted + version: "1.25.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + test_core: + dependency: transitive + description: + name: test_core + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: e7d5ecd604e499358c5fe35ee828c0298a320d54455e791e9dcf73486bc8d9f0 + url: "https://pub.dev" + source: hosted + version: "14.1.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" + url: "https://pub.dev" + source: hosted + version: "2.4.4" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.3.1 <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..8e9c50f --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,16 @@ +name: nyxx_utils +description: Collection of utilities for the nyxx library. +version: 1.0.0 + +environment: + sdk: ^3.3.1 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 +dependencies: + nyxx: ^6.1.0 + prometheus_client: ^1.0.0+1 + prometheus_client_shelf: ^1.0.0+1 + shelf: ^1.4.1 + shelf_router: ^1.1.4 diff --git a/test/nyxx_utils_test.dart b/test/nyxx_utils_test.dart new file mode 100644 index 0000000..e69de29