API
给开发者的留言¶
作为一名饥荒mod开发者,在收到bug反馈时,我常常要花费大量精力教玩家寻找 server_log,所以我做出了这个小工具。
错误追踪mod内置了日志发送功能,玩家只需要点击按钮,就能把报错日志直接发到你的手里。 支持两种发送方法: 邮箱、URL。
配置过程非常简单。只需在 modinfo.lua
或 modmain.lua
中以全局变量的形式声明 bugtracker_config
表,然后把所有配置写在这个表内。类似这样:
bugtracker_config = {
email = "myemail@dst.com",
upload_client_log = true,
upload_server_log = false,
-- 其它配置项目...
}
所有配置项目一览¶
项目 | 描述 | 类型 | 示例值 |
---|---|---|---|
接收日志的邮箱。 | 字符串 | myemail@dst.com | |
lang | 邮件使用的语言,设定为CHI 代表接收中文邮件,否则为英文。 |
字符串 | CHI |
url | 接收post请求的地址,优先级高于email,注意必须带http或https协议。 | 字符串 | http://23.233.2.3:80/upload/ http://my-log-db.cn/upload/ |
upload_client_log | 是否接受客户端报错日志,默认true。 大部分mod都包含会在客户端运行的代码,所以建议都设置为true。 |
布尔 | true |
upload_server_log | 是否接受服务器报错日志,客户端mod默认false,服务器mod默认true。 建议默认(不填)。 |
布尔 | true |
upload_other_mods_crash_log | 是否接受其它mod引起的报错日志,默认true。 | 布尔 | true |
auto_upload | 只要发生崩溃就自动上传日志,默认false。 该设定仅对url有效。 |
布尔 | true |
详细介绍¶
1.设定接收条件¶
你可以指定哪些日志允许上传,避免收到一些无意义的报错信息。
可跳过此设置,使用默认值。
bugtracker_config = {
upload_client_log = true, -- 接受客户端报错日志
upload_server_log = true, -- 接受服务器报错日志
upload_other_mods_crash_log = true, -- 接受其他mod引起的报错日志
-- 其它配置项目...
}
2.设定邮箱¶
如果你希望玩家将日志发送到你指定的邮箱,你需要添加email
键,如下所示:
bugtracker_config = {
email = "myemail@dst.com", --注意: 不要设置成工作的邮箱!建议注册一个新邮箱专门用于接收日志。
lang = "CHI", -- 设置邮件语言为中文
-- 其它配置项目...
}
这样一来,当玩家点击【发送日志】按钮时,日志会即刻送达你的邮箱。
具体来说,日志会先上传至我的服务器,然后自动转发到你的邮箱,每日发送上限为100封,日志信息不会储存在服务器上。
如果想收到更多报错邮件,你可以选择配置URL。(见下)
3.设定URL¶
如果你有一个网络服务器,强烈建议你配置一个专用的上传URL,日志信息将直接以POST的方法发送至你的服务器。
该配置的优先级高于 email
。如果同时设置 email
和 url
,只有 url
会生效。
bugtracker_config = {
url = "http://127.0.0.1:8000/demo/", -- 请求的url,请务必带上协议,如 http://
auto_upload = true, -- 设置为自动发送日志,该配置项目仅对url有效
-- 其它配置项目...
}
上传的数据结构为: <摘要区字节数> 摘要区(json格式)日志内容(纯字符串)
。
这是使用python-django的后端解析示例,可供参考。(我没学过php和java,所以没有例子)
import json
import re
from django.http import HttpResponse
def parsebody(body: bytes) -> dict:
'''饥荒只能POST字符串,服务器需要对上传的内容进行解析。
数据结构为 <摘要区字节数> 摘要区(json格式) 日志内容(纯字符串)
摘要区包含一些基础信息,日志则包含详细的报错内容。
摘要结构:
gameversion <str> 饥荒版本号
platform <str> 运行平台
playername <str> 向您发送日志的玩家昵称
playerid <str> 玩家的游戏id
modname <str> 模组名
modversion <str> 模组版本号
diagnose <str> 诊断信息,如安全/崩溃回溯路径/崩溃点
diagnoselevel <int> 诊断等级,大于50代表崩溃可能和mod有关,小于50代表其他警告,0代表安全
timestamp <int> 崩溃发生的时间戳
ingame <bool> 崩溃发生在世界启动后
isserver <bool> 崩溃点位于服务器
isdedicated <bool> 崩溃点位于专用服务器
apiversion <str> 错误追踪器版本号
'''
match = re.match(b"^<(\\d+)>.", body)
if match is not None:
# parse abstract length
abslenstr = match.group(1)
abslen = int(abslenstr)
# don't forget `<` and `>`!
absstart = len(abslenstr) + 2
# parse abstract, note abstract may contain utf-8 character.
jsonstr = body[absstart: absstart + abslen].decode("utf-8")
# Here we get abstract!
abstract = json.loads(jsonstr)
# Here we get log content!
log = body[absstart + abslen: ].decode("utf-8")
return {
"abstract" : abstract,
"log" : log,
}
def demo(request):
''' Your url function '''
if request.method == "POST":
result = parsebody(request.body)
if result:
abstract = result["abstract"]
log = request["log"]
# Now do anything you want to do.
# (For example, save log file in the database or send an email.)
# Actually, BugTracker doesn't handle response, but you need this to avoid 500.
return HttpResponse("")
进阶:忽略部分钩子¶
在mod中修改某些常用的基础函数,可能会导致mod经常出现在回溯路径内。
在下面的例子中,我们对 CreateEntity 函数稍作修改。
-- modmain.lua
local old_fn = GLOBAL.CreateEntity
function GLOBAL.CreateEntity(name)
print("Hello don't starve!")
return old_fn(name)
end
由于 CreateEntity 函数会被频繁调用,在报错路径出镜率极高,这会让你的mod也无辜中枪,被错误追踪检测到。
为了解决这一问题,你可以显式地添加忽略标记,以使特定的钩子不被错误追踪识别为报错路径。
标记格式为 local bugtracker_ignore_flag__{函数名} = true
,注意flag后是双下划线。
-- modmain.lua
local old_fn = GLOBAL.CreateEntity
function GLOBAL.CreateEntity(name)
print("Hello don't starve!")
local bugtracker_ignore_flag__CreateEntity = true -- 标记
return old_fn(name)
end
添加标记后,如果游戏调用 CreateEntity 发生了某些错误,你的这处修改会被错误追踪忽略,mod不会被判定为位于回溯路径内。
警告:
尽量少用这个功能,特别是在你无法确认钩子是否绝对安全的情况下。
在加入标记前,请务必确保你的修改是符合逻辑的!注意观察下面的代码。
-- modmain.lua
local old_fn = GLOBAL.CreateEntity
function GLOBAL.CreateEntity(name)
print("Hello don't starve!")
local bugtracker_ignore_flag__CreateEntity = true -- 标记
-- return old_fn() -- 错误的写法,缺少原始参数
-- old_fn(name) -- 错误的写法,未返回,注意原始的 CreateEntity 函数有返回值
return old_fn(name) -- 正确
end
源代码¶
本mod所有代码开源无混淆,如果你对本mod的实现有任何疑问,可直接查看源代码。