zoukankan      html  css  js  c++  java
  • Go

    上篇文章 Go - 实现项目内链路追踪 分享了,通过 链路 ID 可以将 请求信息响应信息调用第三方接口的信息调试信息执行的 SQL 信息执行的 Redis 信息 串起来,记录的具体参数在文件中都有介绍。

    这篇文章在上面的基础上,新增 2 个功能点:

    1. 新增将 调用 gRPC 接口信息 记录到 Trace 中;
    2. 新增对记录的敏感信息进行脱敏处理;

    调用 gRPC 接口信息

    记录参数

    Object,结构如下:

    type Grpc struct {
    	Timestamp   string                 `json:"timestamp"`             // 时间,格式:2006-01-02 15:04:05
    	Addr        string                 `json:"addr"`                  // 地址
    	Method      string                 `json:"method"`                // 操作方法
    	Meta        metadata.MD            `json:"meta"`                  // Mate 信息
    	Request     map[string]interface{} `json:"request"`               // 请求信息
    	Response    map[string]interface{} `json:"response"`              // 返回信息
    	CostSeconds float64                `json:"cost_seconds"`          // 执行时间(单位秒)
    	Code        string                 `json:"err_code,omitempty"`    // 错误码
    	Message     string                 `json:"err_message,omitempty"` // 错误信息
    }
    

    如何收集参数

    封装了一个 grpclient 包:

    • 支持设置 DialTimeout
    • 支持设置 UnaryInterceptor
    • 支持设置 KeepaliveParams
    • 支持设置 TransportCredentials

    主要是在拦截器 Interceptor 中进行收集。

    示例代码

    实例化 gRPC client

    // TODO 需从配置文件中获取
    target := "127.0.0.1:9988"
    secret := "abcdef"
    
    clientInterceptor := NewClientInterceptor(func(message []byte) (authorization string, err error) {
    	return GenerateSign(secret, message)
    })
    
    conn, err := grpclient.New(target,
    	grpclient.WithKeepAlive(keepAlive),
    	grpclient.WithDialTimeout(time.Second*5),
    	grpclient.WithUnaryInterceptor(clientInterceptor.UnaryInterceptor),
    )
    
    return &clientConn{
    	conn: conn,
    }, err
    

    调用具体方法

    // 核心:传递 core.Context 给 Interceptor 使用
    client := hello.NewHelloClient(d.grpconn.Conn())
    client.SayHello(grpc.ContextWithValueAndTimeout(c, time.Second*3), &hello.HelloRequest{Name: "Hello World"})
    

    敏感信息脱敏

    敏感信息脱敏又称为动态数据掩码(Dynamic Data Masking,简称为DDM)能够防止把敏感数据暴露给未经授权的用户。

    根据项目要求可以约定一些规范,例如:

    类型 要求 示例 说明
    手机号 前 3 后 4 132****7986 定长 11 位数字
    邮箱地址 前 1 后 1 l**w@gmail.com 仅对 @ 之前的邮箱名称进行掩码
    姓名 隐姓 *鸿章 将姓氏隐藏
    密码 不输出 ******
    银行卡卡号 前 6 后 4 622888******5676 银行卡卡号最多 19 位数字
    身份证号 前 1 后 1 1******7 定长 18 位

    如何实现

    我现在的实现方案是:自定义 MarshalJSON(),欢迎大佬们提出更好的方案。

    示例代码

    // 定义 Mobile 类型
    type Mobile string
    
    // 自定义 MarshalJSON()
    func (m Mobile) MarshalJSON() ([]byte, error) {
    	if len(m) != 11 {
    		return []byte(`"` + m + `"`), nil
    	}
    
    	v := fmt.Sprintf("%s****%s", m[:3], m[len(m)-4:])
    	return []byte(`"` + v + `"`), nil
    }
    

    测试

    type message struct {
    	Mobile    ddm.Mobile   `json:"mobile"`
    }
    
    msg := new(message)
    msg.Mobile = ddm.Mobile("13288889999")
    
    marshal, _ := json.Marshal(msg)
    fmt.Println(string(marshal))
    
    // 输出:{"mobile":"132****9999"}
    

    小结

    本篇文章新增了 2 个实用的功能点,大家赶紧使用起来吧。关于 敏感信息脱敏 期待各位大佬不吝赐教,提出更好的解决方案,谢谢!

    以上代码都在 go-gin-api 项目中,地址:https://github.com/xinliangnote/go-gin-api

    作者:新亮笔记(关注公众号,可申请添加微信好友)
    出处:https://www.cnblogs.com/xinliangcoder
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    NIO简述
    函数式编程
    ReadWriterLock读写锁
    Semaphore工具类使用
    CyclicBarrier工具类使用
    CountDownLatch工具类使用
    创建VUE+Element-UI项目
    <slot>插板使用
    Spring面试题
    实现定时任务的几种方式
  • 原文地址:https://www.cnblogs.com/xinliangcoder/p/14396753.html
Copyright © 2011-2022 走看看