Skip to content

Commit 46f3bbf

Browse files
committed
add new telemetry and triage logs
1 parent 387d314 commit 46f3bbf

File tree

8 files changed

+411
-310
lines changed

8 files changed

+411
-310
lines changed

Build.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,12 @@ def merge_source_files():
9898
file.write("{\n")
9999

100100
# Write the plugin first as our classes are defined inside of it.
101-
file.write(output["Tebex.cs"][:-2]) # remove the close curly brace to leave class definition open
101+
file.write(output["TebexPlugin.cs"][:-2]) # remove the close curly brace to leave class definition open
102102

103103
# Write the rest of our files
104104
for sourceFile in output.keys():
105-
if sourceFile != "Tebex.cs":
105+
if sourceFile != "TebexPlugin.cs":
106+
print("Writing " + sourceFile)
106107
file.write(output[sourceFile])
107108

108109
# Closing braces

TebexOxide/BaseTebexAdapter.cs

Lines changed: 131 additions & 135 deletions
Large diffs are not rendered by default.

TebexOxide/PluginEvent.cs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using System.Net;
2+
using Newtonsoft.Json;
3+
using Oxide.Core.Libraries;
4+
using Oxide.Plugins;
5+
using Tebex.Adapters;
6+
using Tebex.API;
7+
8+
namespace Tebex.Triage
9+
{
10+
public enum EnumEventLevel
11+
{
12+
INFO,
13+
WARNING,
14+
ERROR
15+
}
16+
17+
public class PluginEvent
18+
{
19+
// Data attached to all plugin events, set via Init()
20+
public static string SERVER_IP = "";
21+
public static string SERVER_ID = "";
22+
public static string STORE_URL = "";
23+
public static bool IS_DISABLED = false;
24+
25+
[JsonProperty("game_id")] private string GameId { get; set; }
26+
[JsonProperty("framework_id")] private string FrameworkId { get; set; }
27+
[JsonProperty("runtime_version")] private string RuntimeVersion { get; set; }
28+
29+
[JsonProperty("framework_version")]
30+
private string FrameworkVersion { get; set; }
31+
32+
[JsonProperty("plugin_version")] private string PluginVersion { get; set; }
33+
[JsonProperty("server_id")] private string ServerId { get; set; }
34+
[JsonProperty("event_message")] private string EventMessage { get; set; }
35+
[JsonProperty("event_level")] private String EventLevel { get; set; }
36+
[JsonProperty("metadata")] private Dictionary<string, string> Metadata { get; set; }
37+
[JsonProperty("trace")] private string Trace { get; set; }
38+
39+
[JsonProperty("store_url")] private string StoreUrl { get; set; }
40+
41+
[JsonProperty("server_ip")] private string ServerIp { get; set; }
42+
43+
[JsonIgnore]
44+
public TebexPlatform platform;
45+
46+
private TebexPlugin _plugin;
47+
48+
public PluginEvent(TebexPlugin plugin, TebexPlatform platform, EnumEventLevel level, string message)
49+
{
50+
_plugin = plugin;
51+
platform = platform;
52+
53+
TebexTelemetry tel = platform.GetTelemetry();
54+
55+
GameId = "Rust"; // always Rust
56+
FrameworkId = tel.GetServerSoftware(); // Oxide / Carbon
57+
RuntimeVersion = tel.GetRuntimeVersion(); // version of Rust
58+
FrameworkVersion = tel.GetServerVersion(); // version of Oxide
59+
PluginVersion = platform.GetPluginVersion(); // version of plugin
60+
EventLevel = level.ToString();
61+
EventMessage = message;
62+
Trace = "";
63+
ServerIp = PluginEvent.SERVER_IP;
64+
ServerId = PluginEvent.SERVER_ID;
65+
StoreUrl = PluginEvent.STORE_URL;
66+
}
67+
68+
public PluginEvent WithTrace(string trace)
69+
{
70+
Trace = trace;
71+
return this;
72+
}
73+
74+
public PluginEvent WithMetadata(Dictionary<string, string> metadata)
75+
{
76+
Metadata = metadata;
77+
return this;
78+
}
79+
80+
public void Send(BaseTebexAdapter adapter)
81+
{
82+
if (IS_DISABLED)
83+
{
84+
return;
85+
}
86+
87+
List<PluginEvent> eventsList = new List<PluginEvent>(); //TODO
88+
eventsList.Add(this);
89+
adapter.MakeWebRequest("https://plugin-logs.tebex.io/events", JsonConvert.SerializeObject(eventsList), TebexApi.HttpVerb.POST,
90+
(code, body) =>
91+
{
92+
if (code < 300 && code > 199) // success
93+
{
94+
adapter.LogDebug("Successfully sent plugin events");
95+
return;
96+
}
97+
98+
adapter.LogDebug("Failed to send plugin logs. Unexpected response code: " + code);
99+
adapter.LogDebug(body);
100+
}, (pluginLogsApiError) =>
101+
{
102+
adapter.LogDebug("Failed to send plugin logs. Unexpected Tebex API error: " + pluginLogsApiError);
103+
}, (pluginLogsServerErrorCode, pluginLogsServerErrorResponse) =>
104+
{
105+
adapter.LogDebug("Failed to send plugin logs. Unexpected server error: " + pluginLogsServerErrorResponse);
106+
});
107+
}
108+
}
109+
}

TebexOxide/TebexOxideAdapter.cs

Lines changed: 66 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
using Oxide.Core.Libraries.Covalence;
44
using Tebex.API;
55
using Tebex.Triage;
6+
using UnityEngine;
67

78
namespace Tebex.Adapters
89
{
910
public class TebexOxideAdapter : BaseTebexAdapter
1011
{
11-
public static Oxide.Plugins.Tebex Plugin { get; private set; }
12+
public static Oxide.Plugins.TebexPlugin Plugin { get; private set; }
1213

13-
public TebexOxideAdapter(Oxide.Plugins.Tebex plugin)
14+
public TebexOxideAdapter(Oxide.Plugins.TebexPlugin plugin)
1415
{
1516
Plugin = plugin;
1617
}
@@ -43,16 +44,47 @@ public override void Init()
4344
});
4445
}
4546

46-
public override void LogWarning(string message)
47+
public override void LogWarning(string message, string solution)
4748
{
4849
Plugin.Warn(message);
50+
Plugin.Warn("- " + solution);
51+
52+
if (PluginConfig.AutoReportingEnabled)
53+
{
54+
new PluginEvent(Plugin, Plugin.GetPlatform(Plugin.Server()), EnumEventLevel.WARNING, message).Send(this);
55+
}
4956
}
5057

58+
public override void LogWarning(string message, string solution, Dictionary<String, String> metadata)
59+
{
60+
Plugin.Warn(message);
61+
Plugin.Warn("- " + solution);
62+
63+
if (PluginConfig.AutoReportingEnabled)
64+
{
65+
new PluginEvent(Plugin, Plugin.GetPlatform(Plugin.Server()), EnumEventLevel.WARNING, message).WithMetadata(metadata).Send(this);
66+
}
67+
}
68+
5169
public override void LogError(string message)
5270
{
5371
Plugin.Error(message);
72+
73+
if (PluginConfig.AutoReportingEnabled)
74+
{
75+
new PluginEvent(Plugin, Plugin.GetPlatform(Plugin.Server()), EnumEventLevel.ERROR, message).Send(this);
76+
}
5477
}
5578

79+
public override void LogError(string message, Dictionary<String, String> metadata)
80+
{
81+
Plugin.Error(message);
82+
if (PluginConfig.AutoReportingEnabled)
83+
{
84+
new PluginEvent(Plugin, Plugin.GetPlatform(Plugin.Server()), EnumEventLevel.ERROR, message).WithMetadata(metadata).Send(this);
85+
}
86+
}
87+
5688
public override void LogInfo(string message)
5789
{
5890
Plugin.Info(message);
@@ -152,6 +184,7 @@ public override void MakeWebRequest(string endpoint, string body, TebexApi.HttpV
152184
// We should never have an HTML response passed to callback functions which might assume is JSON
153185
if (body.Contains("DOCTYPE html") || body.StartsWith("<html"))
154186
{
187+
155188
LogDebug("> Unexpected html response from web request!");
156189
return;
157190
}
@@ -164,16 +197,13 @@ public override void MakeWebRequest(string endpoint, string body, TebexApi.HttpV
164197
{
165198
if (url.Contains(TebexApi.TebexApiBase))
166199
{
167-
LogError("Your server's secret key is either not set or incorrect.");
168-
LogError("tebex.secret <key>\" to set your secret key to the one associated with your webstore.");
169-
LogError("Set up your store and get your secret key at https://tebex.io/");
200+
LogWarning("Your server's secret key is either not set or incorrect.", "Use /tebex.secret <key> to set your secret key.");
170201
}
171202
}
172203
else if (code == 429) // Rate limited
173204
{
174205
// Rate limits sent from Tebex enforce a 5 minute cooldown.
175-
LogWarning("We are being rate limited by Tebex API. If this issue continues, please report a problem.");
176-
LogWarning("Requests will resume after 5 minutes.");
206+
LogInfo("We are being rate limited by Tebex API. Requests will resume after 5 minutes.");
177207
Plugin.PluginTimers().Once(60 * 5, () =>
178208
{
179209
LogDebug("Rate limit timer has elapsed.");
@@ -182,15 +212,10 @@ public override void MakeWebRequest(string endpoint, string body, TebexApi.HttpV
182212
}
183213
else if (code == 500)
184214
{
185-
ReportAutoTriageEvent(TebexTriage.CreateAutoTriageEvent("Internal server error from Plugin API",
186-
new Dictionary<string, string>
187-
{
188-
{ "request", logOutStr },
189-
{ "response", logInStr },
190-
}));
191-
LogDebug(
192-
"Internal Server Error from Tebex API. Please try again later. Error details follow below.");
193-
LogDebug(response);
215+
LogError("Internal Server Error from Tebex API. " + response, new Dictionary<string, string>()
216+
{
217+
{"response", response}
218+
});
194219
onServerError?.Invoke(code, response);
195220
}
196221
else if (code == 530) // Cloudflare origin error
@@ -201,13 +226,11 @@ public override void MakeWebRequest(string endpoint, string body, TebexApi.HttpV
201226
}
202227
else if (code == 0)
203228
{
204-
ReportAutoTriageEvent(TebexTriage.CreateAutoTriageEvent("Request timeout to Plugin API",
205-
new Dictionary<string, string>
206-
{
207-
{ "request", logOutStr },
208-
{ "response", logInStr },
209-
}));
210-
LogDebug("Request Timeout from Tebex API. Please try again later.");
229+
LogWarning("Request timeout to plugin API", "Please try again. Automated requests will re-run at the next command check.", new Dictionary<string, string>
230+
{
231+
{ "request", logOutStr },
232+
{ "response", logInStr },
233+
});
211234
}
212235
else // This should be a general failure error message with a JSON-formatted response from the API.
213236
{
@@ -216,23 +239,21 @@ public override void MakeWebRequest(string endpoint, string body, TebexApi.HttpV
216239
var error = JsonConvert.DeserializeObject<TebexApi.TebexError>(response);
217240
if (error != null)
218241
{
219-
ReportAutoTriageEvent(TebexTriage.CreateAutoTriageEvent(
220-
"Plugin API reported general failure", new Dictionary<string, string>
221-
{
222-
{ "request", logOutStr },
223-
{ "error", error.ErrorMessage },
224-
}));
242+
LogError("API request failed: " + error.ErrorMessage, new Dictionary<string, string>
243+
{
244+
{ "request", logOutStr },
245+
{ "response", response },
246+
{ "error", error.ErrorMessage },
247+
});
225248
onApiError?.Invoke(error);
226249
}
227250
else
228251
{
229-
ReportAutoTriageEvent(TebexTriage.CreateAutoTriageEvent(
230-
"Plugin API error could not be interpreted!", new Dictionary<string, string>
252+
LogError("Plugin API error could not be interpreted!", new Dictionary<string, string>
231253
{
232254
{ "request", logOutStr },
233-
{ "response", logInStr },
234-
}));
235-
LogDebug($"Failed to unmarshal an expected error response from API.");
255+
{ "response", response },
256+
});
236257
onServerError?.Invoke(code, response);
237258
}
238259

@@ -241,12 +262,11 @@ public override void MakeWebRequest(string endpoint, string body, TebexApi.HttpV
241262
}
242263
catch (Exception e) // Something really unexpected with our response and it's likely not JSON
243264
{
244-
ReportAutoTriageEvent(TebexTriage.CreateAutoTriageEvent(
245-
"Did not handle error response from API", new Dictionary<string, string>
265+
LogError("Did not handle error response from API", new Dictionary<string, string>
246266
{
247267
{ "request", logOutStr },
248268
{ "response", logInStr },
249-
}));
269+
});
250270

251271
LogDebug("Could not gracefully handle error response.");
252272
LogDebug($"Response from remote {response}");
@@ -357,11 +377,11 @@ public override bool ExecuteOnlineCommand(TebexApi.Command command, object playe
357377
// Some commands have slot requirements, don't execute those if the player can't accept it
358378
if (slotsAvailable < command.Conditions.Slots)
359379
{
360-
LogWarning($"> Player has command {command.CommandToRun} but not enough main inventory slots. Need {command.Conditions.Slots} empty slots.");
380+
LogWarning($"> Player has command {command.CommandToRun} but not enough main inventory slots.", "Need {command.Conditions.Slots} empty slots.");
361381
return false;
362382
}
363383
#else
364-
LogWarning($"> Command has slots condition, but slots are not supported in this game.");
384+
LogWarning($"> Command has slots condition, but slots are not supported in this game.", "Remove the slots condition to suppress this message.");
365385
#endif
366386
}
367387

@@ -382,14 +402,12 @@ public override bool ExecuteOnlineCommand(TebexApi.Command command, object playe
382402
}
383403
catch (Exception e)
384404
{
385-
ReportAutoTriageEvent(TebexTriage.CreateAutoTriageEvent("Caused exception while executing online command", new Dictionary<string, string>()
405+
LogError("Caused exception while executing online command", new Dictionary<string, string>()
386406
{
387407
{"command", command.CommandToRun},
388408
{"exception", e.Message},
389409
{"trace", e.StackTrace},
390-
}));
391-
LogError("Failed to run online command due to exception. Command run is aborted.");
392-
LogError(e.ToString());
410+
});
393411
return false;
394412
}
395413

@@ -418,26 +436,22 @@ public override string ExpandUsernameVariables(string input, object playerObj)
418436
IPlayer iPlayer = playerObj as IPlayer;
419437
if (iPlayer == null)
420438
{
421-
LogError($"Could not cast player instance when expanding username variables: {playerObj}");
422-
ReportAutoTriageEvent(TebexTriage.CreateAutoTriageEvent("Could not cast player instance when expanding username variables", new Dictionary<string, string>
439+
LogError($"Could not cast player instance when expanding username variables: {playerObj}", new Dictionary<string, string>
423440
{
424441
{"input", input},
425442
{"playerObj", playerObj?.ToString()},
426-
}));
443+
});
427444
return input;
428445
}
429446

430447
if (input.Contains("{username}") && string.IsNullOrEmpty(iPlayer.Name))
431448
{
432-
LogError($"Player name is null while expanding username?!: {iPlayer}");
433-
LogError($"Base player object: {playerObj}");
434-
LogError($"Input command: {input}");
435-
ReportAutoTriageEvent(TebexTriage.CreateAutoTriageEvent("Player ID is null while expanding username?!: ", new Dictionary<string, string>
449+
LogError("Player ID is null while expanding username?!: ", new Dictionary<string, string>
436450
{
437451
{"input", input},
438452
{"iPlayer.Id", iPlayer.Id},
439453
{"iPlayer.Name", iPlayer.Name}
440-
}));
454+
});
441455
return input;
442456
}
443457

@@ -455,15 +469,5 @@ public override string ExpandUsernameVariables(string input, object playerObj)
455469

456470
return parsed;
457471
}
458-
459-
public override TebexTriage.AutoTriageEvent FillAutoTriageParameters(TebexTriage.AutoTriageEvent partialEvent)
460-
{
461-
partialEvent.GameId = $"{Plugin.GetGame()} {Plugin.Server().Version} | {Plugin.Server().Protocol}";
462-
partialEvent.FrameworkId = "Oxide";
463-
partialEvent.PluginVersion = Oxide.Plugins.Tebex.GetPluginVersion();
464-
partialEvent.ServerIp = Plugin.Server().Address.ToString();
465-
466-
return partialEvent;
467-
}
468472
}
469473
}

0 commit comments

Comments
 (0)