From e454d4cedc9b1648ede65fec30741cf4d5054f36 Mon Sep 17 00:00:00 2001 From: Cold-Mint Date: Mon, 15 Jul 2024 22:36:48 +0800 Subject: [PATCH] =?UTF-8?q?Log=20upload=20to=20the=20server=20is=20support?= =?UTF-8?q?ed.=20=E6=94=AF=E6=8C=81=E5=B0=86=E6=97=A5=E5=BF=97=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E5=88=B0=E6=9C=8D=E5=8A=A1=E5=99=A8=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + ColdMint.Traveler.csproj | 2 + README.md | 28 ++++ README_JA.md | 28 ++++ README_ZH.md | 28 ++++ locals/Log.csv | 8 +- scripts/AppConfig.cs | 82 ++++++++++ scripts/Config.cs | 6 + scripts/bubble/BubbleMarker.cs | 4 +- scripts/camp/CampManager.cs | 2 +- scripts/character/CharacterTemplate.cs | 4 +- scripts/character/Player.cs | 2 +- scripts/debug/LogCat.cs | 142 +++++++++--------- scripts/inventory/ItemTypeRegister.cs | 14 +- scripts/loader/uiLoader/MainMenuLoader.cs | 6 + scripts/loot/LootList.cs | 6 +- scripts/map/MapGenerator.cs | 10 +- scripts/map/room/Room.cs | 4 +- scripts/openObserve/LogCollector.cs | 139 +++++++++++++++++ scripts/stateMachine/IStateContext.cs | 2 +- scripts/stateMachine/StateMachineTemplate.cs | 2 +- .../StateProcessor/PatrolStateProcessor.cs | 6 +- scripts/utils/NodeUtils.cs | 3 +- scripts/utils/TimeUtils.cs | 2 +- 24 files changed, 433 insertions(+), 98 deletions(-) create mode 100644 scripts/AppConfig.cs create mode 100644 scripts/openObserve/LogCollector.cs diff --git a/.gitignore b/.gitignore index 1ebcbdd..dbf6167 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ export_presets.cfg .vs/ *.translation *.user +AppConfig.yaml \ No newline at end of file diff --git a/ColdMint.Traveler.csproj b/ColdMint.Traveler.csproj index 9ba3342..c8681d1 100644 --- a/ColdMint.Traveler.csproj +++ b/ColdMint.Traveler.csproj @@ -10,6 +10,8 @@ + + \ No newline at end of file diff --git a/README.md b/README.md index 60c9eb4..845c392 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,34 @@ You need to fill in the Export Presets > Resources > Filter to export non-resour data/* ``` +## Configuring Openobserve + +> This is optional, and the game will work even if you do not configure Openobserve. + +openobserve is used to continuously collect logs and alarm information after a game has been released. + +#### Set up the openobserve server + +see:[openobserve](https://github.com/openobserve/openobserve) + +#### Write configuration + +After you have set up an openobserve server, follow the following steps to configure the file: + +1. Create a configuration file named **AppConfig.yaml** in the root directory of your project. + +2. Fill in the information for the remote server. + + ```yaml + open_observe: + address: [address] + access_token: [token] + org_id: [org_id] + stream_name: [stream_name] + ``` + + address Indicates the address of the server in the format of http(s)://www.example.com. (Support http and https) + ## Participate in translation The project is prepared for localization at the beginning of writing. You can edit the csv file in the locals directory. To modify and add new translations. diff --git a/README_JA.md b/README_JA.md index 3ba5955..0608bf5 100644 --- a/README_JA.md +++ b/README_JA.md @@ -50,6 +50,34 @@ git clone https://github.com/Cold-Mint/Traveller.git data/* ``` +## はいちOpenobserve + +> これはオプションなので、Openobserveを設定しなくてもゲームは正常に動作します。 + +openobserveは、リリース後にログやアラームを継続的に収集するために使用されます。 + +#### 搭建openobserve衣服务器 + +読み過ごす:[openobserve](https://github.com/openobserve/openobserve) + +#### 構成を書きます + +openobserveのサーバーを構築したら、次のようにファイルを設定します。 + +1. プロジェクトのルートディレクトリに**AppConfig.yaml **というプロファイルを作成します。 + +2. リモートサーバーの情報を入力します。 + + ```yaml + open_observe: + address: [address] + access_token: [token] + org_id: [org_id] + stream_name: [stream_name] + ``` + + address サーバーのアドレス、フォーマットはこうなります http(s)://www.example.com。(支持http和https) + ## 翻訳に携わります このプロジェクトは、当初からローカライズの準備ができていました。localsディレクトリのcsvファイルを編集することができます。新しい翻訳を加えたり修正したりしています diff --git a/README_ZH.md b/README_ZH.md index 83a0c80..5cef5e2 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -52,6 +52,34 @@ git clone https://github.com/Cold-Mint/Traveller.git data/* ``` +## 配置Openobserve + +> 这是可选的操作,即使您不配置Openobserve,游戏也能正常运行。 + +openobserve用于在游戏发布后,持续收集日志和报警信息。 + +#### 搭建openobserve服务器 + +请见:[openobserve](https://github.com/openobserve/openobserve) + +#### 编写配置 + +在您搭建完毕openobserve的服务器后,按如下步骤配置文件: + +1. 在项目的根目录创建名为**AppConfig.yaml**的配置文件。 + +2. 填入远程服务器的信息。 + + ```yaml + open_observe: + address: [address] + access_token: [token] + org_id: [org_id] + stream_name: [stream_name] + ``` + + address 服务器的地址,格式为 http(s)://www.example.com。(支持http和https) + ## 参与翻译 此项目在编写之初就为本地化做好了准备。您可以编辑locals目录下的csv文件。来修改和添加新的翻译。 diff --git a/locals/Log.csv b/locals/Log.csv index 7186f21..f23d688 100644 --- a/locals/Log.csv +++ b/locals/Log.csv @@ -23,7 +23,7 @@ log_player_packed_scene_not_exist,玩家预制场景不存在。,Player packed s log_exit_the_room_debug,节点{0}退出房间{1}。,"Node {0} exits room {1}.",ノード{0}が部屋{1}を退出します。 log_enter_the_room_debug,节点{0}进入房间{1}。,"Node {0} enters room {1}.",ノード{0}が部屋{1}に入ります。 log_death_info,生物{0}被{1}击败。,"Creature {0} was defeated by {1}.",生物{0}が{1}によって打ち負かされました。 - +log_appConfig_not_exist,您可以在项目根目录创建名为AppConfig.yaml的文件,并在其中配置OpenObserve的数据,以便在游戏发布后持续收集日志和运行数据。,You can create a file named AppConfig.yaml in the project root directory and configure OpenObserve data in it to collect log and run data continuously after the game has been released.,プロジェクトのルートディレクトリにappconfig.yamlというファイルを作成し、そこにOpenObserveのデータを配置して、リリース後も継続的にログや実行データを収集することができます。 log_loot_list_has_no_entries,ID为{0}的战利品表,没有指定条目。,"Loot list with ID {0}, no entry specified.",ID{0}の戦利品テーブルは、エントリ指定されていません。 log_not_within_the_loot_spawn_range,给定的数值{0}没有在战利品{1}的生成范围{2}内。,The given value {0} is not within the spawn range {2} of loot {1}.,与えられた数値{0}は戦利品{1}の生成範囲{2}内にありません。 log_loot_data_quantity,有{0}个战利品数据被返回。,{0} loot data was returned.,{0}個の戦利品データが返されます。 @@ -75,4 +75,8 @@ log_owner_is_not_AiCharacter,所有者不是AiCharacter。,Owner is not AiCharac log_weaponContainer_is_null,武器容器为空。,Weapon container is null.,武器コンテナが空です。 log_find_nearest_item,查找最近的物品。,Find the nearest item.,最も近いアイテムを見つけます。 log_float_label_instantiate_failed,浮动标签实例化失败。,Float label instantiation failed.,フロートラベルのインスタンス化に失敗しました。 -log_pickable_picked_up,可拾捡物被捡起了,那么不显示标签。,"If the pickable item is picked up, the label is not displayed.",でも、拾得物が拾い上げられたら、ラベルは表示されません。 \ No newline at end of file +log_pickable_picked_up,可拾捡物被捡起了,那么不显示标签。,"If the pickable item is picked up, the label is not displayed.",でも、拾得物が拾い上げられたら、ラベルは表示されません。 +log_start_uploading,开始上传{0}条日志。,Start uploading {0} logs.,{0}個のログをアップロードを開始します。 +log_upload_successful,上传成功,已上传{0}条日志,剩余{1}条日志待上传。,"Upload successful, {0} logs uploaded, {1} logs remaining.",アップロードが成功しました、{0}個のログがアップロードされ、{1}個のログが残っています。 +log_upload_failed,上传失败,错误代码:{0},剩余{1}条日志待上传。,"Upload failed, error code: {0}, {1} logs remaining.",アップロードに失敗しました、エラーコード:{0}、{1}個のログが残っています。 +log_upload_status,已记录{0}条日志,上传阈值为{1}。,"{0} logs recorded, upload threshold is {1}.",{0}個のログが記録され、アップロード閾値は{1}です。 \ No newline at end of file diff --git a/scripts/AppConfig.cs b/scripts/AppConfig.cs new file mode 100644 index 0000000..9b19987 --- /dev/null +++ b/scripts/AppConfig.cs @@ -0,0 +1,82 @@ +using ColdMint.scripts.debug; +using ColdMint.scripts.openObserve; +using ColdMint.scripts.serialization; +using Godot; + +namespace ColdMint.scripts; + +public class AppConfig +{ + /// + /// Load configuration from file + /// 从文件加载配置 + /// + public static AppConfigData? LoadFromFile() + { + var appConfigExists = FileAccess.FileExists(Config.AppConfigPath); + if (!appConfigExists) + { + LogCat.LogWarning("appConfig_not_exist"); + return null; + } + + var appConfigFileAccess = FileAccess.Open(Config.AppConfigPath, FileAccess.ModeFlags.Read); + var yamlData = appConfigFileAccess.GetAsText(); + appConfigFileAccess.Close(); + return YamlSerialization.Deserialize(yamlData); + } + + + /// + /// ApplyAppConfig + /// 应用配置 + /// + /// + public static void ApplyAppConfig(AppConfigData appConfigData) + { + if (appConfigData.OpenObserve != null) + { + LogCollector.UpdateHttpClient(appConfigData.OpenObserve); + } + } +} + +public class AppConfigData +{ + /// + /// OpenObserve configuration information + /// OpenObserve的配置信息 + /// + public OpenObserve? OpenObserve { get; set; } +} + +/// +/// OpenObserve Configuration information +/// OpenObserve配置信息 +/// +public class OpenObserve +{ + /// + /// server address + /// 服务器地址 + /// + public string? Address { get; set; } + + /// + /// Access Token + /// 访问密匙 + /// + public string? AccessToken { get; set; } + + /// + /// Organization ID + /// 组织ID + /// + public string? OrgId { get; set; } + + /// + /// Stream Name + /// 流名称 + /// + public string? StreamName { get; set; } +} \ No newline at end of file diff --git a/scripts/Config.cs b/scripts/Config.cs index fa14572..d626cbb 100644 --- a/scripts/Config.cs +++ b/scripts/Config.cs @@ -85,6 +85,12 @@ public static class Config public const string Aborigines = "Aborigines"; } + /// + /// Path of the App configuration file + /// App配置文件路径 + /// + public const string AppConfigPath = "res://AppConfig.yaml"; + /// /// The percentage of speed reduced after a thrown item hits an enemy /// 抛出的物品击中敌人后减少的速度百分比 diff --git a/scripts/bubble/BubbleMarker.cs b/scripts/bubble/BubbleMarker.cs index 263f72b..959e2c6 100644 --- a/scripts/bubble/BubbleMarker.cs +++ b/scripts/bubble/BubbleMarker.cs @@ -45,7 +45,7 @@ public partial class BubbleMarker : Marker2D { if (!_bubbleDictionary.TryGetValue(id, out var value)) { - LogCat.LogErrorWithFormat("bubble_not_found", LogCat.LogLabel.BubbleMarker, id); + LogCat.LogErrorWithFormat("bubble_not_found", LogCat.LogLabel.BubbleMarker, LogCat.UploadFormat,id); return; } @@ -60,7 +60,7 @@ public partial class BubbleMarker : Marker2D { if (!_bubbleDictionary.TryGetValue(id, out var value)) { - LogCat.LogErrorWithFormat("bubble_not_found", LogCat.LogLabel.BubbleMarker, id); + LogCat.LogErrorWithFormat("bubble_not_found", LogCat.LogLabel.BubbleMarker, LogCat.UploadFormat,id); return; } diff --git a/scripts/camp/CampManager.cs b/scripts/camp/CampManager.cs index c944ec8..3ee99c3 100644 --- a/scripts/camp/CampManager.cs +++ b/scripts/camp/CampManager.cs @@ -40,7 +40,7 @@ public static class CampManager if (camp.Id != Config.CampId.Default) return false; _defaultCamp = camp; AddCamp(camp); - LogCat.LogWithFormat("set_default_camp", label: LogCat.LogLabel.CampManager, camp.Id); + LogCat.LogWithFormat("set_default_camp", label: LogCat.LogLabel.CampManager, LogCat.UploadFormat, camp.Id); return true; } diff --git a/scripts/character/CharacterTemplate.cs b/scripts/character/CharacterTemplate.cs index 0a540dd..baf6e6f 100644 --- a/scripts/character/CharacterTemplate.cs +++ b/scripts/character/CharacterTemplate.cs @@ -585,12 +585,12 @@ public partial class CharacterTemplate : CharacterBody2D if (damageTemplate.Attacker is CharacterTemplate characterTemplate && !string.IsNullOrEmpty(characterTemplate.CharacterName)) { - LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, CharacterName, + LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, LogCat.UploadFormat,CharacterName, characterTemplate.CharacterName); } else { - LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, CharacterName, + LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, LogCat.UploadFormat,CharacterName, damageTemplate.Attacker.Name); } } diff --git a/scripts/character/Player.cs b/scripts/character/Player.cs index 380ee9e..384161b 100644 --- a/scripts/character/Player.cs +++ b/scripts/character/Player.cs @@ -48,7 +48,7 @@ public partial class Player : CharacterTemplate { base._Ready(); CharacterName = TranslationServerUtils.Translate("default_player_name"); - LogCat.LogWithFormat("player_spawn_debug", LogCat.LogLabel.Default, ReadOnlyCharacterName, + LogCat.LogWithFormat("player_spawn_debug", LogCat.LogLabel.Default, LogCat.UploadFormat,ReadOnlyCharacterName, GlobalPosition); var floatLabelPackedScene = GD.Load("res://prefab/ui/FloatLabel.tscn"); //Initializes the float label. diff --git a/scripts/debug/LogCat.cs b/scripts/debug/LogCat.cs index b59e859..bd82d75 100644 --- a/scripts/debug/LogCat.cs +++ b/scripts/debug/LogCat.cs @@ -1,8 +1,12 @@ using System; using System.Collections.Generic; using System.Text; +using ColdMint.scripts.openObserve; using ColdMint.scripts.utils; using Godot; +using Microsoft.Extensions.Logging; +using OpenTelemetry.Exporter; +using OpenTelemetry.Logs; namespace ColdMint.scripts.debug; @@ -27,19 +31,19 @@ public static class LogCat /// 阵营管理器 /// public const string CampManager = "CampManager"; - + /// /// State context /// 状态上下文 /// public const string StateContext = "StateContext"; - + /// /// StateMachineTemplate /// 状态机模板 /// public const string StateMachineTemplate = "StateMachineTemplate"; - + /// /// Pursuit enemy processor /// 追击敌人处理器 @@ -50,7 +54,13 @@ public static class LogCat /// BubbleMarker /// 气泡标记 /// - public static string BubbleMarker = "BubbleMarker"; + public const string BubbleMarker = "BubbleMarker"; + + /// + /// LogCollector + /// 日志收集器 + /// + public const string LogCollector = "LogCollector"; } @@ -94,6 +104,12 @@ public static class LogCat set => _minLogLevel = value; } + /// + /// Whether to upload logs that need to be formatted by default + /// 是否默认上传需要格式化的日志 + /// + public static bool UploadFormat { get; set; } = true; + private static readonly StringBuilder StringBuilder = new StringBuilder(); /// @@ -103,6 +119,25 @@ public static class LogCat private static HashSet DisabledLogLabels { get; } = []; + public static void Init() + { + var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddOpenTelemetry(options => { options.AddOtlpExporter(OtlpExporterOptions); }); + }); + var logger = loggerFactory.CreateLogger("323"); + logger.Log(LogLevel.Debug, "你好"); + } + + public static void OtlpExporterOptions(OtlpExporterOptions options) + { + options.Protocol = OtlpExportProtocol.HttpProtobuf; + options.Endpoint = new Uri("http://test.coldmint.top/api/default/traces"); + options.Headers = + "Authorization=Basic cm9vdEBleGFtcGxlLmNvbTp5V0kwVzZYcWhteTBzQml3,organization=default,stream-name=default"; + } + + /// /// Disable log Label /// 禁用某个日志标签 @@ -194,7 +229,14 @@ public static class LogCat /// /// /// - public static void Log(string message, string label = LogLabel.Default) + /// + /// + public static void Log(string message, string label = LogLabel.Default, bool upload = true) + { + PrintLog(InfoLogLevel, HandleMessage(InfoLogLevel, message, label).ToString(), label, upload); + } + + private static void PrintLog(int level, string concreteLog, string label, bool upload) { if (!IsEnabledLogLabel(label)) { @@ -206,7 +248,18 @@ public static class LogCat return; } - GD.Print(HandleMessage(InfoLogLevel, message, label)); + if (LogCollector.CanUploadLog && upload) + { + var logData = new LogData + { + Level = level, + Message = concreteLog, + AppId = "none" + }; + LogCollector.Push(logData); + } + + GD.Print(concreteLog); } /// @@ -220,80 +273,34 @@ public static class LogCat /// 这个消息支持本地化输出,假设已存在翻译key,Hello = 你好,传入Hello则会输出你好。 /// /// - public static void LogError(string message, string label = LogLabel.Default) + /// + public static void LogError(string message, string label = LogLabel.Default, bool upload = true) { - if (!IsEnabledLogLabel(label)) - { - return; - } - - if (_minLogLevel > ErrorLogLevel) - { - return; - } - - GD.PrintErr(HandleMessage(ErrorLogLevel, message, label)); + PrintLog(ErrorLogLevel, HandleMessage(ErrorLogLevel, message, label).ToString(), label, upload); } - public static void LogWarning(string message, string label = LogLabel.Default) + public static void LogWarning(string message, string label = LogLabel.Default, bool upload = true) { - if (!IsEnabledLogLabel(label)) - { - return; - } - - if (_minLogLevel > WarningLogLevel) - { - return; - } - - GD.Print(HandleMessage(WarningLogLevel, message, label)); + PrintLog(WarningLogLevel, HandleMessage(WarningLogLevel, message, label).ToString(), label, upload); } - public static void LogErrorWithFormat(string message, string label, params object?[] args) + public static void LogErrorWithFormat(string message, string label, bool upload, params object?[] args) { - if (!IsEnabledLogLabel(label)) - { - return; - } - - if (_minLogLevel > ErrorLogLevel) - { - return; - } - - GD.PrintErr(string.Format(HandleMessage(ErrorLogLevel, message, label).ToString(), args)); + PrintLog(WarningLogLevel, string.Format(HandleMessage(ErrorLogLevel, message, label).ToString(), args), label, + upload); } - public static void LogWithFormat(string message, string label, params object?[] args) + public static void LogWithFormat(string message, string label, bool upload, params object?[] args) { - if (!IsEnabledLogLabel(label)) - { - return; - } - - if (_minLogLevel > InfoLogLevel) - { - return; - } - - GD.Print(string.Format(HandleMessage(InfoLogLevel, message, label).ToString(), args)); + PrintLog(InfoLogLevel, string.Format(HandleMessage(InfoLogLevel, message, label).ToString(), args), label, + upload); } - public static void LogWarningWithFormat(string message, string label, params object?[] args) + public static void LogWarningWithFormat(string message, bool upload, string label, params object?[] args) { - if (!IsEnabledLogLabel(label)) - { - return; - } - - if (_minLogLevel > InfoLogLevel) - { - return; - } - - GD.Print(string.Format(HandleMessage(WarningLogLevel, message, label).ToString(), args)); + PrintLog(WarningLogLevel, string.Format(HandleMessage(WarningLogLevel, message, label).ToString(), args), label, + upload); } /// @@ -311,6 +318,7 @@ public static class LogCat //Log an exception here or send it to the server. //请在这里记录异常或将异常发送至服务器。 - GD.PrintErr(HandleMessage(ErrorLogLevel, e.Message, label).Append('\n').Append(e.StackTrace)); + PrintLog(ErrorLogLevel, + HandleMessage(ErrorLogLevel, e.Message, label).Append('\n').Append(e.StackTrace).ToString(), label, true); } } \ No newline at end of file diff --git a/scripts/inventory/ItemTypeRegister.cs b/scripts/inventory/ItemTypeRegister.cs index 3a55fd4..7ab2fed 100644 --- a/scripts/inventory/ItemTypeRegister.cs +++ b/scripts/inventory/ItemTypeRegister.cs @@ -36,7 +36,7 @@ public static class ItemTypeRegister var error = DirAccess.GetOpenError(); if (error is not Error.Ok) { - LogCat.LogError("error_when_open_item_regs_dir",error.ToString()); + LogCat.LogError("error_when_open_item_regs_dir", error.ToString()); } //找到文件 @@ -44,16 +44,16 @@ public static class ItemTypeRegister var files = itemRegsDir.GetFiles(); if (files == null) { - LogCat.LogWithFormat("found_files", LogCat.LogLabel.Default, 0); + LogCat.LogWithFormat("found_files", LogCat.LogLabel.Default, LogCat.UploadFormat, 0); return; } - LogCat.LogWithFormat("found_files", LogCat.LogLabel.Default, files.Length); + LogCat.LogWithFormat("found_files", LogCat.LogLabel.Default, LogCat.UploadFormat, files.Length); //将文件解析为项目类型信息 //parse files to item type infos IEnumerable typeInfos = files.SelectMany(file => ParseFile($"{itemRegsDirPath}/{file}")).ToList(); - LogCat.LogWithFormat("found_item_types", LogCat.LogLabel.Default, typeInfos.Count()); + LogCat.LogWithFormat("found_item_types", LogCat.LogLabel.Default, LogCat.UploadFormat, typeInfos.Count()); //遍历类型信息并注册它们。 //traverse type infos and register them. @@ -120,7 +120,8 @@ public static class ItemTypeRegister }, icon, typeInfo.MaxStackValue); var succeed = ItemTypeManager.Register(itemType); - LogCat.LogWithFormat("register_item", label: LogCat.LogLabel.Default, itemType.Id, succeed); + LogCat.LogWithFormat("register_item", label: LogCat.LogLabel.Default, LogCat.UploadFormat, itemType.Id, + succeed); } //Use for yaml deserialization @@ -151,7 +152,8 @@ public static class ItemTypeRegister var ss = s.Split(','); if (ss.Length != 2) { - LogCat.LogErrorWithFormat("wrong_custom_arg", LogCat.LogLabel.Default, "Vector2", s); + LogCat.LogErrorWithFormat("wrong_custom_arg", LogCat.LogLabel.Default, LogCat.UploadFormat, "Vector2", + s); return Vector2.Zero; } diff --git a/scripts/loader/uiLoader/MainMenuLoader.cs b/scripts/loader/uiLoader/MainMenuLoader.cs index 5c19867..fb1071d 100644 --- a/scripts/loader/uiLoader/MainMenuLoader.cs +++ b/scripts/loader/uiLoader/MainMenuLoader.cs @@ -33,6 +33,12 @@ public partial class MainMenuLoader : UiLoaderTemplate public override void InitializeData() { + AppConfigData? appConfigData = AppConfig.LoadFromFile(); + if (appConfigData != null) + { + AppConfig.ApplyAppConfig(appConfigData); + } + if (Config.IsDebug()) { //Set the minimum log level to Info in debug mode.(Print all logs) diff --git a/scripts/loot/LootList.cs b/scripts/loot/LootList.cs index 78e5b2e..99ff3f3 100644 --- a/scripts/loot/LootList.cs +++ b/scripts/loot/LootList.cs @@ -25,7 +25,7 @@ public readonly struct LootList(string id, IList groups) { if (Groups is []) { - LogCat.LogWithFormat("loot_list_has_no_entries", LogCat.LogLabel.Default, Id); + LogCat.LogWithFormat("loot_list_has_no_entries", LogCat.LogLabel.Default, LogCat.UploadFormat, Id); return []; } @@ -41,10 +41,10 @@ public readonly struct LootList(string id, IList groups) //我们为每个战利品条目生成一个战利品数据。 var datum = group.GenerateLootData(); lootDataList.Add(datum); - LogCat.LogWithFormat("loot_data_add", LogCat.LogLabel.Default, datum); + LogCat.LogWithFormat("loot_data_add", LogCat.LogLabel.Default, LogCat.UploadFormat,datum); } - LogCat.LogWithFormat("loot_data_quantity", LogCat.LogLabel.Default, lootDataList.Count); + LogCat.LogWithFormat("loot_data_quantity", LogCat.LogLabel.Default, LogCat.UploadFormat,lootDataList.Count); return lootDataList.ToArray(); } } \ No newline at end of file diff --git a/scripts/map/MapGenerator.cs b/scripts/map/MapGenerator.cs index f0b8eeb..dc5a91b 100644 --- a/scripts/map/MapGenerator.cs +++ b/scripts/map/MapGenerator.cs @@ -241,7 +241,7 @@ public static class MapGenerator //If the room injection processor cannot be found, a print error occurs. //如果找不到房间注入处理器,那么打印错误。 LogCat.LogErrorWithFormat("room_injection_processor_does_not_exist", - LogCat.LogLabel.Default, injectionProcessorData.Id); + LogCat.LogLabel.Default, LogCat.UploadFormat,injectionProcessorData.Id); continue; } @@ -278,7 +278,7 @@ public static class MapGenerator if (roomPlacementData == null) { LogCat.LogWithFormat("failed_to_calculate_the_room_location", LogCat.LogLabel.Default, - roomNodeData.Id); + LogCat.UploadFormat,roomNodeData.Id); continue; } @@ -324,18 +324,18 @@ public static class MapGenerator if (dictionary.ContainsKey(roomNodeDataId)) { - LogCat.LogWithFormat("place_existing_rooms", LogCat.LogLabel.Default, roomNodeDataId); + LogCat.LogWithFormat("place_existing_rooms", LogCat.LogLabel.Default, LogCat.UploadFormat,roomNodeDataId); return false; } if (!await _roomPlacementStrategy.PlaceRoom(_mapRoot, roomPlacementData)) { - LogCat.LogWarningWithFormat("room_placement_failed", LogCat.LogLabel.Default, roomNodeDataId); + LogCat.LogWarningWithFormat("room_placement_failed", LogCat.UploadFormat,LogCat.LogLabel.Default, roomNodeDataId); return false; } dictionary.Add(roomNodeDataId, roomPlacementData.Room); - LogCat.LogWithFormat("room_placement_information", LogCat.LogLabel.Default, roomNodeDataId, + LogCat.LogWithFormat("room_placement_information", LogCat.LogLabel.Default, LogCat.UploadFormat,roomNodeDataId, roomPlacementData.Position.ToString()); return true; } diff --git a/scripts/map/room/Room.cs b/scripts/map/room/Room.cs index 8a205fe..8a497db 100644 --- a/scripts/map/room/Room.cs +++ b/scripts/map/room/Room.cs @@ -36,7 +36,7 @@ public class Room { if (_rootNode != null) { - LogCat.LogWithFormat("enter_the_room_debug", LogCat.LogLabel.Default, node.Name, _rootNode.Name); + LogCat.LogWithFormat("enter_the_room_debug", LogCat.LogLabel.Default, LogCat.UploadFormat,node.Name, _rootNode.Name); } if (string.IsNullOrEmpty(EnterRoomEventHandlerId)) @@ -57,7 +57,7 @@ public class Room { if (_rootNode != null) { - LogCat.LogWithFormat("exit_the_room_debug", LogCat.LogLabel.Default, node.Name, _rootNode.Name); + LogCat.LogWithFormat("exit_the_room_debug", LogCat.LogLabel.Default, LogCat.UploadFormat,node.Name, _rootNode.Name); } if (string.IsNullOrEmpty(ExitRoomEventHandlerId)) diff --git a/scripts/openObserve/LogCollector.cs b/scripts/openObserve/LogCollector.cs new file mode 100644 index 0000000..9e137c4 --- /dev/null +++ b/scripts/openObserve/LogCollector.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http.Json; +using System.Threading.Tasks; +using ColdMint.scripts.debug; +using HttpClient = System.Net.Http.HttpClient; + +namespace ColdMint.scripts.openObserve; + +/// +/// LogCollector +/// 日志收集器 +/// +public static class LogCollector +{ + private static readonly List LogDataList = []; + + /// + /// Automatic upload threshold + /// 自动上传的阈值 + /// + /// + ///An attempt is made to upload logs when messages reach this number. + ///当消息到达此数量后将尝试上传日志。 + /// + public static int UploadThreshold { get; set; } = 300; + + private static bool _lockList = false; + + /// + /// httpClient + /// Http客户 + /// + private static HttpClient? _httpClient; + + private static string? _orgId; + private static string? _streamName; + + /// + /// CanUploadLog + /// 是否能上传日志 + /// + public static bool CanUploadLog => _httpClient != null; + + /// + /// UpdateHttpClient + /// 更新Http客户端 + /// + /// + public static void UpdateHttpClient(OpenObserve openObserve) + { + if (openObserve.Address == null || openObserve.AccessToken == null || openObserve.OrgId == null || + openObserve.StreamName == null) + { + return; + } + + var httpClient = new HttpClient(); + httpClient.BaseAddress = new Uri(openObserve.Address); + //Add a Cookie to the request header + //添加Cookie到请求头 + var cookie = new Cookie("auth_tokens", + "{\"access_token\":\"Basic " + openObserve.AccessToken + "\",\"refresh_token\":\"\"}"); + httpClient.DefaultRequestHeaders.Add("Cookie", cookie.ToString()); + _httpClient = httpClient; + _orgId = openObserve.OrgId; + _streamName = openObserve.StreamName; + } + + + /// + /// Push log + /// 推送日志 + /// + /// + private static async Task PostLog(List logRequestBean) + { + if (_httpClient == null) + { + return; + } + + _lockList = true; + LogCat.LogWithFormat("start_uploading", label: LogCat.LogLabel.LogCollector, false, logRequestBean.Count); + var httpResponseMessage = + await _httpClient.PostAsJsonAsync("/api/" + _orgId + "/" + _streamName + "/_json", logRequestBean); + _lockList = false; + if (httpResponseMessage.IsSuccessStatusCode) + { + LogDataList.RemoveRange(0, logRequestBean.Count); + LogCat.LogWithFormat("upload_successful", label: LogCat.LogLabel.LogCollector, false, + logRequestBean.Count, LogDataList.Count); + if (LogDataList.Count > UploadThreshold) + { + //After the upload succeeds, if the threshold is still met, continue uploading. + //上传成功后,如果依然满足阈值,那么继续上传。 + PostLog(LogDataList.GetRange(0, UploadThreshold)); + } + } + else + { + LogCat.LogWithFormat("upload_failed", label: LogCat.LogLabel.LogCollector, false, + httpResponseMessage.StatusCode.ToString(), LogDataList.Count); + } + } + + public static void Push(LogData logData) + { + LogDataList.Add(logData); + LogCat.LogWithFormat("upload_status", LogCat.LogLabel.LogCollector, false, LogDataList.Count, UploadThreshold); + if (!_lockList && LogDataList.Count > UploadThreshold) + { + //执行上传 + PostLog(LogDataList.GetRange(0, UploadThreshold)); + } + } +} + +public class LogData +{ + /// + /// The AppId of this application + /// 此应用的AppId + /// + public string? AppId { get; set; } + + /// + /// message + /// 消息 + /// + public string? Message { get; set; } + + /// + /// level + /// 错误等级 + /// + public int Level { get; set; } +} \ No newline at end of file diff --git a/scripts/stateMachine/IStateContext.cs b/scripts/stateMachine/IStateContext.cs index 2e5effc..cdb81a5 100644 --- a/scripts/stateMachine/IStateContext.cs +++ b/scripts/stateMachine/IStateContext.cs @@ -33,7 +33,7 @@ public class StateContext return; } - LogCat.LogWithFormat("state_change", label: LogCat.LogLabel.StateContext, _currentState, value); + LogCat.LogWithFormat("state_change", label: LogCat.LogLabel.StateContext, LogCat.UploadFormat,_currentState, value); OnStateChange?.Invoke(_currentState, value); _previousState = _currentState; _currentState = value; diff --git a/scripts/stateMachine/StateMachineTemplate.cs b/scripts/stateMachine/StateMachineTemplate.cs index e0fb25c..2eb06e6 100644 --- a/scripts/stateMachine/StateMachineTemplate.cs +++ b/scripts/stateMachine/StateMachineTemplate.cs @@ -69,7 +69,7 @@ public abstract class StateMachineTemplate : IStateMachine else { LogCat.LogErrorWithFormat("state_processor_not_found", label: LogCat.LogLabel.StateMachineTemplate, - newState); + LogCat.UploadFormat,newState); } } diff --git a/scripts/stateMachine/StateProcessor/PatrolStateProcessor.cs b/scripts/stateMachine/StateProcessor/PatrolStateProcessor.cs index 0068e17..5d10ed8 100644 --- a/scripts/stateMachine/StateProcessor/PatrolStateProcessor.cs +++ b/scripts/stateMachine/StateProcessor/PatrolStateProcessor.cs @@ -78,7 +78,7 @@ public class PatrolStateProcessor : StateProcessorTemplate _originPosition = aiCharacter.GlobalPosition; LogCat.LogWithFormat("patrol_origin_position", LogCat.LogLabel.PatrolStateProcessor, - _originPosition); + LogCat.UploadFormat,_originPosition); } var point = _originPosition + Points[_index]; @@ -87,7 +87,7 @@ public class PatrolStateProcessor : StateProcessorTemplate { //No need to actually come to the patrol point, we just need a distance to get close. //无需真正的来到巡逻点,我们只需要一个距离接近了就可以了。 - LogCat.LogWithFormat("patrol_arrival_point", LogCat.LogLabel.PatrolStateProcessor, point); + LogCat.LogWithFormat("patrol_arrival_point", LogCat.LogLabel.PatrolStateProcessor, LogCat.UploadFormat,point); _index++; if (_index >= Points.Length) { @@ -96,7 +96,7 @@ public class PatrolStateProcessor : StateProcessorTemplate } else { - LogCat.LogWithFormat("patrol_to_next_point", label: LogCat.LogLabel.PatrolStateProcessor, point, + LogCat.LogWithFormat("patrol_to_next_point", label: LogCat.LogLabel.PatrolStateProcessor, LogCat.UploadFormat,point, aiCharacter.GlobalPosition, Points[_index], distance); aiCharacter.SetTargetPosition(point.Value); diff --git a/scripts/utils/NodeUtils.cs b/scripts/utils/NodeUtils.cs index 7af8dbd..2b5dcb4 100644 --- a/scripts/utils/NodeUtils.cs +++ b/scripts/utils/NodeUtils.cs @@ -279,7 +279,8 @@ public static class NodeUtils if (node is T result) return result; // If the transformation fails, release the created node //如果转型失败,释放所创建的节点 - LogCat.LogWarningWithFormat("warning_node_cannot_cast_to", LogCat.LogLabel.Default, node, nameof(T)); + LogCat.LogWarningWithFormat("warning_node_cannot_cast_to", LogCat.UploadFormat, LogCat.LogLabel.Default, node, + nameof(T)); node.QueueFree(); return null; } diff --git a/scripts/utils/TimeUtils.cs b/scripts/utils/TimeUtils.cs index c47048c..3efce58 100644 --- a/scripts/utils/TimeUtils.cs +++ b/scripts/utils/TimeUtils.cs @@ -33,7 +33,7 @@ public static class TimeUtils var compNum1 = DateTime.Compare(dateTime, dtStartTime); var compNum2 = DateTime.Compare(dateTime, dtEndTime); var result = compNum1 >= 0 && compNum2 <= 0; - LogCat.LogWithFormat("time_range_debug", LogCat.LogLabel.Default, dateTime, dtStartTime, dtEndTime, + LogCat.LogWithFormat("time_range_debug", LogCat.LogLabel.Default, LogCat.UploadFormat,dateTime, dtStartTime, dtEndTime, result); return result; }