├── .gitignore ├── LICENSE ├── NOTICE ├── README.md ├── cfg.example.json ├── collector └── collector.go ├── control ├── g ├── cfg.go ├── g.go └── git.go ├── http ├── common.go ├── http.go ├── index_http.go └── proc_http.go ├── index ├── index.go ├── index_db.go ├── index_delete_task.go └── index_update_all_task.go ├── main.go ├── proc └── proc.go └── test └── debug /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | *.swp 27 | *.swo 28 | *.log 29 | .idea 30 | .DS_Store 31 | /var 32 | /falcon-task* 33 | /cfg.json 34 | /test/build 35 | 36 | cfg.json 37 | gitversion 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Open-Falcon 2 | 3 | Copyright (c) 2014-2017 Xiaomi, Inc. All Rights Reserved. 4 | 5 | This product is licensed to you under the Apache License, Version 2.0 (the "License"). 6 | You may not use this product except in compliance with the License. 7 | 8 | This product may include a number of subcomponents with separate copyright notices 9 | and license terms. Your use of these subcomponents is subject to the terms and 10 | conditions of the subcomponent's license, as noted in the LICENSE file. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | task是监控系统一个必要的辅助模块。有些功能,不适合与监控的核心业务耦合、无高可用要求、但又必不可少,我们把这部分功能拿出来 放到定时任务task模块中。 定时任务,要求单机部署,整套falcon系统中应该只有一个定时任务的服务实例。部署定时任务的服务器上,应该安装了falcon-agent、开放了1988的数据推送接口。 4 | 5 | 定时任务,实现了如下几个功能: 6 | 7 | + index更新。包括图表索引的全量更新和垃圾索引清理(是否自动清理,由配置决定)。 8 | + falcon组件[自监控](http://book.open-falcon.com/zh/practice/monitor.html)数据采集。当前,定时任务了采集了 transfer、graph、task等组建的状态数据。 9 | 10 | ## Build 11 | 12 | 我们提供了[最新的release包](https://github.com/open-falcon/task/releases),你可以直接从这里下载。或者,你也可以按照如下方式进行源码编译, 13 | 14 | ```bash 15 | # set $GOPATH and $GOROOT 16 | 17 | # update dependencies 18 | # cd $GOPATH/src/github.com/open-falcon/common && git pull 19 | 20 | mkdir -p $GOPATH/src/github.com/open-falcon 21 | cd $GOPATH/src/github.com/open-falcon 22 | git clone https://github.com/open-falcon/task.git 23 | 24 | cd task 25 | go get ./... 26 | ./control build 27 | ./control pack 28 | ``` 29 | 最后一步会pack出一个tar.gz的安装包,拿着这个包去部署服务即可。 30 | 31 | ## Deploy 32 | 服务部署,包括配置修改、启动服务、检验服务、停止服务等。这之前,需要将安装包解压到服务的部署目录下。 33 | 34 | ```bash 35 | # 修改配置, 配置项含义见下文 36 | mv cfg.example.json cfg.json 37 | vim cfg.json 38 | 39 | # 启动服务 40 | ./control start 41 | 42 | # 校验服务,这里假定服务开启了8002的http监听端口。检验结果为ok表明服务正常启动。 43 | curl -s "127.0.0.1:8002/health" 44 | 45 | ... 46 | # 停止服务 47 | ./control stop 48 | 49 | ``` 50 | 服务启动后,可以通过日志查看服务的运行状态,日志文件地址为./var/app.log。可以通过调试脚本./test/debug查看服务器的内部状态数据,如 运行 bash ./test/debug 可以得到服务器内部状态的统计信息。 51 | 52 | ## Configuration 53 | 54 | debug: true/false, 如果为true,日志中会打印debug信息 55 | 56 | http 57 | - enable: true/false, 表示是否开启该http端口,该端口为控制端口,主要用来对task发送控制命令、统计命令、debug命令等 58 | - listen: 表示http-server监听的端口 59 | 60 | index 61 | - enable: true/false, 表示是否开启索引更新任务 62 | - dsn: 索引服务的MySQL的连接信息,默认用户名是root,密码为空,host为127.0.0.1,database为graph(如有必要,请修改) 63 | - maxIdle: MySQL连接池配置,连接池允许的最大空闲连接数,保持默认即可 64 | - cluster: 后端graph索引更新的定时任务描述。一条记录的形如: "graph地址:执行周期描述",通过设置不同的执行周期,来实现负载在时间上的均衡。 65 | eg. 后端部署了两个graph实例,cluster可以配置为 66 | "cluster":{ 67 | "test.hostname01:6071" : "0 0 0 ? * 0-5", //周0-5,每天的00:00:00,开始执行索引全量更新;"0 0 0 ? * 0-5"为quartz表达式 68 | "test.hostname02:6071" : "0 30 0 ? * 0-5", //周0-5,每天的00:30:00,开始执行索引全量更新 69 | } 70 | - autoDelete: true|false, 是否自动删除垃圾索引。默认为false 71 | 72 | collector 73 | - enable: true/false, 表示是否开启falcon的自身状态采集任务 74 | - destUrl: 监控数据的push地址,默认为本机的1988接口 75 | - srcUrlFmt: 监控数据采集的url格式, %s将由机器名或域名替换 76 | - cluster: falcon后端服务列表,用具体的"module,hostname:port"表示,module取值可以为graph、transfer、task等 77 | 78 | ## 补充说明 79 | ### 关于自监控报警 80 | 因为多点监控的需求,自版本v0.0.10开始,我们将自监控报警功能 从Task模块移除。关于Open-Falcon自监控的详情,请参见[这里](http://book.open-falcon.com/zh/practice/monitor.html)。 81 | 82 | ### 关于过期索引清除 83 | 监控数据停止上报后,该数据对应的索引也会停止更新、变为过期索引。过期索引,影响视听,部分用户希望删除之。 84 | 85 | 我们原来的方案,是: 通过task模块,有数据上报的索引、每天被更新一次,7天未被更新的索引、清除之。但是,很多用户不能正确配置graph实例的http接口,导致正常上报的监控数据的索引 无法被更新;7天后,合法索引被task模块误删除。 86 | 87 | 为了解决上述问题,我们在默认配置里面,停掉了task模块自动删除过期索引的功能(autoDelete=false);如果你确定配置的index.cluster正确无误,可以自行打开该功能。 88 | 89 | 当然,我们提供了更安全的、手动删除过期索引的方法。用户按需触发索引删除操作,具体步骤为: 90 | 91 | 1.进行一次索引数据的全量更新。方法为: 针对每个graph实例,运行```curl -s "127.0.0.1:6071/index/updateAll"```,异步地触发graph实例的索引全量更新(这里假设graph的http监听端口为6071),等待所有的graph实例完成索引全量更新后 进行第2步操作。单个graph实例,索引全量更新的耗时,因counter数量、mysql数据库性能而不同,一般耗时不大于30min。 92 | 93 | 2.待索引全量更新完成后,发起过期索引删除 ``` curl -s "$Hostname.Of.Task:$Http.Port/index/delete" ```。运行索引删除前,请务必**确保索引全量更新已完成**。 94 | -------------------------------------------------------------------------------- /cfg.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug": false, 3 | "http": { 4 | "enable": true, 5 | "listen": "0.0.0.0:8002" 6 | }, 7 | "index": { 8 | "enable": false, 9 | "dsn": "root:root@tcp(127.0.0.1:3306)/graph?loc=Local&parseTime=true", 10 | "maxIdle": 4, 11 | "autoDelete": false, 12 | "cluster":{ 13 | "test.hostname01:6071" : "0 0 0 ? * 0-5", 14 | "test.hostname02:6071" : "0 30 0 ? * 0-5" 15 | } 16 | }, 17 | "collector" : { 18 | "enable": true, 19 | "destUrl" : "http://127.0.0.1:1988/v1/push", 20 | "srcUrlFmt" : "http://%s/statistics/all", 21 | "cluster" : [ 22 | "transfer,test.hostname:6060", 23 | "graph,test.hostname:6071", 24 | "task,test.hostname:8001" 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /collector/collector.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package collector 17 | 18 | import ( 19 | "bytes" 20 | "encoding/json" 21 | "fmt" 22 | "io/ioutil" 23 | "log" 24 | "net/http" 25 | "os" 26 | "strings" 27 | "time" 28 | 29 | cmodel "github.com/open-falcon/common/model" 30 | cron "github.com/toolkits/cron" 31 | nhttpclient "github.com/toolkits/http/httpclient" 32 | ntime "github.com/toolkits/time" 33 | 34 | "github.com/open-falcon/task/g" 35 | "github.com/open-falcon/task/proc" 36 | ) 37 | 38 | var ( 39 | collectorCron = cron.New() 40 | srcUrlFmt = "http://%s/statistics/all" 41 | destUrl = "http://127.0.0.1:1988/v1/push" 42 | ) 43 | 44 | func Start() { 45 | if !g.Config().Collector.Enable { 46 | log.Println("collector.Start warning, not enable") 47 | return 48 | } 49 | 50 | // init url 51 | if g.Config().Collector.DestUrl != "" { 52 | destUrl = g.Config().Collector.DestUrl 53 | } 54 | if g.Config().Collector.SrcUrlFmt != "" { 55 | srcUrlFmt = g.Config().Collector.SrcUrlFmt 56 | } 57 | // start 58 | go startCollectorCron() 59 | log.Println("collector.Start, ok") 60 | } 61 | 62 | func startCollectorCron() { 63 | collectorCron.AddFuncCC("0 * * * * ?", func() { collect() }, 1) 64 | collectorCron.Start() 65 | } 66 | 67 | func collect() { 68 | startTs := time.Now().Unix() 69 | _collect() 70 | endTs := time.Now().Unix() 71 | log.Printf("collect, start %s, ts %ds\n", ntime.FormatTs(startTs), endTs-startTs) 72 | 73 | // statistics 74 | proc.CollectorCronCnt.Incr() 75 | } 76 | 77 | func _collect() { 78 | clientGet := nhttpclient.GetHttpClient("collector.get", 10*time.Second, 20*time.Second) 79 | tags := "type=statistics,pdl=falcon" 80 | for _, host := range g.Config().Collector.Cluster { 81 | ts := time.Now().Unix() 82 | jsonList := make([]*cmodel.JsonMetaData, 0) 83 | 84 | // get statistics by http-get 85 | hostInfo := strings.Split(host, ",") // "module,hostname:port" 86 | if len(hostInfo) != 2 { 87 | continue 88 | } 89 | hostModule := hostInfo[0] 90 | hostNamePort := hostInfo[1] 91 | 92 | hostNamePortList := strings.Split(hostNamePort, ":") 93 | if len(hostNamePortList) != 2 { 94 | continue 95 | } 96 | hostName := hostNamePortList[0] 97 | hostPort := hostNamePortList[1] 98 | 99 | myTags := tags + ",module=" + hostModule + ",port=" + hostPort 100 | srcUrl := fmt.Sprintf(srcUrlFmt, hostNamePort) 101 | reqGet, _ := http.NewRequest("GET", srcUrl, nil) 102 | reqGet.Header.Set("Connection", "close") 103 | getResp, err := clientGet.Do(reqGet) 104 | if err != nil { 105 | log.Printf(hostNamePort+", get statistics error,", err) 106 | continue 107 | } 108 | defer getResp.Body.Close() 109 | 110 | body, err := ioutil.ReadAll(getResp.Body) 111 | if err != nil { 112 | log.Println(hostNamePort+", get statistics error,", err) 113 | continue 114 | } 115 | 116 | var data Dto 117 | err = json.Unmarshal(body, &data) 118 | if err != nil { 119 | log.Println(hostNamePort+", get statistics error,", err) 120 | continue 121 | } 122 | 123 | for _, item := range data.Data { 124 | if item["Name"] == nil { 125 | continue 126 | } 127 | itemName := item["Name"].(string) 128 | 129 | if item["Cnt"] != nil { 130 | var jmdCnt cmodel.JsonMetaData 131 | jmdCnt.Endpoint = hostName 132 | jmdCnt.Metric = itemName 133 | jmdCnt.Timestamp = ts 134 | jmdCnt.Step = 60 135 | jmdCnt.Value = int64(item["Cnt"].(float64)) 136 | jmdCnt.CounterType = "GAUGE" 137 | jmdCnt.Tags = myTags 138 | jsonList = append(jsonList, &jmdCnt) 139 | } 140 | 141 | if item["Qps"] != nil { 142 | var jmdQps cmodel.JsonMetaData 143 | jmdQps.Endpoint = hostName 144 | jmdQps.Metric = itemName + ".Qps" 145 | jmdQps.Timestamp = ts 146 | jmdQps.Step = 60 147 | jmdQps.Value = int64(item["Qps"].(float64)) 148 | jmdQps.CounterType = "GAUGE" 149 | jmdQps.Tags = myTags 150 | jsonList = append(jsonList, &jmdQps) 151 | } 152 | } 153 | 154 | // format result 155 | err = sendToTransfer(jsonList, destUrl) 156 | if err != nil { 157 | log.Println(hostNamePort, "send to transfer error,", err.Error()) 158 | } 159 | } 160 | 161 | // collector.alive 162 | _collectorAlive() 163 | } 164 | 165 | func _collectorAlive() error { 166 | hostname, err := os.Hostname() 167 | if err != nil { 168 | log.Println("get hostname failed,", err) 169 | return err 170 | } 171 | 172 | var jmdCnt cmodel.JsonMetaData 173 | jmdCnt.Endpoint = hostname 174 | jmdCnt.Metric = "falcon.task.alive" 175 | jmdCnt.Timestamp = time.Now().Unix() 176 | jmdCnt.Step = 60 177 | jmdCnt.Value = 0 178 | jmdCnt.CounterType = "GAUGE" 179 | jmdCnt.Tags = "" 180 | 181 | jsonList := make([]*cmodel.JsonMetaData, 0) 182 | jsonList = append(jsonList, &jmdCnt) 183 | err = sendToTransfer(jsonList, destUrl) 184 | if err != nil { 185 | log.Println("send task.alive failed,", err) 186 | return err 187 | } 188 | 189 | return nil 190 | } 191 | 192 | func sendToTransfer(items []*cmodel.JsonMetaData, destUrl string) error { 193 | if len(items) < 1 { 194 | return nil 195 | } 196 | 197 | // format result 198 | jsonBody, err := json.Marshal(items) 199 | if err != nil { 200 | return fmt.Errorf("json.Marshal failed with %v", err) 201 | } 202 | 203 | // send by http-post 204 | req, err := http.NewRequest("POST", destUrl, bytes.NewBuffer(jsonBody)) 205 | req.Header.Set("Content-Type", "application/json; charset=UTF-8") 206 | req.Header.Set("Connection", "close") 207 | clientPost := nhttpclient.GetHttpClient("collector.post", 5*time.Second, 10*time.Second) 208 | postResp, err := clientPost.Do(req) 209 | if err != nil { 210 | return fmt.Errorf("post to %s, resquest failed with %v", destUrl, err) 211 | } 212 | defer postResp.Body.Close() 213 | 214 | if postResp.StatusCode/100 != 2 { 215 | return fmt.Errorf("post to %s, got bad response %d", destUrl, postResp.StatusCode) 216 | } 217 | 218 | return nil 219 | } 220 | 221 | type Dto struct { 222 | Msg string `json:"msg"` 223 | Data []map[string]interface{} `json:"data"` 224 | } 225 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | workspace=$(cd $(dirname $0) && pwd) 3 | cd $workspace 4 | 5 | module=task 6 | app=falcon-$module 7 | conf=cfg.json 8 | pidfile=var/app.pid 9 | logfile=var/app.log 10 | 11 | mkdir -p var &>/dev/null 12 | 13 | 14 | ## build & pack 15 | function build() { 16 | commit=$(git log -1 --pretty=%h) 17 | cat < ./g/git.go 18 | package g 19 | const ( 20 | COMMIT = "$commit" 21 | ) 22 | EOF 23 | go build -o $app main.go 24 | sc=$? 25 | if [ $sc -ne 0 ];then 26 | echo "build error" 27 | exit $sc 28 | else 29 | echo -n "build ok, vsn=" 30 | ./$app -v 31 | fi 32 | } 33 | 34 | function pack() { 35 | build 36 | git log -1 --pretty=%h > gitversion 37 | version=`./$app -v` 38 | tar zcvf $app-$version.tar.gz control $app cfg.example.json gitversion ./test 39 | rm -f gitversion &>/dev/null 40 | } 41 | 42 | function packbin() { 43 | build 44 | git log -1 --pretty=%h > gitversion 45 | version=`./$app -v` 46 | tar zcvf $app-bin-$version.tar.gz $app gitversion 47 | rm -f gitversion &>/dev/null 48 | } 49 | 50 | ## opt 51 | function start() { 52 | check_pid 53 | running=$? 54 | if [ $running -gt 0 ];then 55 | echo -n "started, pid=" 56 | cat $pidfile 57 | return 1 58 | fi 59 | 60 | nohup ./$app -c $conf &> $logfile & 61 | echo $! > $pidfile 62 | echo "start ok, pid=$!" 63 | } 64 | 65 | function stop() { 66 | pid=`cat $pidfile` 67 | kill -9 $pid 68 | echo "stoped" 69 | } 70 | 71 | function restart() { 72 | stop 73 | sleep 1 74 | start 75 | } 76 | 77 | ## other 78 | function status() { 79 | check_pid 80 | running=$? 81 | if [ $running -gt 0 ];then 82 | echo -n "running, pid=" 83 | cat $pidfile 84 | else 85 | echo "stoped" 86 | fi 87 | } 88 | 89 | function version() { 90 | ./$app -vg 91 | } 92 | 93 | function tailf() { 94 | tail -f $logfile 95 | } 96 | 97 | ## internal 98 | function check_pid() { 99 | if [ -f $pidfile ];then 100 | pid=`cat $pidfile` 101 | if [ -n $pid ]; then 102 | running=`ps -p $pid|grep -v "PID TTY" |wc -l` 103 | return $running 104 | fi 105 | fi 106 | return 0 107 | } 108 | 109 | ## usage 110 | function usage() { 111 | echo "$0 build|pack|packbin|start|stop|restart|status|tail|version" 112 | } 113 | 114 | ## main 115 | action=$1 116 | case $action in 117 | ## build 118 | "build" ) 119 | build 120 | ;; 121 | "pack" ) 122 | pack 123 | ;; 124 | "packbin" ) 125 | packbin 126 | ;; 127 | ## opt 128 | "start" ) 129 | start 130 | ;; 131 | "stop" ) 132 | stop 133 | ;; 134 | "restart" ) 135 | restart 136 | ;; 137 | ## other 138 | "status" ) 139 | status 140 | ;; 141 | "version" ) 142 | version 143 | ;; 144 | "tail" ) 145 | tailf 146 | ;; 147 | * ) 148 | usage 149 | ;; 150 | esac 151 | -------------------------------------------------------------------------------- /g/cfg.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package g 17 | 18 | import ( 19 | "encoding/json" 20 | "log" 21 | "sync" 22 | 23 | "github.com/toolkits/file" 24 | ) 25 | 26 | type HttpConfig struct { 27 | Enable bool `json:"enable"` 28 | Listen string `json:"listen"` 29 | } 30 | 31 | type IndexConfig struct { 32 | Enable bool `json:"enable"` 33 | Dsn string `json:"dsn"` 34 | MaxIdle int `json:"maxIdle"` 35 | AutoDelete bool `json:"autoDelete"` 36 | Cluster map[string]string `json:"cluster"` 37 | } 38 | 39 | type CollectorConfig struct { 40 | Enable bool `json:"enable"` 41 | DestUrl string `json:"destUrl"` 42 | SrcUrlFmt string `json:"srcUrlFmt"` 43 | Cluster []string `json:"cluster"` 44 | } 45 | 46 | type PluginConfig struct { 47 | ApiUrlFmt string `json:"apiUrlFmt"` 48 | Interval int32 `json:"interval"` 49 | Concurrent int32 `json:"concurrent"` 50 | ConnectTimeout int32 `json:"connectTimeout"` 51 | RequestTimeout int32 `json:"requestTimeout"` 52 | } 53 | 54 | type CleanerConfig struct { 55 | Interval int32 `json:"interval"` 56 | } 57 | 58 | type AgentConfig struct { 59 | Enable bool `json:"enable"` 60 | Dsn string `json:"dsn"` 61 | MaxIdle int32 `json:"maxIdle"` 62 | Plugin *PluginConfig `json:"plugin"` 63 | Cleaner *CleanerConfig `json:"cleaner"` 64 | } 65 | 66 | type GlobalConfig struct { 67 | Debug bool `json:"debug"` 68 | Http *HttpConfig `json:"http"` 69 | Index *IndexConfig `json:"index"` 70 | Collector *CollectorConfig `json:"collector"` 71 | Agent *AgentConfig `json:"agent"` 72 | } 73 | 74 | var ( 75 | ConfigFile string 76 | config *GlobalConfig 77 | configLock = new(sync.RWMutex) 78 | ) 79 | 80 | func Config() *GlobalConfig { 81 | configLock.RLock() 82 | defer configLock.RUnlock() 83 | return config 84 | } 85 | 86 | func ParseConfig(cfg string) { 87 | if cfg == "" { 88 | log.Fatalln("use -c to specify configuration file") 89 | } 90 | 91 | if !file.IsExist(cfg) { 92 | log.Fatalln("config file:", cfg, "is not existent. maybe you need `mv cfg.example.json cfg.json`") 93 | } 94 | 95 | ConfigFile = cfg 96 | 97 | configContent, err := file.ToTrimString(cfg) 98 | if err != nil { 99 | log.Fatalln("read config file:", cfg, "fail:", err) 100 | } 101 | 102 | var c GlobalConfig 103 | err = json.Unmarshal([]byte(configContent), &c) 104 | if err != nil { 105 | log.Fatalln("parse config file:", cfg, "fail:", err) 106 | } 107 | 108 | configLock.Lock() 109 | defer configLock.Unlock() 110 | config = &c 111 | 112 | log.Println("g:ParseConfig ok, ", cfg) 113 | } 114 | -------------------------------------------------------------------------------- /g/g.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package g 17 | 18 | import ( 19 | "log" 20 | "runtime" 21 | ) 22 | 23 | // changelog: 24 | // 0.0.1: init project 25 | // 0.0.3: add readme, add gitversion, modify proc, add config reload 26 | // 0.0.4: make collector configurable, add monitor cron, adjust index db 27 | // Changes: send turning-ok only after alarm happens, add conn timeout for http 28 | // maybe fix bug of 'too many open files', rollback to central lib 29 | // 0.0.5: move self.monitor to anteye 30 | // 0.0.6: make index update configurable, use global time formater 31 | // 0.0.7: fix bug of index_update_all 32 | // 0.0.8: add agents' house_keeper, use relative paths in 'import' 33 | // 0.0.9: gen falcon.task.alive, use common module, use absolute paths in import 34 | // 0.0.10: rm monitor, add controller for index cleaner 35 | 36 | const ( 37 | VERSION = "0.0.10" 38 | ) 39 | 40 | func init() { 41 | runtime.GOMAXPROCS(runtime.NumCPU()) 42 | log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) 43 | } 44 | -------------------------------------------------------------------------------- /g/git.go: -------------------------------------------------------------------------------- 1 | package g 2 | const ( 3 | COMMIT = "72ff809" 4 | ) 5 | -------------------------------------------------------------------------------- /http/common.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package http 17 | 18 | import ( 19 | "fmt" 20 | "net/http" 21 | "strings" 22 | 23 | "github.com/toolkits/file" 24 | 25 | "github.com/open-falcon/task/g" 26 | ) 27 | 28 | func configCommonRoutes() { 29 | http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { 30 | w.Write([]byte("ok\n")) 31 | }) 32 | 33 | http.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) { 34 | w.Write([]byte(fmt.Sprintf("%s\n", g.VERSION))) 35 | }) 36 | 37 | http.HandleFunc("/workdir", func(w http.ResponseWriter, r *http.Request) { 38 | w.Write([]byte(fmt.Sprintf("%s\n", file.SelfDir()))) 39 | }) 40 | 41 | http.HandleFunc("/config", func(w http.ResponseWriter, r *http.Request) { 42 | RenderDataJson(w, g.Config()) 43 | }) 44 | 45 | http.HandleFunc("/config/reload", func(w http.ResponseWriter, r *http.Request) { 46 | if strings.HasPrefix(r.RemoteAddr, "127.0.0.1") { 47 | g.ParseConfig(g.ConfigFile) 48 | RenderDataJson(w, "ok") 49 | } else { 50 | RenderDataJson(w, "no privilege") 51 | } 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /http/http.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package http 17 | 18 | import ( 19 | "encoding/json" 20 | "log" 21 | "net/http" 22 | 23 | "github.com/open-falcon/task/g" 24 | ) 25 | 26 | type Dto struct { 27 | Msg string `json:"msg"` 28 | Data interface{} `json:"data"` 29 | } 30 | 31 | // start http server 32 | func Start() { 33 | go startHttpServer() 34 | } 35 | func startHttpServer() { 36 | if !g.Config().Http.Enable { 37 | return 38 | } 39 | 40 | addr := g.Config().Http.Listen 41 | if addr == "" { 42 | return 43 | } 44 | 45 | // init url mapping 46 | configCommonRoutes() 47 | configProcHttpRoutes() 48 | configIndexHttpRoutes() 49 | 50 | s := &http.Server{ 51 | Addr: addr, 52 | MaxHeaderBytes: 1 << 30, 53 | } 54 | 55 | log.Println("http:startHttpServer, ok, listening ", addr) 56 | log.Fatalln(s.ListenAndServe()) 57 | } 58 | 59 | func RenderJson(w http.ResponseWriter, v interface{}) { 60 | bs, err := json.Marshal(v) 61 | if err != nil { 62 | http.Error(w, err.Error(), http.StatusInternalServerError) 63 | return 64 | } 65 | w.Header().Set("Content-Type", "application/json; charset=UTF-8") 66 | w.Write(bs) 67 | } 68 | 69 | func RenderDataJson(w http.ResponseWriter, data interface{}) { 70 | RenderJson(w, Dto{Msg: "success", Data: data}) 71 | } 72 | 73 | func RenderMsgJson(w http.ResponseWriter, msg string) { 74 | RenderJson(w, map[string]string{"msg": msg}) 75 | } 76 | 77 | func AutoRender(w http.ResponseWriter, data interface{}, err error) { 78 | if err != nil { 79 | RenderMsgJson(w, err.Error()) 80 | return 81 | } 82 | RenderDataJson(w, data) 83 | } 84 | -------------------------------------------------------------------------------- /http/index_http.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package http 17 | 18 | import ( 19 | "net/http" 20 | 21 | "github.com/open-falcon/task/index" 22 | ) 23 | 24 | func configIndexHttpRoutes() { 25 | http.HandleFunc("/index/delete", func(w http.ResponseWriter, r *http.Request) { 26 | index.DeleteIndex() 27 | RenderDataJson(w, "ok") 28 | }) 29 | http.HandleFunc("/index/updateAll", func(w http.ResponseWriter, r *http.Request) { 30 | index.UpdateAllIndex() 31 | RenderDataJson(w, "ok") 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /http/proc_http.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package http 17 | 18 | import ( 19 | "net/http" 20 | 21 | "github.com/open-falcon/task/proc" 22 | ) 23 | 24 | func configProcHttpRoutes() { 25 | // counter 26 | http.HandleFunc("/counter/all", func(w http.ResponseWriter, r *http.Request) { 27 | RenderDataJson(w, proc.GetAll()) 28 | }) 29 | // TO BE DISCARDed 30 | http.HandleFunc("/statistics/all", func(w http.ResponseWriter, r *http.Request) { 31 | RenderDataJson(w, proc.GetAll()) 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /index/index.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package index 17 | 18 | import ( 19 | "log" 20 | 21 | "github.com/open-falcon/task/g" 22 | ) 23 | 24 | // 初始化索引功能模块 25 | func Start() { 26 | cfg := g.Config() 27 | if !cfg.Index.Enable { 28 | log.Println("index.Start warning, not enable") 29 | return 30 | } 31 | 32 | InitDB() 33 | if cfg.Index.AutoDelete { 34 | StartIndexDeleteTask() 35 | log.Println("index.Start warning, index cleaner enable") 36 | } 37 | StartIndexUpdateAllTask() 38 | log.Println("index.Start ok") 39 | } 40 | -------------------------------------------------------------------------------- /index/index_db.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package index 17 | 18 | import ( 19 | "database/sql" 20 | _ "github.com/go-sql-driver/mysql" 21 | "log" 22 | 23 | "github.com/open-falcon/task/g" 24 | ) 25 | 26 | var DB *sql.DB 27 | 28 | func InitDB() { 29 | var err error 30 | DB, err = GetDbConn() 31 | if err != nil { 32 | log.Fatalln("index:InitDB error,", err) 33 | } else { 34 | log.Println("index:InitDB ok") 35 | } 36 | } 37 | 38 | func GetDbConn() (conn *sql.DB, err error) { 39 | conn, err = sql.Open("mysql", g.Config().Index.Dsn) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | conn.SetMaxIdleConns(g.Config().Index.MaxIdle) 45 | 46 | err = conn.Ping() 47 | if err != nil { 48 | conn.Close() 49 | } 50 | 51 | return conn, err 52 | } 53 | -------------------------------------------------------------------------------- /index/index_delete_task.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package index 17 | 18 | import ( 19 | "log" 20 | "time" 21 | 22 | Mdb "github.com/open-falcon/common/db" 23 | cron "github.com/toolkits/cron" 24 | ntime "github.com/toolkits/time" 25 | 26 | "github.com/open-falcon/task/proc" 27 | ) 28 | 29 | const ( 30 | indexDeleteCronSpec = "0 0 2 ? * 6" // 每周6晚上22:00执行一次 31 | deteleStepInSec = 7 * 24 * 3600 // 索引的最大生存周期, sec 32 | ) 33 | 34 | var ( 35 | indexDeleteCron = cron.New() 36 | ) 37 | 38 | // 启动 索引全量更新 定时任务 39 | func StartIndexDeleteTask() { 40 | indexDeleteCron.AddFuncCC(indexDeleteCronSpec, func() { DeleteIndex() }, 1) 41 | indexDeleteCron.Start() 42 | } 43 | 44 | // 索引的全量更新 45 | func DeleteIndex() { 46 | startTs := time.Now().Unix() 47 | deleteIndex() 48 | endTs := time.Now().Unix() 49 | log.Printf("deleteIndex, start %s, ts %ds", ntime.FormatTs(startTs), endTs-startTs) 50 | 51 | // statistics 52 | proc.IndexDeleteCnt.Incr() 53 | } 54 | 55 | // 先select 得到可能被删除的index的信息, 然后以相同的条件delete. select和delete不是原子操作,可能有一些不一致,但不影响正确性 56 | func deleteIndex() error { 57 | dbConn, err := GetDbConn() 58 | if err != nil { 59 | log.Println("[ERROR] get dbConn fail", err) 60 | return err 61 | } 62 | defer dbConn.Close() 63 | 64 | ts := time.Now().Unix() 65 | lastTs := ts - deteleStepInSec 66 | log.Printf("deleteIndex, lastTs %d\n", lastTs) 67 | 68 | // reinit statistics 69 | proc.IndexDeleteCnt.PutOther("deleteCntEndpoint", 0) 70 | proc.IndexDeleteCnt.PutOther("deleteCntTagEndpoint", 0) 71 | proc.IndexDeleteCnt.PutOther("deleteCntEndpointCounter", 0) 72 | 73 | // endpoint表 74 | { 75 | // select 76 | rows, err := dbConn.Query("SELECT id, endpoint FROM endpoint WHERE ts < ?", lastTs) 77 | if err != nil { 78 | log.Println(err) 79 | return err 80 | } 81 | 82 | cnt := 0 83 | for rows.Next() { 84 | item := &Mdb.GraphEndpoint{} 85 | err := rows.Scan(&item.Id, &item.Endpoint) 86 | if err != nil { 87 | log.Println(err) 88 | return err 89 | } 90 | log.Println("will delete endpoint:", item) 91 | cnt++ 92 | } 93 | 94 | if err = rows.Err(); err != nil { 95 | log.Println(err) 96 | return err 97 | } 98 | 99 | // delete 100 | _, err = dbConn.Exec("DELETE FROM endpoint WHERE ts < ?", lastTs) 101 | if err != nil { 102 | log.Println(err) 103 | return err 104 | } 105 | log.Printf("delete endpoint, done, cnt %d\n", cnt) 106 | 107 | // statistics 108 | proc.IndexDeleteCnt.PutOther("deleteCntEndpoint", cnt) 109 | } 110 | 111 | // tag_endpoint表 112 | { 113 | // select 114 | rows, err := dbConn.Query("SELECT id, tag, endpoint_id FROM tag_endpoint WHERE ts < ?", lastTs) 115 | if err != nil { 116 | log.Println(err) 117 | return err 118 | } 119 | 120 | cnt := 0 121 | for rows.Next() { 122 | item := &Mdb.GraphTagEndpoint{} 123 | err := rows.Scan(&item.Id, &item.Tag, &item.EndpointId) 124 | if err != nil { 125 | log.Println(err) 126 | return err 127 | } 128 | log.Println("will delete tag_endpoint:", item) 129 | cnt++ 130 | } 131 | 132 | if err = rows.Err(); err != nil { 133 | log.Println(err) 134 | return err 135 | } 136 | 137 | // delete 138 | _, err = dbConn.Exec("DELETE FROM tag_endpoint WHERE ts < ?", lastTs) 139 | if err != nil { 140 | log.Println(err) 141 | return err 142 | } 143 | log.Printf("delete tag_endpoint, done, cnt %d\n", cnt) 144 | 145 | // statistics 146 | proc.IndexDeleteCnt.PutOther("deleteCntTagEndpoint", cnt) 147 | } 148 | // endpoint_counter表 149 | { 150 | // select 151 | rows, err := dbConn.Query("SELECT id, endpoint_id, counter FROM endpoint_counter WHERE ts < ?", lastTs) 152 | if err != nil { 153 | log.Println(err) 154 | return err 155 | } 156 | 157 | cnt := 0 158 | for rows.Next() { 159 | item := &Mdb.GraphEndpointCounter{} 160 | err := rows.Scan(&item.Id, &item.EndpointId, &item.Counter) 161 | if err != nil { 162 | log.Println(err) 163 | return err 164 | } 165 | log.Println("will delete endpoint_counter:", item) 166 | cnt++ 167 | } 168 | 169 | if err = rows.Err(); err != nil { 170 | log.Println(err) 171 | return err 172 | } 173 | 174 | // delete 175 | _, err = dbConn.Exec("DELETE FROM endpoint_counter WHERE ts < ?", lastTs) 176 | if err != nil { 177 | log.Println(err) 178 | return err 179 | } 180 | log.Printf("delete endpoint_counter, done, cnt %d\n", cnt) 181 | 182 | // statistics 183 | proc.IndexDeleteCnt.PutOther("deleteCntEndpointCounter", cnt) 184 | } 185 | 186 | return nil 187 | } 188 | -------------------------------------------------------------------------------- /index/index_update_all_task.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package index 17 | 18 | import ( 19 | "encoding/json" 20 | "fmt" 21 | "io/ioutil" 22 | "log" 23 | "net/http" 24 | "time" 25 | 26 | cron "github.com/toolkits/cron" 27 | nhttpclient "github.com/toolkits/http/httpclient" 28 | ntime "github.com/toolkits/time" 29 | 30 | "github.com/open-falcon/task/g" 31 | "github.com/open-falcon/task/proc" 32 | ) 33 | 34 | const ( 35 | destUrlFmt = "http://%s/index/updateAll" 36 | ) 37 | 38 | var ( 39 | indexUpdateAllCron = cron.New() 40 | ) 41 | 42 | // 启动 索引全量更新 定时任务 43 | func StartIndexUpdateAllTask() { 44 | for graphAddr, cronSpec := range g.Config().Index.Cluster { 45 | ga := graphAddr 46 | indexUpdateAllCron.AddFuncCC(cronSpec, func() { UpdateIndexOfOneGraph(ga, "cron") }, 1) 47 | } 48 | 49 | indexUpdateAllCron.Start() 50 | } 51 | 52 | // 手动触发全量更新 53 | func UpdateAllIndex() { 54 | for graphAddr, _ := range g.Config().Index.Cluster { 55 | UpdateIndexOfOneGraph(graphAddr, "manual") 56 | } 57 | } 58 | 59 | func UpdateIndexOfOneGraph(graphAddr string, src string) { 60 | startTs := time.Now().Unix() 61 | err := updateIndexOfOneGraph(graphAddr) 62 | endTs := time.Now().Unix() 63 | 64 | // statistics 65 | proc.IndexUpdateCnt.Incr() 66 | if err == nil { 67 | log.Printf("index update ok, %s, %s, start %s, ts %ds", 68 | src, graphAddr, ntime.FormatTs(startTs), endTs-startTs) 69 | } else { 70 | proc.IndexUpdateErrorCnt.Incr() 71 | log.Printf("index update error, %s, %s, start %s, ts %ds, reason %v", 72 | src, graphAddr, ntime.FormatTs(startTs), endTs-startTs, err) 73 | } 74 | } 75 | 76 | func updateIndexOfOneGraph(hostNamePort string) error { 77 | if hostNamePort == "" { 78 | return fmt.Errorf("index update error, bad host") 79 | } 80 | 81 | client := nhttpclient.GetHttpClient("index.update."+hostNamePort, 5*time.Second, 10*time.Second) 82 | 83 | destUrl := fmt.Sprintf(destUrlFmt, hostNamePort) 84 | req, _ := http.NewRequest("GET", destUrl, nil) 85 | req.Header.Set("Connection", "close") 86 | getResp, err := client.Do(req) 87 | if err != nil { 88 | log.Printf(hostNamePort+", index update error,", err) 89 | return err 90 | } 91 | defer getResp.Body.Close() 92 | 93 | body, err := ioutil.ReadAll(getResp.Body) 94 | if err != nil { 95 | log.Println(hostNamePort+", index update error,", err) 96 | return err 97 | } 98 | 99 | var data Dto 100 | err = json.Unmarshal(body, &data) 101 | if err != nil { 102 | log.Println(hostNamePort+", index update error,", err) 103 | return err 104 | } 105 | 106 | if data.Data != "ok" { 107 | log.Println(hostNamePort+", index update error, bad result,", data.Data) 108 | return err 109 | } 110 | 111 | return nil 112 | } 113 | 114 | type Dto struct { 115 | Msg string `json:"msg"` 116 | Data string `json:"data"` 117 | } 118 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package main 17 | 18 | import ( 19 | "flag" 20 | "fmt" 21 | "os" 22 | 23 | "github.com/open-falcon/task/collector" 24 | "github.com/open-falcon/task/g" 25 | "github.com/open-falcon/task/http" 26 | "github.com/open-falcon/task/index" 27 | "github.com/open-falcon/task/proc" 28 | ) 29 | 30 | func main() { 31 | cfg := flag.String("c", "cfg.json", "configuration file") 32 | version := flag.Bool("v", false, "show version") 33 | versionGit := flag.Bool("vg", false, "show version") 34 | flag.Parse() 35 | 36 | if *version { 37 | fmt.Println(g.VERSION) 38 | os.Exit(0) 39 | } 40 | if *versionGit { 41 | fmt.Println(g.VERSION, g.COMMIT) 42 | os.Exit(0) 43 | } 44 | 45 | // global config 46 | g.ParseConfig(*cfg) 47 | // proc 48 | proc.Start() 49 | 50 | // graph index 51 | index.Start() 52 | // collector 53 | collector.Start() 54 | 55 | // http 56 | http.Start() 57 | 58 | select {} 59 | } 60 | -------------------------------------------------------------------------------- /proc/proc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Xiaomi, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | package proc 17 | 18 | import ( 19 | nproc "github.com/toolkits/proc" 20 | "log" 21 | ) 22 | 23 | // 索引更新 24 | var ( 25 | IndexUpdateCnt = nproc.NewSCounterQps("IndexUpdateCnt") 26 | IndexUpdateErrorCnt = nproc.NewSCounterQps("IndexUpdateErrorCnt") 27 | IndexDeleteCnt = nproc.NewSCounterQps("IndexDeleteCnt") 28 | ) 29 | 30 | // 监控数据采集 31 | var ( 32 | CollectorCronCnt = nproc.NewSCounterQps("CollectorCronCnt") 33 | ) 34 | 35 | func Start() { 36 | log.Println("proc.Start ok") 37 | } 38 | 39 | func GetAll() []interface{} { 40 | ret := make([]interface{}, 0) 41 | 42 | // index 43 | ret = append(ret, IndexUpdateCnt.Get()) 44 | ret = append(ret, IndexUpdateErrorCnt.Get()) 45 | ret = append(ret, IndexDeleteCnt.Get()) 46 | 47 | // collector 48 | ret = append(ret, CollectorCronCnt.Get()) 49 | 50 | return ret 51 | } 52 | -------------------------------------------------------------------------------- /test/debug: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## test home 3 | testdir=$(cd $(dirname $0)/; pwd) 4 | ## word home 5 | workdir=$(dirname $testdir) 6 | cd $workdir 7 | 8 | module=task 9 | app=falcon-$module 10 | pidfile=var/app.pid 11 | logfile=var/app.log 12 | control=./control 13 | httpprex="127.0.0.1:8002" 14 | 15 | ## statistics 16 | function statistics(){ 17 | curl -s "$httpprex/statistics/all" | python -m json.tool 18 | } 19 | 20 | ## config 21 | function config(){ 22 | action=$1 23 | case $action in 24 | "reload") 25 | curl -s "$httpprex/config/reload" | python -m json.tool 26 | ;; 27 | *) 28 | curl -s "$httpprex/config" | python -m json.tool 29 | ;; 30 | esac 31 | } 32 | 33 | ## build 34 | function build(){ 35 | $control build 36 | } 37 | function start(){ 38 | $control start 39 | } 40 | function stop(){ 41 | $control stop 42 | } 43 | 44 | ## index 45 | function index_update_all(){ 46 | curl -s "$httpprex/index/updateAll" | python -m json.tool 47 | } 48 | 49 | function index_delete(){ 50 | curl -s "$httpprex/index/delete" | python -m json.tool 51 | } 52 | 53 | ## tail 54 | function tail_log(){ 55 | $control tail 56 | } 57 | 58 | action=$1 59 | case $action in 60 | "build") 61 | build 62 | ;; 63 | "start") 64 | start 65 | ;; 66 | "stop") 67 | stop 68 | ;; 69 | "restart") 70 | stop && build && start 71 | ;; 72 | "config") 73 | config $2 74 | ;; 75 | "index_update") 76 | index_update_all 77 | ;; 78 | "index_delete") 79 | index_delete 80 | ;; 81 | "tail") 82 | tail_log 83 | ;; 84 | *) 85 | statistics 86 | ;; 87 | esac 88 | 89 | --------------------------------------------------------------------------------