第一部分

首先,转自https://studygolang.com/articles/3314对断言的基本介绍

golang的语言中提供了断言的功能。golang中的所有程序都实现了interface{}的接口,这意味着,所有的类型如string,int,int64甚至是自定义的struct类型都就此拥有了interface{}的接口,这种做法和java中的Object类型比较类似。那么在一个数据通过func funcName(interface{})的方式传进来的时候,也就意味着这个参数被自动的转为interface{}的类型。

如以下的代码:

func funcName(a interface{}) string {
     return string(a)
}

编译器将会返回:

cannot convert a (type interface{}) to type string: need type assertion

此时,意味着整个转化的过程需要类型断言。类型断言有以下几种形式:

1)直接断言使用

var a interface{}

fmt.Println("Where are you,Jonny?", a.(string))

但是如果断言失败一般会导致panic的发生。所以为了防止panic的发生,我们需要在断言前进行一定的判断

value, ok := a.(string)

如果断言失败,那么ok的值将会是false,但是如果断言成功ok的值将会是true,同时value将会得到所期待的正确的值。示例:

value, ok := a.(string)
if !ok {
    fmt.Println("It's not ok for type string")
    return
}
fmt.Println("The value is ", value)


另外也可以配合switch语句进行判断:

var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
    fmt.Printf("unexpected type %T", t)       // %T prints whatever type t has
break case bool: fmt.Printf("boolean %t\n", t) // t has type bool
break case int: fmt.Printf("integer %d\n", t) // t has type int
break case *bool: fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
break case *int: fmt.Printf("pointer to integer %d\n", *t) // t has type *int
break }


第二部分

net/jsonrpc增加get_client_ip功能

问题描述:falcon-agent无法监测到宿主机ip的变动,导致初始化安装时写在配置里的IP地址与当前真实IP地址不符,产生错误的上报数据(将数据以旧IP上报,新IP查不到任何监控项)。

解决思路:由于agent已大规模部署在服务器上,更新比较麻烦,考虑修改transfer端,从rpc连接中直接获取到agent的IP。

 

来自open-falcon/falcon-plus/transfer组件中的rpc相关代码:

初始建立RPC server:open-falcon\falcon-plus\modules\transfer\receiver\rpc\rpc.go

这里使用的是jsonrpc的编码解码器,其中会对conn中的数据使用json.Unmarshal解码。

 

重要的步骤位于jsonrpc/server.go的下列函数中:

1-4行和13-15行是新增的一个断言判断,目的是为了给解析出来的args参数增加一些上下文信息,比如最重要的:将conn对象存入其中。

如此,便可以从rpc的callback函数中访问到conn对象,从而拿到client IP【要求args的类型在定义时实现ArgsContext的接口】。

 

该思路源自https://github.com/club-codoon/rpcx/blob/630e53bff09759ba2a21644f318907504cfdd98a/_examples/context/server.go,应用方式如下:

 

但是该方法有一个局限,如下的callback场景中,args参数为[]*sometype,是一个slice。

如果是一个struct,则可以方便的按照上述方法添加一个私有的ctx即可存放相关数据,但如果是一个slice,是没办法放一个ctx解决的,那样的话会把slice改为一个struct,从而在json.Unmarshal时失败。

RPC server的callback函数定义:open-falcon\falcon-plus\modules\transfer\receiver\rpc\rpc_transfer.go

 

一个workaround思路是,将jsonrpc单拿出来作为一个私有依赖包,更改其中的逻辑,直接将args断言为slice指针类型,并遍历其数据,将client IP放入Endpoint字段中。

【由于transfer的rpc机制只有这里用到了jsonrpc包,所以该workaround可以不影响其他rpc逻辑】: