解决方案:无需重启应用,动态采集任意点位日志

优采云 发布时间: 2022-11-12 19:30

  解决方案:无需重启应用,动态采集任意点位日志

  作者 | 玉山

  实际系统通常具有很高的复杂性。我们使用 Trace、Log、Metric 三驾马车,让我们的系统具备一定的可观测性,但是观测的位置和信息往往是固定的,遇到的问题往往是出乎意料的,导致我们能够定位问题的范围,但是很难更进一步,这时候我们需要采集信息来帮助我们在我们想要的地方,这在通常的实践中意味着然后我们需要添加日志记录逻辑并重新启动应用程序,这价格昂贵,失去了现场。借助日志管理,只需要在控制台中配置规则,即可动态采集任意点信息,无需重启应用。接下来,我们将通过一个假设的故障排除过程来简要介绍日志管理的实践。

  动态日志打印

  假设我们有一个简单的请求调用链接,用于请求数据库,如图所示。当调用链路的请求异常时,在定位问题的过程中,我们往往需要知道调用栈信息,然后查看栈上的Methods,获取这些方法的参数、返回值、异常等信息,从而帮助我们找出问题的原因。有了日志治理的能力,我们就可以轻松的进行这些操作。

  这种场景下,当发现AppB的/sql请求部分报错,但是我们还没有提前写出可以记录有效信息的日志,那么我们可以配置一个日志管理规则,打印现场栈信息来获取我们需要检查的方法列表,然后逐个方法进一步分析。我们选择 /sql 作为目标。如果不知道具体的界面,可以保持默认选择all。

  由于我们只需要分析错误请求,在过滤规则条件中开启异常过滤,在打印内容中选择调用栈,其他内容可以根据需要选择。

  开启这条规则后,可以看到系统帮助我们打印日志文件中收录堆栈信息的日志:

  /home/admin/.opt/ArmsAgent/logs/mse-log-governance.log

  在 com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:989)

  在 com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:213)

  在 com.alibabacloud.mse.demo.service.DruidCon.doCommon(DruidCon.java:57)

  在 com.alibabacloud.mse.demo.service.DruidService.query(DruidService.java:15)

  在 com.alibabacloud.mse.demo.BApplication$AController.sql(BApplication.java:89)

  在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

  在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  

  通过截取其中的一些,我们可以发现其中一些是我们自己的业务逻辑方法,也是我们需要关注的方法。我们可以继续使用日志管理的能力来获取这些方法的现场信息,比如参数、返回值、类加载器等等。

  自己的业务逻辑方法:com.alibabacloud.mse.demo.service.DruidCon.doCommon com.alibabacloud.mse.demo.service.DruidService.query

  以 doCommon 方法为例,我们只需要添加一个新的规则来指定自定义方法。

  然后在过滤规则条件中开启异常过滤,在打印内容中选择请求参数,其他内容可以根据需要选择。

  开启这条规则后,可以看到系统帮我们打印了JSON格式的日志信息,包括我们检查的参数信息:

  /home/admin/.opt/ArmsAgent/logs/mse-log-governance.log

  {

  "appName": "app-b",

  “属性”: {

  “mse.tag”:“基地”,

  "mse.param": "{\"sql\":\"select * from log_demo where id = ?\",\"id\":\"1\"}",

  “mse.app.tag”:“基础”,

  “mse.service.type”:“自定义”

  },

  “结束时间”:28,

  “事件”:{},

  "ip": "10.0.0.166",

  "名称": "com.alibabacloud.mse.demo.service.DruidCon:doCommon(java.lang.String,int)",

  “需要记录”:是的,

  “parentId”:-46695586,

  

  “规则标识集”:[

  288

  ],

  “spanId”:-86744300,

  “开始时间”:25,

  “状态代码”:2,

  “traceId”:“ea1a00009d231724d0001”

  }

  上面只是一个简单的例子,但是可以发现日志管理的能力让我们可以在Java方法中的任意点采集信息,将检查工作变成零代码和动态,因为不需要重复在测试环境中添加日志代码并不断重启应用,可以大大降低一些在测试环境中难以重现的问题的排查难度。

  日记采集

  开启日志管理功能后,我们的日志会自动滚动保存到本地。为了满足存储或者进一步分析的需要,我们可以将这些日志采集放到日志服务系统中。这里我们以 SLS 的 Logtail 采集 模式为例。

  配置Logtail 采集 日志

  通过组件或其他方式在我们的集群或实例中安装Logtail后,即可通过日志服务SLS控制台完成log采集的配置。具体请参考SLS日志服务的相关文档。. 我们只关注其中的一些配置,首先是Logtail配置。在K8s集群场景下,我们需要的配置如下:

  使用 OneAgent 时,日志路径为:/home/admin/.opt/ArmsAgent/plugins/ArmsAgent/logs/mse-log-governance.log

  二是查询分析配置。在控制台配置过程中,我们可以选择自动生成索引或稍后在 SLS 控制台中添加索引。为方便我们分析,建议对statusCode、ruleIdSet、name、appName等字段添加索引。

  查看日志

  一段时间后,可以在 SLS 控制台中查看采集的日志,并在查询分析的帮助下进行处理。

  概括

  借助现有的日志管理能力,我们可以动态采集任意点信息,无需重启应用。同时,由于日志管理在采集信息时会引入链接信息,分析起来比较复杂。调用问题时效果很好。目前日志管理的信息采集会以JSON格式存储在本地,我们可以使用SLS等日志服务系统提供的采集方法采集做进一步的查询分析,后续日志管理会不断完善和优化,采集的信息组织完全兼容OpenTelemetry标准,进一步提供符合标准的完整上报方式。

  解决方案:个推 解决Android应用后台运行无法接受推送的问题

  【问题描述】

  这个问题只出现在Andoid上,因为iOS端使用APNS,所以推送可以及时送达。

  使用push推送时,一旦用户将应用切换到后台,推送时会显示success_offline,即离线的cilentID。

  事实上,此时应用程序并没有被系统杀死,只是已经无法接收推送消息了。即使您重新打开APP,您也不会收到任何消息,无论是之前的消息还是之后推送的消息。

  【解决方案】

  首先,确保APP后台的进程没有被杀死。一位推送官方给出了各个系统的设置

  强烈鼓励大家阅读蜡笔小新的《推用中的各种坑》@蜡笔小新

  【解决过程】

  本来以为是sdk版本推送的问题。5+SDK集成的*敏*感*词*是2.7.0.0,现在正式发布的版本是2.9.3.0。但是下载并编译Getui官方SDK后,后台仍然无法接受消息。

  我使用的开发机器是小米5,在“更多应用”中查看时发现,当应用后台运行时,“正在运行”应用列表中会显示APP的名称,显示“1进程和0服务”。然后大约五秒钟后,该应用程序从“运行”列表中消失,并出现在“缓存”列表中。

  但是Getui SDK有一个后台服务叫做NotificationCenter,用来管理推送消息。也就是说,我们的应用程序没有成功调用 NoticationCenter 服务。

  但是我只知道一点Android开发的知识(web全栈够花精力了~老板加薪~),只能尝试用Native.js拉一个PushService,但是它不起作用。失败的。

  拉起服务的代码是这样的:

   var main = plus.android.runtimeMainActivity();

var Intent = plus.android.importClass('android.content.Intent');

var intent = new Intent();

var serviceName = 'com.igexin.sdk.PushService';//把这里换成其他Service的名字,也可以实现拉取自定义的Service

intent.setClassName(main, serviceName);

main.startService(intent);

  注意:将 serviceName 替换为 'com.igexin.sdk.PushServiceForUser' 可以拉起 NoticationCenterForUser 服务。我以为和PushService一样,结果发现这个服务对推送什么都没有用……

  然后做了对比,发现在Getui的官方Demo中,AndroidManifest.xml中,SDK的两个activity存在一些差异。

  第一部分:

  

  第二部分

  这里的流程属性名称与核心推送服务相同

  然后我google了一下,这个属性的作用是:

   android:process

应在其中运行 Activity 的进程的名称。正常情况下,应用的所有组件都在为应用创建的默认进程名称内运行,您无需使用该属性。 但在必要时,您可以使用该属性替换默认进程名称,以便让应用组件散布到多个进程中。

如果为该属性分配的名称以冒号(“:”)开头,则会在需要时创建应用专用的新进程,并且 Activity 会在该进程中运行。如果进程名称以小写字符开头,Activity 将在该名称的全局进程中运行,前提是它拥有相应的权限。这可以让不同应用中的组件共享一个进程,从而减少资源占用。

元素的 process 属性可为所有组件设置一个不同的默认进程名称。

  点击这里查看官方文档

  因此,猜测一下,因为主activity没有运行在pushservice进程中,所以后台push服务无法成功启动。

  添加到主要活动

  android:process=":pushservice"

  这个属性,发现NotificationCenter进程正常启动。并且应用后台运行后,服务正常运行,可以正常接收推送信息。

  问题解决了,但是我对Android开发了解不多,所以不知道这会有什么副作用。但是,内存消耗和网络连接似乎是正常的,没有观察到严重的后果。

  前后花了两天一夜的时间,程序员没有人权~

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线