CDB数据库在腾讯云控制台可以看到每个数据库示例的操作日志,其中我们可以下载到:
但是,为了找到这些慢查询日志的下载路径,在不介入API调用的情况下,需要在控制台点开每个数据库示例,找到慢查询日志的下载TAB页,进行慢查询日志的下载,在集中对数据库进行索引和查询优化的时候,这种操作是需要一定成本哒。
为了能够每天早晨或者某个时间段自动汇总所有数据库示例的慢查询日志的下载链接给到开发同学下载统一分析,我们可以利用腾讯云CDB备份相关的接口来完成CDB慢查询日志的获取,汇总所有的查询结果,通过企业微信群机器人WebHook将消息发送到指定群。
考虑到SCF代码部署的方便性,采用golang来进行功能的开发。
点击在线调用选项卡。
将得到的JSON结果通过JSON转Struct
转换成GO语言需要的struct定义(参考下文代码实现)。
将得到的JSON结果通过JSON转Struct
转换成GO语言需要的struct定义(参考下文代码实现)。
func main() {
cloudfunction.Start(MainFunc)
}
不按照标准姿势的你,可能会遇到SCF在超时结束
之后,得到这样的返回值撒
{"errorCode":-1,"errorMessage":"Time limit exceeded"}
Golang 环境的云函数,仅支持 zip 包上传,可以选择使用本地上传 zip 包或通过 COS 对象存储引用 zip 包。zip 包内包含的应该是编译后的可执行二进制文件,二进制文件需要在 zip 包根目录,注意打包成zip包的时候不要多了一层文件夹呀。 Golang 编译可以在任意平台上通过制定 OS 及 ARCH 完成跨平台的编译,因此在 Linux,Windows 或 MacOS 下都可以进行编译。 在 Linux 或 MacOS 下通过如下方法完成编译及打包: SCF需要和你的数据库在同一个地域,比如都在广州或者上海GOOS=linux GOARCH=amd64 go build -o main main.go zip main.zip main
在 Windows 下可使用如下命令编译
set GOOS=linux
set GOARCH=amd64
go build -o main main.go
然后,就是配置SCF了
程序的简单实现如下:
type InstanceResponse struct {
Response struct {
TotalCount int `json:"TotalCount"`
Items []struct {
InstanceID string `json:"InstanceId"`
ResourceID string `json:"ResourceId"`
RegionID int `json:"RegionId"`
RegionName string `json:"RegionName"`
QPS int `json:"Qps"`
Region string `json:"Region"`
InitFlag int `json:"InitFlag"`
InstanceType int `json:"InstanceType"`
InstanceName string `json:"InstanceName"`
Vip string `json:"Vip"`
Vport int `json:"Vport"`
WanStatus int `json:"WanStatus"`
WanDomain string `json:"WanDomain"`
WanPort int `json:"WanPort"`
Status int `json:"Status"`
CdbError int `json:"CdbError"`
TaskStatus int `json:"TaskStatus"`
EngineVersion string `json:"EngineVersion"`
CreateTime string `json:"CreateTime"`
DeadlineTime string `json:"DeadlineTime"`
IsolateTime string `json:"IsolateTime"`
DeviceType string `json:"DeviceType"`
Memory int `json:"Memory"`
Volume int `json:"Volume"`
CPU int `json:"Cpu"`
AutoRenew int `json:"AutoRenew"`
ZoneID int `json:"ZoneId"`
Zone string `json:"Zone"`
ZoneName string `json:"ZoneName"`
VpcID int `json:"VpcId"`
SubnetID int `json:"SubnetId"`
UniqVpcID string `json:"UniqVpcId"`
UniqSubnetID string `json:"UniqSubnetId"`
ProjectID int `json:"ProjectId"`
PayType int `json:"PayType"`
ProtectMode int `json:"ProtectMode"`
DeployMode int `json:"DeployMode"`
SlaveInfo struct {
First struct {
Region string `json:"Region"`
ZoneID int `json:"ZoneId"`
Zone string `json:"Zone"`
Vip string `json:"Vip"`
Vport int `json:"Vport"`
} `json:"First"`
Second interface{} `json:"Second"`
} `json:"SlaveInfo"`
MasterInfo interface{} `json:"MasterInfo"`
RoInfo []interface{} `json:"RoInfo"`
RoGroups []interface{} `json:"RoGroups"`
DrInfo []interface{} `json:"DrInfo"`
BackupZoneID int `json:"BackupZoneId"`
ExClusterID string `json:"ExClusterId"`
OfflineTime string `json:"OfflineTime"`
HourFeeStatus int `json:"HourFeeStatus"`
RoVipInfo interface{} `json:"RoVipInfo"`
PhysicalID string `json:"PhysicalId"`
} `json:"Items"`
RequestID string `json:"RequestId"`
} `json:"Response"`
}
type SlowLogResponse struct {
Response struct {
TotalCount int `json:"TotalCount"`
Items []struct {
Name string `json:"Name"`
IntranetURL string `json:"IntranetUrl"`
InternetURL string `json:"InternetUrl"`
Size int `json:"Size"`
Type string `json:"Type"`
Date string `json:"Date"`
} `json:"Items"`
RequestID string `json:"RequestId"`
} `json:"Response"`
}
func main() {
cloudfunction.Start(MainFunc)
}
func MainFunc() {
credential := common.NewCredential(
"",
"",
)
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = "cdb.tencentcloudapi.com"
client, _ := cdb.NewClient(credential, "ap-guangzhou", cpf)
insRequest := cdb.NewDescribeDBInstancesRequest()
insParams := `{"Limit":100}`
err := insRequest.FromJsonString(insParams)
if err != nil {
panic(err)
}
responseIns, err := client.DescribeDBInstances(insRequest)
if _, ok := err.(*errors.TencentCloudSDKError); ok {
fmt.Println(err)
return
}
if err != nil {
panic(err)
}
var response InstanceResponse
err = json.Unmarshal([]byte(responseIns.ToJsonString()), &response)
if err != nil {
fmt.Println(err)
return
}
instanceCount := len(response.Response.Items)
if instanceCount == 0 {
fmt.Println("no instance")
return
}
var wg sync.WaitGroup
wg.Add(instanceCount)
slowLogChan := make(chan SlowLogResponse, instanceCount)
for idx := 0; idx < instanceCount; idx++ {
go SlowLogRequest(response.Response.Items[idx].InstanceID, slowLogChan, &wg)
}
wg.Wait()
close(slowLogChan)
var msgBuf bytes.Buffer //消息buf
for res := range slowLogChan {
if len(res.Response.Items) > 1 && res.Response.Items[1].Size > 0 {
logName, err := url.QueryUnescape(res.Response.Items[1].Name)
if err != nil {
continue
}
msgBuf.WriteString(fmt.Sprintf(">Name: %s \\n", logName))
msgBuf.WriteString(fmt.Sprintf(">Size: %d B\\n", res.Response.Items[1].Size))
msgBuf.WriteString(fmt.Sprintf("[点击下载](%s) \\n\\n", res.Response.Items[1].InternetURL))
}
}
msgStr := msgBuf.String()
if msgStr == "<nil>" || msgStr == "" {
msgStr = "<font color=\"success\">很好~</font>昨天没有产生慢查询日志\\n"
} else {
msgStr = "### 昨日CDB慢查询提醒 \\n\\n" + msgStr
}
sendMarkdownToUs(msgStr)
fmt.Println("exit...")
return
}
func sendMarkdownToUs(msgStr string) {
param := fmt.Sprintf(`{"msgtype": "markdown",
"markdown": {
"content":"%s"
}}`, msgStr)
fmt.Println(param)
resp, err := http.Post("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的企业微信机器人key",
"application/json",
strings.NewReader(param))
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
_, err = ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("send msg error")
}
return
}
func SlowLogRequest(instanceId string, ch chan SlowLogResponse, wg *sync.WaitGroup) {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
wg.Done()
}()
credential := common.NewCredential(
"",
"",
)
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = "cdb.tencentcloudapi.com"
client, _ := cdb.NewClient(credential, "ap-guangzhou", cpf)
request := cdb.NewDescribeSlowLogsRequest()
params := fmt.Sprintf(`{"InstanceId":"%s", "Limit":100}`, instanceId)
err := request.FromJsonString(params)
if err != nil {
panic(err)
}
response, err := client.DescribeSlowLogs(request)
if _, ok := err.(*errors.TencentCloudSDKError); ok {
fmt.Println(err)
return
}
if err != nil {
panic(err)
}
var slowLogResponse SlowLogResponse
err = json.Unmarshal([]byte(response.ToJsonString()), &slowLogResponse)
if err != nil {
fmt.Println(err)
return
}
ch <- slowLogResponse
return
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。