@@ -13,7 +13,6 @@ namespace Grid.Bot.Commands.Public;
13
13
using System . Text . RegularExpressions ;
14
14
15
15
using Discord ;
16
- using Discord . WebSocket ;
17
16
18
17
using Discord . Commands ;
19
18
@@ -39,7 +38,6 @@ namespace Grid.Bot.Commands.Public;
39
38
/// <param name="logger">The <see cref="ILogger"/>.</param>
40
39
/// <param name="gridSettings">The <see cref="GridSettings"/>.</param>
41
40
/// <param name="scriptsSettings">The <see cref="ScriptsSettings"/>.</param>
42
- /// <param name="discordClient">The <see cref="DiscordShardedClient"/>.</param>
43
41
/// <param name="luaUtility">The <see cref="ILuaUtility"/>.</param>
44
42
/// <param name="floodCheckerRegistry">The <see cref="IFloodCheckerRegistry"/>.</param>
45
43
/// <param name="backtraceUtility">The <see cref="IBacktraceUtility"/>.</param>
@@ -52,7 +50,6 @@ namespace Grid.Bot.Commands.Public;
52
50
/// - <paramref name="logger"/> cannot be null.
53
51
/// - <paramref name="gridSettings"/> cannot be null.
54
52
/// - <paramref name="scriptsSettings"/> cannot be null.
55
- /// - <paramref name="discordClient"/> cannot be null.
56
53
/// - <paramref name="luaUtility"/> cannot be null.
57
54
/// - <paramref name="floodCheckerRegistry"/> cannot be null.
58
55
/// - <paramref name="backtraceUtility"/> cannot be null.
@@ -66,7 +63,6 @@ public partial class ExecuteScript(
66
63
ILogger logger ,
67
64
GridSettings gridSettings ,
68
65
ScriptsSettings scriptsSettings ,
69
- DiscordShardedClient discordClient ,
70
66
ILuaUtility luaUtility ,
71
67
IFloodCheckerRegistry floodCheckerRegistry ,
72
68
IBacktraceUtility backtraceUtility ,
@@ -86,7 +82,6 @@ IGridServerFileHelper gridServerFileHelper
86
82
private readonly GridSettings _gridSettings = gridSettings ?? throw new ArgumentNullException ( nameof ( gridSettings ) ) ;
87
83
private readonly ScriptsSettings _scriptsSettings = scriptsSettings ?? throw new ArgumentNullException ( nameof ( scriptsSettings ) ) ;
88
84
89
- private readonly DiscordShardedClient _discordClient = discordClient ?? throw new ArgumentNullException ( nameof ( discordClient ) ) ;
90
85
private readonly ILuaUtility _luaUtility = luaUtility ?? throw new ArgumentNullException ( nameof ( luaUtility ) ) ;
91
86
private readonly IFloodCheckerRegistry _floodCheckerRegistry = floodCheckerRegistry ?? throw new ArgumentNullException ( nameof ( floodCheckerRegistry ) ) ;
92
87
private readonly IBacktraceUtility _backtraceUtility = backtraceUtility ?? throw new ArgumentNullException ( nameof ( backtraceUtility ) ) ;
@@ -96,7 +91,6 @@ IGridServerFileHelper gridServerFileHelper
96
91
private readonly IScriptLogger _scriptLogger = scriptLogger ?? throw new ArgumentNullException ( nameof ( scriptLogger ) ) ;
97
92
private readonly IGridServerFileHelper _gridServerFileHelper = gridServerFileHelper ?? throw new ArgumentNullException ( nameof ( gridServerFileHelper ) ) ;
98
93
99
-
100
94
[ GeneratedRegex ( @"```(.*?)\s(.*?)```" , RegexOptions . IgnoreCase | RegexOptions . Singleline ) ]
101
95
private static partial Regex CodeBlockRegex ( ) ;
102
96
[ GeneratedRegex ( "[\" “‘”]" , RegexOptions . IgnoreCase | RegexOptions . Compiled ) ]
@@ -112,13 +106,21 @@ protected override async Task BeforeExecuteAsync(CommandInfo command)
112
106
if ( ! _adminUtility . UserIsAdmin ( Context . User ) )
113
107
{
114
108
if ( _floodCheckerRegistry . ScriptExecutionFloodChecker . IsFlooded ( ) )
109
+ {
110
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsBlockedByGlobalFloodChecker . Inc ( ) ;
111
+
115
112
throw new ApplicationException ( "Too many people are using this command at once, please wait a few moments and try again." ) ;
113
+ }
116
114
117
115
_floodCheckerRegistry . RenderFloodChecker . UpdateCount ( ) ;
118
116
119
117
var perUserFloodChecker = _floodCheckerRegistry . GetPerUserScriptExecutionFloodChecker ( Context . User . Id ) ;
120
118
if ( perUserFloodChecker . IsFlooded ( ) )
119
+ {
120
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsBlockedByPerUserFloodChecker . WithLabels ( Context . User . Id . ToString ( ) ) . Inc ( ) ;
121
+
121
122
throw new ApplicationException ( "You are sending execute script commands too quickly, please wait a few moments and try again." ) ;
123
+ }
122
124
123
125
perUserFloodChecker . UpdateCount ( ) ;
124
126
}
@@ -152,6 +154,8 @@ private static string GetCodeBlockContents(string s)
152
154
// Check if the input matches grid syntax error
153
155
if ( GridSyntaxErrorRegex ( ) . IsMatch ( input ) )
154
156
{
157
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithSyntaxErrors . WithLabels ( "grid-server-syntax-error:metadata" ) . Inc ( ) ;
158
+
155
159
var match = GridSyntaxErrorRegex ( ) . Match ( input ) ;
156
160
var line = match . Groups [ 1 ] . Value ;
157
161
var error = match . Groups [ 2 ] . Value ;
@@ -167,7 +171,13 @@ private static string GetCodeBlockContents(string s)
167
171
var maxSize = _scriptsSettings . ScriptExecutionMaxFileSizeKb ;
168
172
169
173
if ( input . Length / 1000 > maxSize )
174
+ {
175
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithResultsExceedingMaxSize . WithLabels ( input . Length . ToString ( ) ) . Inc ( ) ;
176
+
170
177
return ( $ "The output cannot be larger than { maxSize } KiB", null ) ;
178
+ }
179
+
180
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithResultsViaFiles . Inc ( ) ;
171
181
172
182
return ( fileName , new MemoryStream ( Encoding . UTF8 . GetBytes ( input ) ) ) ;
173
183
}
@@ -187,7 +197,13 @@ private static string GetCodeBlockContents(string s)
187
197
var maxSize = _scriptsSettings . ScriptExecutionMaxResultSizeKb ;
188
198
189
199
if ( input . Length / 1000 > maxSize )
200
+ {
201
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithResultsExceedingMaxSize . WithLabels ( input . Length . ToString ( ) ) . Inc ( ) ;
202
+
190
203
return ( $ "The result cannot be larger than { maxSize } KiB", null ) ;
204
+ }
205
+
206
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithResultsViaFiles . Inc ( ) ;
191
207
192
208
return ( fileName , new MemoryStream ( Encoding . UTF8 . GetBytes ( input ) ) ) ;
193
209
}
@@ -210,9 +226,17 @@ private async Task HandleResponseAsync(string result, ReturnMetadata metadata)
210
226
. WithCurrentTimestamp ( ) ;
211
227
212
228
if ( metadata . Success )
229
+ {
230
+ ScriptExecutionPerformanceCounters . TotalSuccessfulScriptExecutions . Inc ( ) ;
231
+
213
232
builder . WithColor ( Color . Green ) ;
233
+ }
214
234
else
235
+ {
236
+ ScriptExecutionPerformanceCounters . TotalFailedScriptExecutionsDueToLuaError . Inc ( ) ;
237
+
215
238
builder . WithColor ( Color . Red ) ;
239
+ }
216
240
217
241
var ( fileNameOrOutput , outputFile ) = DetermineDescription (
218
242
metadata . Logs ,
@@ -234,6 +258,8 @@ private async Task HandleResponseAsync(string result, ReturnMetadata metadata)
234
258
235
259
builder . AddField ( "Execution Time" , $ "{ metadata . ExecutionTime : f5} s") ;
236
260
261
+ ScriptExecutionPerformanceCounters . ScriptExecutionAverageExecutionTime . Observe ( metadata . ExecutionTime ) ;
262
+
237
263
var attachments = new List < FileAttachment > ( ) ;
238
264
if ( outputFile != null )
239
265
attachments . Add ( new ( outputFile , fileNameOrOutput ) ) ;
@@ -270,6 +296,8 @@ private async Task<bool> ParseLuaAsync(string input)
270
296
271
297
if ( errors . Any ( ) )
272
298
{
299
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithSyntaxErrors . WithLabels ( "pre-parser-syntax-error" ) . Inc ( ) ;
300
+
273
301
var errorString = string . Join ( "\n " , errors . Select ( err => err . ToString ( ) ) ) ;
274
302
275
303
if ( errorString . Length > _maxErrorLength )
@@ -303,6 +331,8 @@ private async Task<bool> ParseLuaAsync(string input)
303
331
[ Command ( "execute" ) , Summary ( "Execute a script via raw text." ) , Alias ( "ex" , "exc" , "x" ) ]
304
332
public async Task ExecuteScriptFromTextAsync ( [ Remainder ] string script = "" )
305
333
{
334
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsByUser . WithLabels ( Context . User . Id . ToString ( ) ) . Inc ( ) ;
335
+
306
336
using var _ = Context . Channel . EnterTypingState ( ) ;
307
337
308
338
if ( string . IsNullOrWhiteSpace ( script ) )
@@ -331,13 +361,17 @@ public async Task ExecuteScriptFromTextAsync([Remainder] string script = "")
331
361
return ;
332
362
}
333
363
364
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsFromFiles . WithLabels ( file . Filename , file . Size . ToString ( ) ) . Inc ( ) ;
365
+
334
366
script = await file . GetAttachmentContentsAscii ( ) ;
335
367
}
336
368
337
369
script = GetCodeBlockContents ( script ) ;
338
370
339
371
if ( string . IsNullOrEmpty ( script ) )
340
372
{
373
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithNoContent . Inc ( ) ;
374
+
341
375
await LuaErrorAsync ( "There must be content within a code block!" ) ;
342
376
343
377
return ;
@@ -351,6 +385,8 @@ public async Task ExecuteScriptFromTextAsync([Remainder] string script = "")
351
385
352
386
if ( ContainsUnicode ( script ) )
353
387
{
388
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithUnicode . Inc ( ) ;
389
+
354
390
await LuaErrorAsync ( "Scripts can only contain ASCII characters!" ) ;
355
391
356
392
return ;
@@ -370,7 +406,11 @@ public async Task ExecuteScriptFromTextAsync([Remainder] string script = "")
370
406
) ;
371
407
372
408
if ( _scriptsSettings . LuaVMEnabled ) // Disable if pre-luau, or wait for the file to be updated to support pre-luau
409
+ {
410
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsUsingLuaVM . Inc ( ) ;
411
+
373
412
script = string . Format ( _luaUtility . LuaVMTemplate , script ) ;
413
+ }
374
414
375
415
#if ! PRE_JSON_EXECUTION
376
416
// isAdmin allows a bypass of disabled methods and virtualized globals
@@ -430,6 +470,8 @@ public async Task ExecuteScriptFromTextAsync([Remainder] string script = "")
430
470
var message = ex . Message ;
431
471
if ( GridSyntaxErrorRegex ( ) . IsMatch ( message ) )
432
472
{
473
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithSyntaxErrors . WithLabels ( "grid-server-syntax-error:fault" ) . Inc ( ) ;
474
+
433
475
var match = GridSyntaxErrorRegex ( ) . Match ( message ) ;
434
476
var line = match . Groups [ 1 ] . Value ;
435
477
var error = match . Groups [ 2 ] . Value ;
@@ -455,6 +497,8 @@ public async Task ExecuteScriptFromTextAsync([Remainder] string script = "")
455
497
456
498
if ( message . Contains ( _ErrorConvertingToJson ) )
457
499
{
500
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithNonJsonSerializableResults . Inc ( ) ;
501
+
458
502
await LuaErrorAsync ( "The script returned a value that could not be converted to JSON." ) ;
459
503
460
504
return ;
@@ -465,18 +509,24 @@ public async Task ExecuteScriptFromTextAsync([Remainder] string script = "")
465
509
// Catch this and alert the user (only in the case of ex is CommunicationException, ex.InnerException is InvalidOperationException and ex.InnerException.InnerException is XmlException)
466
510
if ( ex is CommunicationException && ex . InnerException is InvalidOperationException && ex . InnerException . InnerException is XmlException )
467
511
{
512
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithNonAsciiResults . Inc ( ) ;
513
+
468
514
await LuaErrorAsync ( "The script returned invalid ASCII characters." ) ;
469
515
470
516
return ;
471
517
}
472
518
473
519
if ( ex is TimeoutException )
474
520
{
521
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsThatTimedOut . Inc ( ) ;
522
+
475
523
await HandleResponseAsync ( null , new ( ) { ErrorMessage = "script exceeded timeout" , ExecutionTime = sw . Elapsed . TotalSeconds , Success = false } ) ;
476
524
477
525
return ;
478
526
}
479
527
528
+ ScriptExecutionPerformanceCounters . TotalScriptExecutionsWithUnexpectedExceptions . WithLabels ( ex . GetType ( ) . ToString ( ) ) . Inc ( ) ;
529
+
480
530
if ( ex is not Discord . Net . HttpException )
481
531
await AlertForSystem ( script , originalScript , scriptId , scriptName , ex ) ;
482
532
0 commit comments