DebugInOut 插件
提示
使用场景推荐
- 开发阶段
介绍
DebugInOut 是控制台输出插件,主要关注点
- 快速导航到请求处理的业务代码中(执行的 action )
- 当前发起请求的用户(玩家)
- 玩家当前所使用的连接方式(webSocket、Tcp、udp)
- 执行 action 的线程
- 执行 action 耗时情况
- 路由、类信息、方法信息等
- action 接收的请求参数
- action 响应给玩家的数据(响应结果)
当 action 处理请求时,会在控制台打印上述相关信息。 这意味着即使有新人加入到项目中,也能快速知道每个请求所对应的 action , 从而快速熟悉项目的整体业务逻辑。
打印预览
当访问 action 业务方法时,控制台将会打印的日志输出如下
┏━━━━━ Debug. [(DemoAction.java:5).here] ━━━━━ [cmd:1-0 65536] ━━━━━ [xxx逻辑服 - id:[76526c134cc88232379167be83e4ddfc]
┣ userId: 1
┣ 参数: message : LoginVerifyMessage(jwt=hello)
┣ 响应: UserMessage(name=Michael Jackson, hello)
┣ 时间: 1 ms (业务方法总耗时)
┗━━━━━ [ioGameVersion] ━━━━━ [线程:User-8-2] ━━━━━━━ [traceId:956230991452569600] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
控制台打印说明
- Debug. [(DemoAction.java:5).here] : 表示执行业务的是 DemoAction 类下的 here 方法,5 表示业务方法所在的代码行数。在工具中点击控制台的 DemoAction.java:5 这条信息,就可以跳转到对应的代码中(快速导航到对应的代码),这是一个开发良好体验的开始!
- userId : 当前发起请求的 用户 id。
- 参数 : 通常是游戏前端传入的值。
- 响应 : 通常是业务方法返回的值 ,业务框架会把这个返回值推送到游戏前端。
- 时间 : 执行业务方法总耗时,我们可根据业务方法总耗时的时长来优化业务。
- 路由信息 : [cmd - subCmd]路由是唯一的访问地址。
- ioGameVersion : 表示当前所使用的 ioGame 版本。
- 线程 : 当前执行 action 所使用的线程。
- traceId : 全链路调用日志跟踪 id,每个请求唯一。(该特性在分布式下非常实用)
- 逻辑服 : 当前游戏逻辑服的 id
有了以上信息,游戏开发者可以很快的定位问题。 如果没有可视化的信息,开发中会浪费很多时间在前后端的沟通上。问题包括:
- 是否传参问题 (游戏前端说传了)
- 是否响应问题(游戏后端说返回了)
- 业务执行时长问题 (游戏前端说没收到响应, 游戏后端说早就响应了)
其中代码导航可以让开发者快速的跳转到业务类对应代码中, 在多人合作的项目中可以快速的知道业务经过了哪些方法的执行,使得我们可以快速的进行阅读或修改。
如何使用
将插件添加到业务框架中即可。
BarSkeletonBuilder builder = ...;
builder.addInOut(new DebugInOut());
最小触发打印时间
插件可以设置最小触发打印时间,默认是 0 表示打印所有请求。 我们可以设置一个最小触发打印时间,当设置 50 ms 时,只有请求超过这个时间的请求才进行打印。
BarSkeletonBuilder builder = ...;
builder.addInOut(new DebugInOut(50));
如何忽略打印
有时我们需要避免某些 action 打印 debug 信息。 可以通过 DebugInOut.setPrintConsumer 方法来做自定义打印设置。
通过硬编码的方式
code 10,当路由为 1-3 时,不打印 debug
...
@Override
public BarSkeleton createBarSkeleton() {
BarSkeletonBuilder builder = ...;
DebugInOut debugInOut = new DebugInOut();
builder.addInOut(debugInOut);
debugInOut.setPrintConsumer((message, flowContext) -> {
CmdInfo cmdInfo = flowContext.getCmdInfo();
if (cmdInfo.getCmd() == 1 && cmdInfo.getSubCmd() == 3) {
return;
}
System.out.println(message);
});
...
}
通过自定义注解
- code 10,不打印 DebugInOut 日志。
- code 23,自定义注解。
...
@Override
public BarSkeleton createBarSkeleton() {
BarSkeletonBuilder builder = ...;
DebugInOut debugInOut = new DebugInOut();
builder.addInOut(debugInOut);
debugInOut.setPrintConsumer((message, flowContext) -> {
ActionCommand actionCommand = flowContext.getActionCommand();
if (actionCommand.containAnnotation(IgnoreDebugInout.class)) {
return;
}
System.out.println(message);
});
...
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreDebugInout {
}
使用
@ActionController(1)
public class DemoAction {
@ActionMethod(3)
@IgnoreDebugInout
public String hello() {
return "hello";
}
}