【TCP/IP】【调试】丢包、流不通、错包等问题查证手段系列之一——日志方式

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【TCP/IP】【调试】丢包、流不通、错包等问题查证手段系列之一——日志方式

前言


在进行TCP/IP相关的开发过程中,经常需要查证丢包、错包、流不通等问题。由于TCP/IP转发面涉及软件和硬件、并且软件流程上函数多、分支多,无论是增加打印或是分析流程,都比较困难。


本系列文章会将常用的定位手段,做一简单的总结和说明,各位可根据问题的情况,选取一种或结合使用。


日志方式简介


  • 虽然打印这种方式比较Low,但在有的情况下反而是最直接和有效的方式,有的情况下更是开发人员的杀手锏。


直接打印报文


  • 直接在需要的地方调用类似下面的print_skb的函数即可。


void print_skb(struct sk_buff *skb)
{
    if (skb) {
        char *buf = skb->data;
        int len = skb->len;
        int i = 0;
        printk("[%s:%d]Packet length = %#4x\n", __FUNCTION__, __LINE__, len);
        for (i = 0; i < len; i++){
            if (i % 16 == 0) printk("%#4.4x", i);
            if (i % 2 == 0) printk(" ");
            printk("%2.2x", ((unsigned char *)buf)[i]);
            if (i % 16 == 15) printk("\n");
        }
        printk("\n\n");
    }
}


值得一提的是,在有的内核版本中,上述代码打印不全,skb->data需要换成skb->mac_header。


另外,这种打印方式,如报文太多,会刷屏,可能将系统打宕机。


条件打印


  • 根据报文中特定字段进行打印,需要在skb结构体中增加一个字段:


struct sk_buff {
  unsigned int dbg_flag;
}


具体在某个位置,首先判断某skb是否需要被打印,比如要跟踪DHCP报文,则在某个入口或点的位置识别DHCP报文并将该标志位置上,具体可参考下面的代码段:


struct ethhdr *mh = (struct ethhdr *)(skb->mac_header);
if(mh->h_proto != htons(ETH_P_IP)) {
    return;
}
struct iphdr *iph = (struct iphdr *)ip_hdr(skb);
if(iph && iph->protocol != IPPROTO_UDP) {
    return ;
}
    // ip header --> iph->ihl*4;
struct udphdr *udph = (struct udphdr *) ((char *)iph + iph->ihl*4);
if(udph && udph->source == htons(68) && udph->dest == htons(67)) {
    skb->dbg_flag = 1;


之后,在后续其他点上,就可以直接根据这个flag来控制打印:


if (1 == skb->dbg_flag) {
    print_skb(skb);
}


开关控制打印


  • 通过某proc文件修改内核某变量,然后根据该变量来控制打印。


echo 1>/proc/net/logctl //假设logctl文件对应g_logctl变量


代码中的具体控制:


if (1 == g_logctl) {
        print_skb(skb);
    }


ratelimit限速打印


  • 限速判断函数可以用net_ratelimit或printk_ratelimit;


 if (net_ratelimit()) {
     print_skb(skb);
 }
  if (printk_ratelimit()) {
     print_skb(skb);
 }


这种打印,有个缺陷,有可能会被限速抑制掉而打印不出来,此时会有下面这种打印出现:


__ratelimit: 250 callbacks suppressed


具体的限速参数,可使用下面方式修改:


[qxhgd@localhost ~]$ cat /proc/sys/kernel/printk_ratelimit
5
[qxhgd@localhost ~]$ cat /proc/sys/kernel/printk_ratelimit_burst
10
# printk_ratelimit默认允许在5s内最多打印10条消息出来: /proc/sys/kernel/printk_ratelimit (多长时间)和 /proc/sys/kernel/printk_ratelimit_burst (在上述时间段内最多允许的消息数量)


自定义限速打印


  • 也可以根据需要,使用系统时间来自行控制打印,比如下面代码段可控制每秒最多打印一个报文:


unsigned long g_lastTime = 0; #全局变量
if (jiffies - g_lastTime > 1 * HZ)  {
    print_skb(skb);
    g_lastTime = jiffies;
}
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
3月前
|
消息中间件 存储 Java
手动实现 Spring Boot 日志链路追踪:提升调试效率的利器
【8月更文挑战第8天】在复杂的分布式系统中,日志是诊断问题、追踪系统行为的重要工具。然而,随着微服务架构的普及,服务间的调用链路错综复杂,传统的日志记录方式往往难以快速定位问题源头。今天,我们将探讨如何在不依赖外部组件(如Zipkin、Sleuth等)的情况下,手动实现Spring Boot应用的日志链路追踪,让日志定位更加便捷高效。
174 1
|
27天前
|
Java 程序员 应用服务中间件
「测试线排查的一些经验-中篇」&& 调试日志实战
「测试线排查的一些经验-中篇」&& 调试日志实战
20 1
「测试线排查的一些经验-中篇」&& 调试日志实战
|
3月前
|
XML Java 数据库
"揭秘!Spring Boot日志链路追踪大法,让你的调试之路畅通无阻,效率飙升,问题无所遁形!"
【8月更文挑战第11天】在微服务架构中,请求可能跨越多个服务与组件,传统日志记录难以全局追踪问题。本文以电商系统为例,介绍如何手动实现Spring Boot应用的日志链路追踪。通过为每个请求生成唯一追踪ID并贯穿全链路,在服务间传递该ID,并在日志中记录,即使日志分散也能通过ID串联。提供了实现这一机制所需的关键代码片段,包括使用过滤器设置追踪ID、业务代码中的日志记录及Logback配置。此方案显著提升了问题定位的效率,适用于基于Spring Boot构建的微服务环境。
82 4
|
3月前
|
SQL 数据库 Java
Hibernate 日志记录竟藏着这些秘密?快来一探究竟,解锁调试与监控最佳实践
【8月更文挑战第31天】在软件开发中,日志记录对调试和监控至关重要。使用持久化框架 Hibernate 时,合理配置日志可帮助理解其内部机制并优化性能。首先,需选择合适的日志框架,如 Log4j 或 Logback,并配置日志级别;理解 Hibernate 的多级日志,如 DEBUG 和 ERROR,以适应不同开发阶段需求;利用 Hibernate 统计功能监测数据库交互情况;记录自定义日志以跟踪业务逻辑;定期审查和清理日志避免占用过多磁盘空间。综上,有效日志记录能显著提升 Hibernate 应用的性能和稳定性。
49 0
|
3月前
|
存储 JSON 监控
FastAPI日志之谜:如何揭开Web应用监控与调试的面纱?
【8月更文挑战第31天】在现代Web开发中,日志记录对于监控应用状态、诊断问题和了解用户行为至关重要。FastAPI框架提供了强大的日志功能,使开发者能轻松集成日志记录。本文将详细介绍如何在FastAPI中设置和利用日志,包括基础配置、请求响应日志、错误处理和结构化日志等内容,帮助提升应用的可维护性和性能。
116 0
|
5月前
|
C++
spdlog 日志库部分源码说明——日志格式设定,DIY你自己喜欢的调试信息,你能调试的远比你想象的还要丰富
spdlog 日志库部分源码说明——日志格式设定,DIY你自己喜欢的调试信息,你能调试的远比你想象的还要丰富
277 6
|
5月前
|
网络协议 Java 程序员
TCP/IP协议栈是网络通信基础,Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用
【6月更文挑战第23天】 **TCP/IP协议栈是网络通信基础,它包含应用层(HTTP, FTP等)、传输层(TCP, UDP)、网络层(IP)、数据链路层(帧, MAC地址)和物理层(硬件信号)。Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用,如Socket和ServerSocket用于客户端和服务器通信。**
53 3
|
5月前
|
SQL 运维 关系型数据库
|
4月前
|
JavaScript
【vue】 将Vue2中的console.log()调试信息移除
【vue】 将Vue2中的console.log()调试信息移除
181 0
|
4月前
|
SQL
关于ThinkPHP5.1+的Log无法记录SQL调试记录的小经历
项目开发阶段,除了基本编码外,性能也需要实时关注与优化。之前我的大部分项目都是使用ThinkPHP5.0以及ThinkPHP3.2,对于框架提供的日志记录和日志配置都差不多,然后使用ThinkPHP5.1的时候就吃瘪,花了十几分钟才好,所以写一下防止后面忘记了再踩坑。
128 0