├── VERSION ├── vendor ├── github.com │ ├── BurntSushi │ │ └── toml │ │ │ ├── session.vim │ │ │ ├── COMPATIBLE │ │ │ ├── Makefile │ │ │ ├── encoding_types_1.1.go │ │ │ ├── encoding_types.go │ │ │ ├── COPYING │ │ │ ├── doc.go │ │ │ ├── type_check.go │ │ │ ├── decode_meta.go │ │ │ ├── README.md │ │ │ └── type_fields.go │ ├── ziutek │ │ └── mymysql │ │ │ ├── all.bash │ │ │ ├── mysql │ │ │ ├── field.go │ │ │ ├── status.go │ │ │ ├── interface.go │ │ │ ├── types.go │ │ │ └── utils.go │ │ │ ├── native │ │ │ ├── addons.go │ │ │ ├── common.go │ │ │ ├── LICENSE │ │ │ ├── unsafe.go-disabled │ │ │ ├── binding.go │ │ │ ├── passwd.go │ │ │ ├── prepared.go │ │ │ ├── command.go │ │ │ ├── paramvalue.go │ │ │ ├── packet.go │ │ │ └── init.go │ │ │ ├── doc.go │ │ │ └── LICENSE │ ├── stretchr │ │ └── testify │ │ │ ├── assert │ │ │ ├── assertion_format.go.tmpl │ │ │ ├── assertion_forward.go.tmpl │ │ │ ├── errors.go │ │ │ ├── forward_assertions.go │ │ │ ├── doc.go │ │ │ └── http_assertions.go │ │ │ └── LICENSE │ ├── astaxie │ │ └── beego │ │ │ ├── LICENSE │ │ │ └── logs │ │ │ ├── color.go │ │ │ ├── README.md │ │ │ ├── slack.go │ │ │ ├── jianliao.go │ │ │ ├── accesslog.go │ │ │ ├── console.go │ │ │ ├── conn.go │ │ │ ├── multifile.go │ │ │ ├── smtp.go │ │ │ └── logger.go │ ├── pkg │ │ └── errors │ │ │ ├── appveyor.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ └── stack.go │ ├── davecgh │ │ └── go-spew │ │ │ ├── LICENSE │ │ │ └── spew │ │ │ ├── bypasssafe.go │ │ │ ├── bypass.go │ │ │ └── spew.go │ ├── sebdah │ │ └── goldie │ │ │ ├── LICENSE │ │ │ ├── errors.go │ │ │ ├── README.md │ │ │ └── goldie.go │ └── pmezard │ │ └── go-difflib │ │ └── LICENSE └── vendor.json ├── fixtures ├── falconignore ├── myMon.cfg ├── setup_slave.sql ├── setup_master.sql ├── test.slave.cfg ├── test.cfg ├── test.master.cfg ├── test_innodb_result.golden ├── push_mock.go └── test_innodb_source.golden ├── .gitignore ├── NOTICE ├── metalinter.json ├── doc.go ├── common ├── doc.go ├── logger_test.go ├── mysql_test.go ├── logger.go ├── mysql.go ├── config_test.go ├── utils.go ├── utils_test.go └── config.go ├── etc └── myMon.cfg ├── CHANGES.md ├── const.go ├── metric_test.go ├── genver.sh ├── main_test.go ├── README.md ├── senddata.go ├── senddata_test.go ├── main.go ├── Makefile └── show_test.go /VERSION: -------------------------------------------------------------------------------- 1 | 0.3.0 2 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/session.vim: -------------------------------------------------------------------------------- 1 | au BufWritePost *.go silent!make tags > /dev/null 2>&1 2 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/all.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | p=github.com/ziutek/mymysql 3 | 4 | go $* $p/mysql $p/native $p/thrsafe $p/autorc $p/godrv 5 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/COMPATIBLE: -------------------------------------------------------------------------------- 1 | Compatible with TOML version 2 | [v0.4.0](https://github.com/toml-lang/toml/blob/v0.4.0/versions/en/toml-v0.4.0.md) 3 | 4 | -------------------------------------------------------------------------------- /fixtures/falconignore: -------------------------------------------------------------------------------- 1 | FalconIgnore: 2 | longest_transaction/port=3306$100 3 | Com_insert_select/isSlave=0,port=3306,readOnly=0,type=mysql 4 | # Com_test/isSlave=0,port=3306,readOnly=0,type=mysql 5 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentFormat}} 2 | func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { 3 | if h, ok := t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { 3 | if h, ok := a.t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | mymon 3 | *.out 4 | *.pyc 5 | *.log 6 | log/ 7 | admin/ 8 | grants/ 9 | .idea/ 10 | falcon_monitor 11 | 12 | innodb_.* 13 | process_.* 14 | fixtures/innodb* 15 | fixtures/process* 16 | *push_metric.txt 17 | coverage.* 18 | version.go 19 | release/.* 20 | -------------------------------------------------------------------------------- /fixtures/myMon.cfg: -------------------------------------------------------------------------------- 1 | [default] 2 | basedir=. 3 | log_dir=. 4 | ignorefile=falconignore 5 | snapshot_dir=. 6 | snapshot_day=10 7 | log_level=5 8 | falcon_client=http://127.0.0.1:1988/v1/push 9 | 10 | [mysql] 11 | user=root 12 | password=1tIsB1g3rt 13 | host=127.0.0.1 14 | port=3306 15 | -------------------------------------------------------------------------------- /fixtures/setup_slave.sql: -------------------------------------------------------------------------------- 1 | use mysql; 2 | CREATE TABLE `heartbeat` ( 3 | `ts` int(11) DEFAULT NULL 4 | ); 5 | CHANGE MASTER TO 6 | MASTER_HOST='mymon-master', 7 | MASTER_PORT=3306, 8 | MASTER_USER='slave', 9 | MASTER_PASSWORD='mypassword', 10 | MASTER_LOG_FILE='binlog.000002', 11 | MASTER_LOG_POS=155; 12 | START slave; -------------------------------------------------------------------------------- /fixtures/setup_master.sql: -------------------------------------------------------------------------------- 1 | CREATE USER slave@'%' IDENTIFIED BY 'mypassword'; 2 | GRANT SELECT, PROCESS, FILE, SUPER, REPLICATION CLIENT, REPLICATION SLAVE, RELOAD ON *.* TO slave@'%'; 3 | Flush Privileges; 4 | use mysql; 5 | CREATE TABLE `heartbeat` ( 6 | `ts` int(11) DEFAULT NULL 7 | ); 8 | insert into `heartbeat` (ts) values (1); -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/mysql/field.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | type Field struct { 4 | Catalog string 5 | Db string 6 | Table string 7 | OrgTable string 8 | Name string 9 | OrgName string 10 | DispLen uint32 11 | // Charset uint16 12 | Flags uint16 13 | Type byte 14 | Scale byte 15 | } 16 | -------------------------------------------------------------------------------- /fixtures/test.slave.cfg: -------------------------------------------------------------------------------- 1 | [default] 2 | basedir = . 3 | log_dir = ./fixtures 4 | ignore_file = ./fixtures/falconignore 5 | snapshot_dir = ./fixtures 6 | snapshot_day = 10 7 | log_level = 5 8 | falcon_client=http://127.0.0.1:1988/v1/push 9 | 10 | [mysql] 11 | user=root 12 | password=1tIsB1g3rt 13 | host=127.0.0.1 14 | port=3308 15 | -------------------------------------------------------------------------------- /fixtures/test.cfg: -------------------------------------------------------------------------------- 1 | [default] 2 | basedir = . 3 | log_dir = ./fixtures 4 | ignore_file = ./falconignore 5 | snapshot_dir = ./snapshot 6 | snapshot_day = 10 7 | log_level = 5 8 | falcon_client=http://127.0.0.1:1988/v1/push 9 | endpoint = endpoint 10 | 11 | [mysql] 12 | user=root 13 | password=1tIsB1g3rt 14 | host=127.0.0.1 15 | port=3306 16 | -------------------------------------------------------------------------------- /fixtures/test.master.cfg: -------------------------------------------------------------------------------- 1 | [default] 2 | basedir = . 3 | log_dir = ./fixtures 4 | ignore_file = ./fixtures/falconignore 5 | snapshot_dir = ./fixtures 6 | snapshot_day = 10 7 | log_level = 5 8 | falcon_client=http://127.0.0.1:1988/v1/push 9 | endpoint = endpoint 10 | 11 | [mysql] 12 | user=root 13 | password=1tIsB1g3rt 14 | host=127.0.0.1 15 | port=3306 16 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/addons.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | func NbinToNstr(nbin *[]byte) *string { 4 | if nbin == nil { 5 | return nil 6 | } 7 | str := string(*nbin) 8 | return &str 9 | } 10 | 11 | func NstrToNbin(nstr *string) *[]byte { 12 | if nstr == nil { 13 | return nil 14 | } 15 | bin := []byte(*nstr) 16 | return &bin 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | go install ./... 3 | 4 | test: install 5 | go test -v 6 | toml-test toml-test-decoder 7 | toml-test -encoder toml-test-encoder 8 | 9 | fmt: 10 | gofmt -w *.go */*.go 11 | colcheck *.go */*.go 12 | 13 | tags: 14 | find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS 15 | 16 | push: 17 | git push origin master 18 | git push github master 19 | 20 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/common.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "io" 5 | "runtime" 6 | ) 7 | 8 | var tab8s = " " 9 | 10 | func catchError(err *error) { 11 | if pv := recover(); pv != nil { 12 | switch e := pv.(type) { 13 | case runtime.Error: 14 | panic(pv) 15 | case error: 16 | if e == io.EOF { 17 | *err = io.ErrUnexpectedEOF 18 | } else { 19 | *err = e 20 | } 21 | default: 22 | panic(pv) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Open-Falcon 2 | 3 | Copyright (c) 2014-2018 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 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/forward_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs 17 | -------------------------------------------------------------------------------- /metalinter.json: -------------------------------------------------------------------------------- 1 | { 2 | "Vendor": true, 3 | "DisableAll": true, 4 | "Enable": [ 5 | "gofmt", 6 | "goimports", 7 | "interfacer", 8 | "misspell", 9 | "unconvert", 10 | "gosimple", 11 | "golint", 12 | "structcheck", 13 | "deadcode", 14 | "ineffassign", 15 | "vetshadow", 16 | "varcheck", 17 | "gas", 18 | "vet" 19 | ], 20 | "Exclude": [ 21 | ".*permissions.*", 22 | "shadows declaration at .*show.go:98" 23 | ], 24 | "Deadline": "2m" 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 astaxie 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. -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/encoding_types_1.1.go: -------------------------------------------------------------------------------- 1 | // +build !go1.2 2 | 3 | package toml 4 | 5 | // These interfaces were introduced in Go 1.2, so we add them manually when 6 | // compiling for Go 1.1. 7 | 8 | // TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here 9 | // so that Go 1.1 can be supported. 10 | type TextMarshaler interface { 11 | MarshalText() (text []byte, err error) 12 | } 13 | 14 | // TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined 15 | // here so that Go 1.1 can be supported. 16 | type TextUnmarshaler interface { 17 | UnmarshalText(text []byte) error 18 | } 19 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | // mymon is a plugin of Open-Falcon for monitoring MySQL running information. 15 | package main 16 | -------------------------------------------------------------------------------- /common/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | // Package common contains many useful functions for logging, config, etc. 15 | package common 16 | -------------------------------------------------------------------------------- /fixtures/test_innodb_result.golden: -------------------------------------------------------------------------------- 1 | 0: MetaData Metric:Innodb_mutex_spin_waits Endpoint:localhost Value:5870888 CounterType:COUNTER Tags:test_tag Timestamp:0 Step:60 2 | 1: MetaData Metric:Innodb_mutex_spin_rounds Endpoint:localhost Value:19812448 CounterType:COUNTER Tags:test_tag Timestamp:0 Step:60 3 | 2: MetaData Metric:Innodb_mutex_os_waits Endpoint:localhost Value:375285 CounterType:COUNTER Tags:test_tag Timestamp:0 Step:60 4 | 3: MetaData Metric:History_list_length Endpoint:localhost Value:35 CounterType:GAUGE Tags:test_tag Timestamp:0 Step:60 5 | 4: MetaData Metric:longest_transaction Endpoint:localhost Value:11 CounterType:GAUGE Tags:test_tag Timestamp:0 Step:60 6 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/encoding_types.go: -------------------------------------------------------------------------------- 1 | // +build go1.2 2 | 3 | package toml 4 | 5 | // In order to support Go 1.1, we define our own TextMarshaler and 6 | // TextUnmarshaler types. For Go 1.2+, we just alias them with the 7 | // standard library interfaces. 8 | 9 | import ( 10 | "encoding" 11 | ) 12 | 13 | // TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here 14 | // so that Go 1.1 can be supported. 15 | type TextMarshaler encoding.TextMarshaler 16 | 17 | // TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined 18 | // here so that Go 1.1 can be supported. 19 | type TextUnmarshaler encoding.TextUnmarshaler 20 | -------------------------------------------------------------------------------- /etc/myMon.cfg: -------------------------------------------------------------------------------- 1 | [default] 2 | # 工作目录 3 | basedir = . 4 | # 日志目录,默认日志文件为myMon.log,旧版本有log_file项,如果同时设置了,会优先采用log_file 5 | log_dir = . 6 | # 配置报警忽略的metric项,依然会上报改metric,但原有的该metric项的报警策略将不会生效 7 | ignore_file = ./falconignore 8 | # 保存快照(process, innodb status)的目录 9 | snapshot_dir = ./snapshot 10 | # 保存快照的时间(日) 11 | snapshot_day = 10 12 | # 日志级别[RFC5424] 13 | # 0 Emergency 14 | # 1 Alert 15 | # 2 Critical 16 | # 3 Error 17 | # 4 Warning 18 | # 5 Notice 19 | # 6 Informational 20 | # 7 Debug 21 | log_level = 5 22 | # falcon agent连接地址 23 | falcon_client=http://127.0.0.1:1988/v1/push 24 | # 自定义endpoint 25 | #endpoint= 26 | 27 | [mysql] 28 | # 数据库用户名 29 | user=root 30 | # 您的数据库密码 31 | password=1tIsB1g3rt 32 | # 数据库连接地址 33 | host=127.0.0.1 34 | # 数据库端口 35 | port=3306 36 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # 更新日志 2 | 3 | ## [version] - 2018-7-25 4 | 5 | 本次更新,主要是在代码规范、代码结构及代码测试上的更新,增加了少量必要的监控项。 6 | 7 | ### Added 8 | 9 | - 新增了项目的单元测试和集成测试,目前整体测试覆盖率在83.3%。 10 | - 新增了监控项`longest_transaction`、`Is_slave`、`binlog_file_size`等。 11 | - 新增了`CHANGES.md`文件。 12 | - 新增了`vendor`包管理。 13 | - 新增了源代码文件头Copyright信息。 14 | - 新增了`Makefile`文件。 15 | 16 | ### Fixed 17 | 18 | - 修复了`binlogFileSize`返回空值的bug 。 19 | - 修复了当没有`mysql.heartbeat`表或数据为空时,数组越界报错问题。 20 | 21 | ### Changed 22 | 23 | - 修改了`README.md`文件。 24 | - 修改了`NOTICE`文件。 25 | - 修改了日志级别为RFC5424标准的7个日志级别。 26 | 27 | ### Refactored 28 | 29 | - 整理了文件结构,合并了`SHOW`相关的监控变量。 30 | - 抽出了`common`包,包含数据库配置、日志配置、配置文件以及utils相关代码。 31 | - 更改了大量变量名、函数名、编码方式、注释,增强可读性并通过gometalinter语法检查。 32 | - 通过正则重构了`falconignore`文件解析相关代码。 33 | - 对部分重复代码进行了抽象重构。 34 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: build-{build}.{branch} 2 | 3 | clone_folder: C:\gopath\src\github.com\pkg\errors 4 | shallow_clone: true # for startup speed 5 | 6 | environment: 7 | GOPATH: C:\gopath 8 | 9 | platform: 10 | - x64 11 | 12 | # http://www.appveyor.com/docs/installed-software 13 | install: 14 | # some helpful output for debugging builds 15 | - go version 16 | - go env 17 | # pre-installed MinGW at C:\MinGW is 32bit only 18 | # but MSYS2 at C:\msys64 has mingw64 19 | - set PATH=C:\msys64\mingw64\bin;%PATH% 20 | - gcc --version 21 | - g++ --version 22 | 23 | build_script: 24 | - go install -v ./... 25 | 26 | test_script: 27 | - set PATH=C:\gopath\bin;%PATH% 28 | - go test -v ./... 29 | 30 | #artifacts: 31 | # - path: '%GOPATH%\bin\*.exe' 32 | deploy: off 33 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/doc.go: -------------------------------------------------------------------------------- 1 | // Package mymysql provides MySQL client API and database/sql driver. 2 | // 3 | // It can be used as a library or as a database/sql driver. 4 | // 5 | // Using as a library 6 | // 7 | // Import native or thrsafe engine. Optionally import autorc for autoreconnect connections. 8 | // 9 | // import ( 10 | // "github.com/ziutek/mymysql/mysql" 11 | // _ "github.com/ziutek/mymysql/thrsafe" // OR native 12 | // // _ "github.com/ziutek/mymysql/native" 13 | // "github.com/ziutek/mymysql/autorc" // for autoreconnect 14 | // ) 15 | // 16 | // 17 | // 18 | // Using as a Go sql driver 19 | // 20 | // Import Go standard sql package and godrv driver. 21 | // 22 | // import ( 23 | // "database/sql" 24 | // _ "github.com/ziutek/mymysql/godrv" 25 | // ) 26 | // 27 | // 28 | // 29 | package mymysql 30 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012-2016 Dave Collins 4 | 5 | Permission to use, copy, modify, and distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/mysql/status.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | type ConnStatus uint16 4 | 5 | // Status of server connection 6 | const ( 7 | SERVER_STATUS_IN_TRANS ConnStatus = 0x01 // Transaction has started 8 | SERVER_STATUS_AUTOCOMMIT ConnStatus = 0x02 // Server in auto_commit mode 9 | SERVER_STATUS_MORE_RESULTS ConnStatus = 0x04 10 | SERVER_MORE_RESULTS_EXISTS ConnStatus = 0x08 // Multi query - next query exists 11 | SERVER_QUERY_NO_GOOD_INDEX_USED ConnStatus = 0x10 12 | SERVER_QUERY_NO_INDEX_USED ConnStatus = 0x20 13 | SERVER_STATUS_CURSOR_EXISTS ConnStatus = 0x40 // Server opened a read-only non-scrollable cursor for a query 14 | SERVER_STATUS_LAST_ROW_SENT ConnStatus = 0x80 15 | 16 | SERVER_STATUS_DB_DROPPED ConnStatus = 0x100 17 | SERVER_STATUS_NO_BACKSLASH_ESCAPES ConnStatus = 0x200 18 | ) 19 | -------------------------------------------------------------------------------- /const.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package main 15 | 16 | // const about metadata 17 | const ( 18 | TimeOut = 30 19 | Origin = "GAUGE" 20 | DeltaPs = "COUNTER" 21 | ) 22 | 23 | // ValueSplitChar is the char splitting value and tag of ignore line 24 | const ValueSplitChar = `\$` 25 | 26 | // TagSplitChar is the char splitting metric and tag of ignore line 27 | const TagSplitChar = `/` 28 | -------------------------------------------------------------------------------- /common/logger_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package common 15 | 16 | import ( 17 | "testing" 18 | ) 19 | 20 | func TestLogger(t *testing.T) { 21 | conf, _ := NewConfig(testConfigFile) 22 | log := MyNewLogger(conf, "myMon.log") 23 | log.Error("error test ok") // level 3, show 24 | log.Info("info test") // level 6, do not show 25 | log.Debug("%v", *conf) // level 7, do not show 26 | } 27 | -------------------------------------------------------------------------------- /common/mysql_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package common 15 | 16 | import ( 17 | "testing" 18 | 19 | "github.com/stretchr/testify/assert" 20 | ) 21 | 22 | func TestMysqlConnect(t *testing.T) { 23 | conf, _ := NewConfig(testConfigFile) 24 | db, _ := NewMySQLConnection(conf) 25 | row, _, err := db.QueryFirst("select 1;") 26 | assert.Nil(t, err) 27 | assert.NotEmpty(t, row.Str(0)) 28 | } 29 | -------------------------------------------------------------------------------- /fixtures/push_mock.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "io/ioutil" 7 | "log" 8 | "net/http" 9 | "os" 10 | 11 | "github.com/gorilla/mux" 12 | ) 13 | 14 | // CreateEndpoint write data of mymon pushing to push_metric.txt 15 | func CreateEndpoint(w http.ResponseWriter, req *http.Request) { 16 | w.WriteHeader(200) 17 | metrics, err := ioutil.ReadAll(req.Body) 18 | if err != nil { 19 | log.Fatal(err) 20 | } 21 | f, err := os.OpenFile("./push_metric.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 22 | if err != nil { 23 | log.Fatal(err) 24 | } 25 | if _, err := f.Write(metrics); err != nil { 26 | log.Fatal(err) 27 | } 28 | if err := f.Close(); err != nil { 29 | log.Fatal(err) 30 | } 31 | } 32 | 33 | func main() { 34 | router := mux.NewRouter() 35 | router.HandleFunc("/v1/push", CreateEndpoint).Methods("POST") 36 | log.Fatal(http.ListenAndServe(":1988", router)) 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/logs/color.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 beego Author. All Rights Reserved. 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 | // +build !windows 16 | 17 | package logs 18 | 19 | import "io" 20 | 21 | type ansiColorWriter struct { 22 | w io.Writer 23 | mode outputMode 24 | } 25 | 26 | func (cw *ansiColorWriter) Write(p []byte) (int, error) { 27 | return cw.w.Write(p) 28 | } 29 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 TOML authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/sebdah/goldie/LICENSE: -------------------------------------------------------------------------------- 1 | MIT 2 | 3 | Copyright 2016 Sebastian Dahlgren 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package toml provides facilities for decoding and encoding TOML configuration 3 | files via reflection. There is also support for delaying decoding with 4 | the Primitive type, and querying the set of keys in a TOML document with the 5 | MetaData type. 6 | 7 | The specification implemented: https://github.com/toml-lang/toml 8 | 9 | The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify 10 | whether a file is a valid TOML document. It can also be used to print the 11 | type of each key in a TOML document. 12 | 13 | Testing 14 | 15 | There are two important types of tests used for this package. The first is 16 | contained inside '*_test.go' files and uses the standard Go unit testing 17 | framework. These tests are primarily devoted to holistically testing the 18 | decoder and encoder. 19 | 20 | The second type of testing is used to verify the implementation's adherence 21 | to the TOML specification. These tests have been factored into their own 22 | project: https://github.com/BurntSushi/toml-test 23 | 24 | The reason the tests are in a separate project is so that they can be used by 25 | any implementation of TOML. Namely, it is language agnostic. 26 | */ 27 | package toml 28 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell 2 | 3 | Please consider promoting this project if you find it useful. 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of the Software, 10 | and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 20 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 21 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 22 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /metric_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package main 15 | 16 | import ( 17 | "testing" 18 | 19 | "github.com/open-falcon/mymon/common" 20 | 21 | "github.com/stretchr/testify/assert" 22 | ) 23 | 24 | func TestNewMetric(t *testing.T) { 25 | conf, err := common.NewConfig(testConfigFile) 26 | if err != nil { 27 | t.Error(err) 28 | } 29 | data := NewMetric(conf, "test") 30 | assert.NotNil(t, data, "Create new metric failed!") 31 | } 32 | 33 | func TestGetIsReadOnly(t *testing.T) { 34 | //test master 35 | isReadOnlyByMaster, _ := GetIsReadOnly(dbTestMaster) 36 | assert.Equal(t, isReadOnlyByMaster, 0, "Read only judge error!") 37 | //test slave 38 | isReadOnlyBySlave, _ := GetIsReadOnly(dbTestSlave) 39 | assert.Equal(t, isReadOnlyBySlave, 1, "Read only judge error!") 40 | } 41 | -------------------------------------------------------------------------------- /common/logger.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package common 15 | 16 | import ( 17 | "fmt" 18 | 19 | "github.com/astaxie/beego/logs" 20 | ) 21 | 22 | // MyNewLogger constructor of needed logger 23 | func MyNewLogger(conf *Config, logFile string) *logs.BeeLogger { 24 | return loggerInit(conf, logFile) 25 | } 26 | 27 | func loggerInit(conf *Config, logFile string) (log *logs.BeeLogger) { 28 | log = logs.NewLogger(0) 29 | log.EnableFuncCallDepth(true) 30 | log.SetLevel(conf.Base.LogLevel) 31 | if conf.Base.LogDir == "console" { 32 | _ = log.SetLogger("console") 33 | } else { 34 | _ = log.SetLogger( 35 | "file", fmt.Sprintf( 36 | `{"filename":"%s", "level":%d, "maxlines":0, 37 | "maxsize":0, "daily":false, "maxdays":0}`, 38 | logFile, conf.Base.LogLevel)) 39 | } 40 | return 41 | } 42 | -------------------------------------------------------------------------------- /common/mysql.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package common 15 | 16 | import ( 17 | "fmt" 18 | "time" 19 | 20 | "github.com/pkg/errors" 21 | "github.com/ziutek/mymysql/mysql" 22 | _ "github.com/ziutek/mymysql/native" //with mysql 23 | ) 24 | 25 | // NewMySQLConnection the constructor of mysql connecting 26 | func NewMySQLConnection(conf *Config) (mysql.Conn, error) { 27 | return initMySQLConnection(conf) 28 | } 29 | 30 | // QueryResult the result of query 31 | func initMySQLConnection(conf *Config) (db mysql.Conn, err error) { 32 | db = mysql.New("tcp", "", fmt.Sprintf( 33 | "%s:%d", conf.DataBase.Host, conf.DataBase.Port), 34 | conf.DataBase.User, conf.DataBase.Password) 35 | db.SetTimeout(500 * time.Millisecond) 36 | if err = db.Connect(); err != nil { 37 | err = errors.Wrap(err, "Building mysql connection failed!") 38 | } 39 | return 40 | } 41 | -------------------------------------------------------------------------------- /common/config_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package common 15 | 16 | import ( 17 | "testing" 18 | 19 | "github.com/stretchr/testify/assert" 20 | ) 21 | 22 | func TestParseConfig(t *testing.T) { 23 | testCase := Config{ 24 | Base: BaseConf{ 25 | BaseDir: ".", 26 | LogDir: "./fixtures", 27 | Endpoint: "endpoint", 28 | LogFile: "", 29 | SnapshotDir: "./snapshot", 30 | IgnoreFile: "./falconignore", 31 | SnapshotDay: 10, 32 | LogLevel: 5, 33 | FalconClient: "http://127.0.0.1:1988/v1/push", 34 | }, 35 | DataBase: DatabaseConf{ 36 | User: "root", 37 | Password: "1tIsB1g3rt", 38 | Host: "127.0.0.1", 39 | Port: 3306, 40 | }, 41 | } 42 | TestFile := "../fixtures/test.cfg" 43 | conf, err := NewConfig(TestFile) 44 | assert.Nil(t, err) 45 | assert.Equal(t, testCase, *conf) 46 | } 47 | -------------------------------------------------------------------------------- /genver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Go version check 4 | GO_VERSION_MIN=$1 5 | echo "==> Checking that build is using go version >= ${GO_VERSION_MIN}..." 6 | 7 | GO_VERSION=$(go version | grep -o 'go[0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?' | tr -d 'go') 8 | 9 | 10 | IFS="." read -r -a GO_VERSION_ARR <<< "$GO_VERSION" 11 | IFS="." read -r -a GO_VERSION_REQ <<< "$GO_VERSION_MIN" 12 | 13 | if [[ ${GO_VERSION_ARR[0]} -lt ${GO_VERSION_REQ[0]} || 14 | ( ${GO_VERSION_ARR[0]} -eq ${GO_VERSION_REQ[0]} && 15 | ( ${GO_VERSION_ARR[1]} -lt ${GO_VERSION_REQ[1]} || 16 | ( ${GO_VERSION_ARR[1]} -eq ${GO_VERSION_REQ[1]} && ${GO_VERSION_ARR[2]} -lt ${GO_VERSION_REQ[2]} ))) 17 | ]]; then 18 | echo "requires go $GO_VERSION_MIN to build; found $GO_VERSION." 19 | exit 1 20 | fi 21 | 22 | ## Generate Repository Version 23 | version=$(git log --date=iso --pretty=format:"%cd @%h" -1) 24 | if [ "X${version}" == "X" ]; then 25 | version="not a git repo" 26 | fi 27 | 28 | git_dirty=$(git diff --no-ext-diff 2> /dev/null | wc -l) 29 | 30 | compile="$(date +"%F %T %z") by $(go version)" 31 | 32 | branch=$(git rev-parse --abbrev-ref HEAD) 33 | 34 | cat << EOF | gofmt > version.go 35 | package main 36 | 37 | // -version输出信息 38 | const ( 39 | Version = "${version}" 40 | Compile = "${compile}" 41 | Branch = "${branch}" 42 | GitDirty= ${git_dirty} 43 | ) 44 | EOF 45 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Dave Cheney 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/logs/README.md: -------------------------------------------------------------------------------- 1 | ## logs 2 | logs is a Go logs manager. It can use many logs adapters. The repo is inspired by `database/sql` . 3 | 4 | 5 | ## How to install? 6 | 7 | go get github.com/astaxie/beego/logs 8 | 9 | 10 | ## What adapters are supported? 11 | 12 | As of now this logs support console, file,smtp and conn. 13 | 14 | 15 | ## How to use it? 16 | 17 | First you must import it 18 | 19 | import ( 20 | "github.com/astaxie/beego/logs" 21 | ) 22 | 23 | Then init a Log (example with console adapter) 24 | 25 | log := NewLogger(10000) 26 | log.SetLogger("console", "") 27 | 28 | > the first params stand for how many channel 29 | 30 | Use it like this: 31 | 32 | log.Trace("trace") 33 | log.Info("info") 34 | log.Warn("warning") 35 | log.Debug("debug") 36 | log.Critical("critical") 37 | 38 | 39 | ## File adapter 40 | 41 | Configure file adapter like this: 42 | 43 | log := NewLogger(10000) 44 | log.SetLogger("file", `{"filename":"test.log"}`) 45 | 46 | 47 | ## Conn adapter 48 | 49 | Configure like this: 50 | 51 | log := NewLogger(1000) 52 | log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`) 53 | log.Info("info") 54 | 55 | 56 | ## Smtp adapter 57 | 58 | Configure like this: 59 | 60 | log := NewLogger(10000) 61 | log.SetLogger("smtp", `{"username":"beegotest@gmail.com","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["xiemengjun@gmail.com"]}`) 62 | log.Critical("sendmail critical") 63 | time.Sleep(time.Second * 30) 64 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Michal Derkacz 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Michal Derkacz 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /vendor/github.com/sebdah/goldie/errors.go: -------------------------------------------------------------------------------- 1 | package goldie 2 | 3 | import "fmt" 4 | 5 | // errFixtureNotFound is thrown when the fixture file could not be found. 6 | type errFixtureNotFound struct { 7 | message string 8 | } 9 | 10 | // newErrFixtureNotFound returns a new instance of the error. 11 | func newErrFixtureNotFound() errFixtureNotFound { 12 | return errFixtureNotFound{ 13 | message: "Golden fixture not found. Try running with -update flag.", 14 | } 15 | } 16 | 17 | // Error returns the error message. 18 | func (e errFixtureNotFound) Error() string { 19 | return e.message 20 | } 21 | 22 | // errFixtureMismatch is thrown when the actual and expected data is not 23 | // matching. 24 | type errFixtureMismatch struct { 25 | message string 26 | } 27 | 28 | // newErrFixtureMismatch returns a new instance of the error. 29 | func newErrFixtureMismatch(message string) errFixtureMismatch { 30 | return errFixtureMismatch{ 31 | message: message, 32 | } 33 | } 34 | 35 | func (e errFixtureMismatch) Error() string { 36 | return e.message 37 | } 38 | 39 | // errFixtureDirecetoryIsFile is thrown when the fixture directory is a file 40 | type errFixtureDirectoryIsFile struct { 41 | file string 42 | } 43 | 44 | // newFixtureDirectoryIsFile returns a new instance of the error. 45 | func newErrFixtureDirectoryIsFile(file string) errFixtureDirectoryIsFile { 46 | return errFixtureDirectoryIsFile{ 47 | file: file, 48 | } 49 | } 50 | 51 | func (e errFixtureDirectoryIsFile) Error() string { 52 | return fmt.Sprintf("fixture folder is a file: %s", e.file) 53 | } 54 | -------------------------------------------------------------------------------- /vendor/github.com/pmezard/go-difflib/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Patrick Mezard 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | The names of its contributors may not be used to endorse or promote 14 | products derived from this software without specific prior written 15 | permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 18 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. 2 | // 3 | // Example Usage 4 | // 5 | // The following is a complete example using assert in a standard test function: 6 | // import ( 7 | // "testing" 8 | // "github.com/stretchr/testify/assert" 9 | // ) 10 | // 11 | // func TestSomething(t *testing.T) { 12 | // 13 | // var a string = "Hello" 14 | // var b string = "Hello" 15 | // 16 | // assert.Equal(t, a, b, "The two words should be the same.") 17 | // 18 | // } 19 | // 20 | // if you assert many times, use the format below: 21 | // 22 | // import ( 23 | // "testing" 24 | // "github.com/stretchr/testify/assert" 25 | // ) 26 | // 27 | // func TestSomething(t *testing.T) { 28 | // assert := assert.New(t) 29 | // 30 | // var a string = "Hello" 31 | // var b string = "Hello" 32 | // 33 | // assert.Equal(a, b, "The two words should be the same.") 34 | // } 35 | // 36 | // Assertions 37 | // 38 | // Assertions allow you to easily write test code, and are global funcs in the `assert` package. 39 | // All assertion functions take, as the first argument, the `*testing.T` object provided by the 40 | // testing framework. This allows the assertion funcs to write the failings and other details to 41 | // the correct place. 42 | // 43 | // Every assertion function also takes an optional string message as the final argument, 44 | // allowing custom error messages to be appended to the message the assertion method outputs. 45 | package assert 46 | -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/logs/slack.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "time" 9 | ) 10 | 11 | // SLACKWriter implements beego LoggerInterface and is used to send jiaoliao webhook 12 | type SLACKWriter struct { 13 | WebhookURL string `json:"webhookurl"` 14 | Level int `json:"level"` 15 | } 16 | 17 | // newSLACKWriter create jiaoliao writer. 18 | func newSLACKWriter() Logger { 19 | return &SLACKWriter{Level: LevelTrace} 20 | } 21 | 22 | // Init SLACKWriter with json config string 23 | func (s *SLACKWriter) Init(jsonconfig string) error { 24 | return json.Unmarshal([]byte(jsonconfig), s) 25 | } 26 | 27 | // WriteMsg write message in smtp writer. 28 | // it will send an email with subject and only this message. 29 | func (s *SLACKWriter) WriteMsg(when time.Time, msg string, level int) error { 30 | if level > s.Level { 31 | return nil 32 | } 33 | 34 | text := fmt.Sprintf("{\"text\": \"%s %s\"}", when.Format("2006-01-02 15:04:05"), msg) 35 | 36 | form := url.Values{} 37 | form.Add("payload", text) 38 | 39 | resp, err := http.PostForm(s.WebhookURL, form) 40 | if err != nil { 41 | return err 42 | } 43 | defer resp.Body.Close() 44 | if resp.StatusCode != http.StatusOK { 45 | return fmt.Errorf("Post webhook failed %s %d", resp.Status, resp.StatusCode) 46 | } 47 | return nil 48 | } 49 | 50 | // Flush implementing method. empty. 51 | func (s *SLACKWriter) Flush() { 52 | } 53 | 54 | // Destroy implementing method. empty. 55 | func (s *SLACKWriter) Destroy() { 56 | } 57 | 58 | func init() { 59 | Register(AdapterSlack, newSLACKWriter) 60 | } 61 | -------------------------------------------------------------------------------- /main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | "time" 8 | 9 | "github.com/open-falcon/mymon/common" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | // This Test need http server to receive data 14 | // Http URL: http://127.0.0.1:1988/v1/push 15 | func TestFetchData(t *testing.T) { 16 | // init create old file to remove 17 | now := time.Now() 18 | ld := now.Add(-time.Duration(confTestMaster.Base.SnapshotDay) * 24 * time.Hour).Day() 19 | for _, prefix := range []string{"innodb", "process"} { 20 | fileName := fmt.Sprintf( 21 | "%s/%s_%s:%d", confTestMaster.Base.SnapshotDir, prefix, 22 | confTestMaster.DataBase.Host, confTestMaster.DataBase.Port) 23 | fileNameOldDay := fmt.Sprintf("%s_%d", fileName, ld) 24 | os.Create(fileNameOldDay) 25 | } 26 | // init logger 27 | Log = common.MyNewLogger(confTestMaster, "myMon.log") 28 | 29 | err := fetchData(confTestMaster, dbTestMaster) 30 | assert.Nil(t, err) 31 | assert.Equal(t, IsReadOnly, 0) 32 | assert.Equal(t, Tag, "port=3306,isSlave=0,readOnly=0,type=mysql") 33 | assert.Equal(t, IsSlave, 0) 34 | } 35 | 36 | // This Test need http server to receive data 37 | // Http URL: http://127.0.0.1:1988/v1/push 38 | func Test_Main(t *testing.T) { 39 | // init create old file to remove 40 | now := time.Now() 41 | ld := now.Add(-time.Duration(confTestMaster.Base.SnapshotDay) * 24 * time.Hour).Day() 42 | for _, prefix := range []string{"innodb", "process"} { 43 | fileName := fmt.Sprintf( 44 | "%s/%s_%s:%d", confTestMaster.Base.SnapshotDir, prefix, 45 | confTestMaster.DataBase.Host, confTestMaster.DataBase.Port) 46 | fileNameOldDay := fmt.Sprintf("%s_%d", fileName, ld) 47 | os.Create(fileNameOldDay) 48 | } 49 | main() 50 | } 51 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypasssafe.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is running on Google App Engine, compiled by GopherJS, or 17 | // "-tags safe" is added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build js appengine safe disableunsafe 20 | 21 | package spew 22 | 23 | import "reflect" 24 | 25 | const ( 26 | // UnsafeDisabled is a build-time constant which specifies whether or 27 | // not access to the unsafe package is available. 28 | UnsafeDisabled = true 29 | ) 30 | 31 | // unsafeReflectValue typically converts the passed reflect.Value into a one 32 | // that bypasses the typical safety restrictions preventing access to 33 | // unaddressable and unexported data. However, doing this relies on access to 34 | // the unsafe package. This is a stub version which simply returns the passed 35 | // reflect.Value when the unsafe package is not available. 36 | func unsafeReflectValue(v reflect.Value) reflect.Value { 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/logs/jianliao.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "time" 9 | ) 10 | 11 | // JLWriter implements beego LoggerInterface and is used to send jiaoliao webhook 12 | type JLWriter struct { 13 | AuthorName string `json:"authorname"` 14 | Title string `json:"title"` 15 | WebhookURL string `json:"webhookurl"` 16 | RedirectURL string `json:"redirecturl,omitempty"` 17 | ImageURL string `json:"imageurl,omitempty"` 18 | Level int `json:"level"` 19 | } 20 | 21 | // newJLWriter create jiaoliao writer. 22 | func newJLWriter() Logger { 23 | return &JLWriter{Level: LevelTrace} 24 | } 25 | 26 | // Init JLWriter with json config string 27 | func (s *JLWriter) Init(jsonconfig string) error { 28 | return json.Unmarshal([]byte(jsonconfig), s) 29 | } 30 | 31 | // WriteMsg write message in smtp writer. 32 | // it will send an email with subject and only this message. 33 | func (s *JLWriter) WriteMsg(when time.Time, msg string, level int) error { 34 | if level > s.Level { 35 | return nil 36 | } 37 | 38 | text := fmt.Sprintf("%s %s", when.Format("2006-01-02 15:04:05"), msg) 39 | 40 | form := url.Values{} 41 | form.Add("authorName", s.AuthorName) 42 | form.Add("title", s.Title) 43 | form.Add("text", text) 44 | if s.RedirectURL != "" { 45 | form.Add("redirectUrl", s.RedirectURL) 46 | } 47 | if s.ImageURL != "" { 48 | form.Add("imageUrl", s.ImageURL) 49 | } 50 | 51 | resp, err := http.PostForm(s.WebhookURL, form) 52 | if err != nil { 53 | return err 54 | } 55 | defer resp.Body.Close() 56 | if resp.StatusCode != http.StatusOK { 57 | return fmt.Errorf("Post webhook failed %s %d", resp.Status, resp.StatusCode) 58 | } 59 | return nil 60 | } 61 | 62 | // Flush implementing method. empty. 63 | func (s *JLWriter) Flush() { 64 | } 65 | 66 | // Destroy implementing method. empty. 67 | func (s *JLWriter) Destroy() { 68 | } 69 | 70 | func init() { 71 | Register(AdapterJianLiao, newJLWriter) 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # README.md 2 | 3 | ## Introduction 4 | 5 | mymon(MySQL-Monitor) 是Open-Falcon用来监控MySQL数据库运行状态的一个插件,采集包括global status, global variables, slave status以及innodb status等MySQL运行状态信息。 6 | 7 | ## Installation 8 | 9 | ```bash 10 | # Build 11 | go get -u github.com/open-falcon/mymon 12 | cd $GOPATH/src/github.com/open-falcon/mymon 13 | make 14 | 15 | # Add to crontab 16 | echo '* * * * * cd ${WORKPATH} && ./mymon -c etc/myMon.cfg' > /etc/cron.d/mymon 17 | ``` 18 | 19 | ## Configuration 20 | 21 | 配置文件采用INI标准。 22 | 23 | ```ini 24 | [default] 25 | basedir = . # 工作目录 26 | log_dir = ./fixtures # 日志目录,默认日志文件为myMon.log,旧版本有log_file项,如果同时设置了,会优先采用log_file 27 | ignore_file = ./falconignore # 配置忽略的metric项 28 | snapshot_dir = ./snapshot # 保存快照(process, innodb status)的目录 29 | snapshot_day = 10 # 保存快照的时间(日) 30 | log_level = 5 # 日志级别[RFC5424] 31 | # 0 LevelEmergency 32 | # 1 LevelAlert 33 | # 2 LevelCritical 34 | # 3 LevelError 35 | # 4 LevelWarning 36 | # 5 LevelNotice 37 | # 6 LevelInformational 38 | # 7 LevelDebug 39 | falcon_client=http://127.0.0.1:1988/v1/push # falcon agent连接地址 40 | 41 | [mysql] 42 | user=root # 数据库用户名 43 | password=1tIsB1g3rt # 您的数据库密码 44 | host=127.0.0.1 # 数据库连接地址 45 | port=3306 # 数据库端口 46 | ``` 47 | 48 | ## Metric 49 | 50 | 采集的metric信息,请参考./metrics.txt。该文件仅供参考,实际采集信息会根据MySQL版本、配置的不同而变化。 51 | 52 | ### ignore项 53 | ignore项配置,是用来屏蔽之前在falcon中设好的报警项,会将原有的metric更改名称之后上传,使原有的报警策略不再生效。由于falcon中的屏蔽策略,只能屏蔽endpoint级别,所以在mymon中的ignore功能是帮助提高了报警屏蔽粒度,而非忽略该metric的上报。 54 | 55 | ### 同步延迟 56 | 57 | 关于同步延迟检测的metric有两个: `Seconds_Behind_Master`、`Heartbeats_Behind_Master`。 58 | 59 | `Seconds_Behind_Master`是MySQL`SHOW SLAVE STATUS`输出的状态变量。由于低版本的MySQL还不支持HEARTBEAT_EVENT,在低版本的MySQL中该状态可能会由于IO线程假死导致测量不准确,因此mymon增加了`Heartbeats_Behind_Master`。它依赖于`pt-heartbeat`,统计基于`pt-heartbeat`生成的mysql.heartbeat表中的ts字段值与从库当前时间差。如果未配置`pt-heartbeat`,则该项上报-1值。 60 | 61 | 关于pt-heartbeat的配置使用,链接如下: 62 | https://www.percona.com/doc/percona-toolkit/LATEST/pt-heartbeat.html 63 | 64 | 65 | ## Contributors 66 | 67 | * libin 微信:libin_cc 邮件:libin_dba@xiaomi.com [OLD] 68 | * liuzidong [![Chat on gitter](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/sylzd) 邮件:liuzidong@xiaomi.com [CURRENT] -------------------------------------------------------------------------------- /common/utils.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package common 15 | 16 | import ( 17 | "fmt" 18 | "os" 19 | "strconv" 20 | "strings" 21 | "time" 22 | ) 23 | 24 | // GetFileNameDayAndOldDay get name of new file and old file 25 | func GetFileNameDayAndOldDay(conf *Config, prefix string) (string, string) { 26 | t := time.Now() 27 | ld := t.Add(-time.Duration(conf.Base.SnapshotDay) * 24 * time.Hour).Day() 28 | fileName := fmt.Sprintf( 29 | "%s/%s_%s:%d", conf.Base.SnapshotDir, prefix, 30 | conf.DataBase.Host, conf.DataBase.Port) 31 | fileNameDay := fmt.Sprintf("%s_%d", fileName, t.Day()) 32 | fileNameOldDay := fmt.Sprintf("%s_%d", fileName, ld) 33 | return fileNameDay, fileNameOldDay 34 | } 35 | 36 | // GetLastNum get file name number suffix 37 | func GetLastNum(str string, split string) int { 38 | parts := strings.Split(str, split) 39 | if len(parts) < 2 { 40 | return -1 41 | } 42 | ans, err := strconv.ParseInt(parts[1], 10, 60) 43 | if err != nil { 44 | return -2 45 | } 46 | return int(ans) 47 | } 48 | 49 | // Hostname get current hostname 50 | func Hostname(conf *Config) string { 51 | if conf.Base.Endpoint != "" { 52 | return conf.Base.Endpoint 53 | } 54 | host, err := os.Hostname() 55 | if err != nil { 56 | host = conf.DataBase.Host 57 | } 58 | return host 59 | } 60 | 61 | //CompatibleLog for making log_file and log_dir compatible 62 | func CompatibleLog(conf *Config) string { 63 | logDir := conf.Base.LogDir 64 | logFile := conf.Base.LogFile 65 | initLogFile := "myMon.log" 66 | if logFile != "" { 67 | return logFile 68 | } 69 | if logDir != "" { 70 | return fmt.Sprintf("%s/%s", logDir, initLogFile) 71 | } 72 | return initLogFile 73 | } 74 | -------------------------------------------------------------------------------- /common/utils_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | package common 14 | 15 | import ( 16 | "fmt" 17 | "strconv" 18 | "strings" 19 | "testing" 20 | 21 | "github.com/stretchr/testify/assert" 22 | ) 23 | 24 | // testConfigFile is used to make test 25 | const testConfigFile = "../fixtures/test.master.cfg" 26 | 27 | var conf *Config 28 | 29 | func init() { 30 | var err error 31 | conf, err = NewConfig(testConfigFile) 32 | if err != nil { 33 | panic(err) 34 | } 35 | } 36 | 37 | func TestGetFilenameDayAndOldDay(t *testing.T) { 38 | testCase := "test" 39 | originStr := fmt.Sprintf( 40 | "%s/%s_%s:%d_", conf.Base.SnapshotDir, testCase, 41 | conf.DataBase.Host, conf.DataBase.Port) 42 | fileNameDay, fnameOldDay := GetFileNameDayAndOldDay(conf, "test") 43 | d, _ := strconv.Atoi(strings.Split(fileNameDay, originStr)[1]) 44 | ld, _ := strconv.Atoi(strings.Split(fnameOldDay, originStr)[1]) 45 | if d > ld { 46 | assert.Equal(t, conf.Base.SnapshotDay, d-ld) 47 | } 48 | } 49 | 50 | func TestGetLastNum(t *testing.T) { 51 | testString := "tests$22" 52 | testString2 := "tests$test" 53 | assert.Equal(t, 22, GetLastNum(testString, "$")) 54 | assert.Equal(t, -1, GetLastNum(testString, "1")) 55 | assert.Equal(t, -2, GetLastNum(testString2, "$")) 56 | } 57 | 58 | func TestHostname(t *testing.T) { 59 | assert.NotNil(t, Hostname(conf)) 60 | } 61 | 62 | func TestCompatibleLog(t *testing.T) { 63 | testCases := []*Config{ 64 | {Base: BaseConf{LogDir: "."}}, 65 | {Base: BaseConf{LogDir: ".", LogFile: "./test_log"}}, 66 | {Base: BaseConf{LogFile: "./test_log"}}, 67 | {}, 68 | } 69 | expectRes := []string{ 70 | "./myMon.log", "./test_log", "./test_log", "myMon.log", 71 | } 72 | for i, logConf := range testCases { 73 | assert.Equal(t, expectRes[i], CompatibleLog(logConf)) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/README.md: -------------------------------------------------------------------------------- 1 | # errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge) 2 | 3 | Package errors provides simple error handling primitives. 4 | 5 | `go get github.com/pkg/errors` 6 | 7 | The traditional error handling idiom in Go is roughly akin to 8 | ```go 9 | if err != nil { 10 | return err 11 | } 12 | ``` 13 | which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error. 14 | 15 | ## Adding context to an error 16 | 17 | The errors.Wrap function returns a new error that adds context to the original error. For example 18 | ```go 19 | _, err := ioutil.ReadAll(r) 20 | if err != nil { 21 | return errors.Wrap(err, "read failed") 22 | } 23 | ``` 24 | ## Retrieving the cause of an error 25 | 26 | Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`. 27 | ```go 28 | type causer interface { 29 | Cause() error 30 | } 31 | ``` 32 | `errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example: 33 | ```go 34 | switch err := errors.Cause(err).(type) { 35 | case *MyError: 36 | // handle specifically 37 | default: 38 | // unknown error 39 | } 40 | ``` 41 | 42 | [Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). 43 | 44 | ## Contributing 45 | 46 | We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. 47 | 48 | Before proposing a change, please discuss your change by raising an issue. 49 | 50 | ## License 51 | 52 | BSD-2-Clause 53 | -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/logs/accesslog.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 beego Author. All Rights Reserved. 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 | package logs 16 | 17 | import ( 18 | "bytes" 19 | "encoding/json" 20 | "time" 21 | "fmt" 22 | ) 23 | 24 | const ( 25 | apacheFormatPattern = "%s - - [%s] \"%s %d %d\" %f %s %s\n" 26 | apacheFormat = "APACHE_FORMAT" 27 | jsonFormat = "JSON_FORMAT" 28 | ) 29 | 30 | // AccessLogRecord struct for holding access log data. 31 | type AccessLogRecord struct { 32 | RemoteAddr string `json:"remote_addr"` 33 | RequestTime time.Time `json:"request_time"` 34 | RequestMethod string `json:"request_method"` 35 | Request string `json:"request"` 36 | ServerProtocol string `json:"server_protocol"` 37 | Host string `json:"host"` 38 | Status int `json:"status"` 39 | BodyBytesSent int64 `json:"body_bytes_sent"` 40 | ElapsedTime time.Duration `json:"elapsed_time"` 41 | HTTPReferrer string `json:"http_referrer"` 42 | HTTPUserAgent string `json:"http_user_agent"` 43 | RemoteUser string `json:"remote_user"` 44 | } 45 | 46 | func (r *AccessLogRecord) json() ([]byte, error) { 47 | buffer := &bytes.Buffer{} 48 | encoder := json.NewEncoder(buffer) 49 | disableEscapeHTML(encoder) 50 | 51 | err := encoder.Encode(r) 52 | return buffer.Bytes(), err 53 | } 54 | 55 | func disableEscapeHTML(i interface{}) { 56 | e, ok := i.(interface { 57 | SetEscapeHTML(bool) 58 | }); 59 | if ok { 60 | e.SetEscapeHTML(false) 61 | } 62 | } 63 | 64 | // AccessLog - Format and print access log. 65 | func AccessLog(r *AccessLogRecord, format string) { 66 | var msg string 67 | 68 | switch format { 69 | 70 | case apacheFormat: 71 | timeFormatted := r.RequestTime.Format("02/Jan/2006 03:04:05") 72 | msg = fmt.Sprintf(apacheFormatPattern, r.RemoteAddr, timeFormatted, r.Request, r.Status, r.BodyBytesSent, 73 | r.ElapsedTime.Seconds(), r.HTTPReferrer, r.HTTPUserAgent) 74 | case jsonFormat: 75 | fallthrough 76 | default: 77 | jsonData, err := r.json() 78 | if err != nil { 79 | msg = fmt.Sprintf(`{"Error": "%s"}`, err) 80 | } else { 81 | msg = string(jsonData) 82 | } 83 | } 84 | 85 | beeLogger.Debug(msg) 86 | } 87 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/type_check.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | // tomlType represents any Go type that corresponds to a TOML type. 4 | // While the first draft of the TOML spec has a simplistic type system that 5 | // probably doesn't need this level of sophistication, we seem to be militating 6 | // toward adding real composite types. 7 | type tomlType interface { 8 | typeString() string 9 | } 10 | 11 | // typeEqual accepts any two types and returns true if they are equal. 12 | func typeEqual(t1, t2 tomlType) bool { 13 | if t1 == nil || t2 == nil { 14 | return false 15 | } 16 | return t1.typeString() == t2.typeString() 17 | } 18 | 19 | func typeIsHash(t tomlType) bool { 20 | return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash) 21 | } 22 | 23 | type tomlBaseType string 24 | 25 | func (btype tomlBaseType) typeString() string { 26 | return string(btype) 27 | } 28 | 29 | func (btype tomlBaseType) String() string { 30 | return btype.typeString() 31 | } 32 | 33 | var ( 34 | tomlInteger tomlBaseType = "Integer" 35 | tomlFloat tomlBaseType = "Float" 36 | tomlDatetime tomlBaseType = "Datetime" 37 | tomlString tomlBaseType = "String" 38 | tomlBool tomlBaseType = "Bool" 39 | tomlArray tomlBaseType = "Array" 40 | tomlHash tomlBaseType = "Hash" 41 | tomlArrayHash tomlBaseType = "ArrayHash" 42 | ) 43 | 44 | // typeOfPrimitive returns a tomlType of any primitive value in TOML. 45 | // Primitive values are: Integer, Float, Datetime, String and Bool. 46 | // 47 | // Passing a lexer item other than the following will cause a BUG message 48 | // to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime. 49 | func (p *parser) typeOfPrimitive(lexItem item) tomlType { 50 | switch lexItem.typ { 51 | case itemInteger: 52 | return tomlInteger 53 | case itemFloat: 54 | return tomlFloat 55 | case itemDatetime: 56 | return tomlDatetime 57 | case itemString: 58 | return tomlString 59 | case itemMultilineString: 60 | return tomlString 61 | case itemRawString: 62 | return tomlString 63 | case itemRawMultilineString: 64 | return tomlString 65 | case itemBool: 66 | return tomlBool 67 | } 68 | p.bug("Cannot infer primitive type of lex item '%s'.", lexItem) 69 | panic("unreachable") 70 | } 71 | 72 | // typeOfArray returns a tomlType for an array given a list of types of its 73 | // values. 74 | // 75 | // In the current spec, if an array is homogeneous, then its type is always 76 | // "Array". If the array is not homogeneous, an error is generated. 77 | func (p *parser) typeOfArray(types []tomlType) tomlType { 78 | // Empty arrays are cool. 79 | if len(types) == 0 { 80 | return tomlArray 81 | } 82 | 83 | theType := types[0] 84 | for _, t := range types[1:] { 85 | if !typeEqual(theType, t) { 86 | p.panicf("Array contains values of type '%s' and '%s', but "+ 87 | "arrays must be homogeneous.", theType, t) 88 | } 89 | } 90 | return tomlArray 91 | } 92 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "ignore": "test", 4 | "package": [ 5 | { 6 | "checksumSHA1": "Pc2ORQp+VY3Un/dkh4QwLC7R6lE=", 7 | "path": "github.com/BurntSushi/toml", 8 | "revision": "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005", 9 | "revisionTime": "2018-08-15T10:47:33Z" 10 | }, 11 | { 12 | "checksumSHA1": "ochJai7DifamCfjDhMQGZYrqrDE=", 13 | "path": "github.com/astaxie/beego/logs", 14 | "revision": "08c3ca642eb437f1dd65a617e107bdd9aafb66b0", 15 | "revisionTime": "2018-07-08T08:11:35Z" 16 | }, 17 | { 18 | "checksumSHA1": "dvabztWVQX8f6oMLRyv4dLH+TGY=", 19 | "origin": "github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew", 20 | "path": "github.com/davecgh/go-spew/spew", 21 | "revision": "f35b8ab0b5a2cef36673838d662e249dd9c94686", 22 | "revisionTime": "2018-05-06T18:05:49Z" 23 | }, 24 | { 25 | "checksumSHA1": "+k58oVsPE5qcJOpN7om0nezEE1o=", 26 | "path": "github.com/gpmgo/gopm/modules/log", 27 | "revision": "7edb73a0f439c016ee40b6608bc271c7fc4462e9", 28 | "revisionTime": "2017-07-27T21:13:37Z" 29 | }, 30 | { 31 | "checksumSHA1": "ljd3FhYRJ91cLZz3wsH9BQQ2JbA=", 32 | "path": "github.com/pkg/errors", 33 | "revision": "816c9085562cd7ee03e7f8188a1cfd942858cded", 34 | "revisionTime": "2018-03-11T21:45:15Z" 35 | }, 36 | { 37 | "checksumSHA1": "LuFv4/jlrmFNnDb/5SCSEPAM9vU=", 38 | "origin": "github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib", 39 | "path": "github.com/pmezard/go-difflib/difflib", 40 | "revision": "f35b8ab0b5a2cef36673838d662e249dd9c94686", 41 | "revisionTime": "2018-05-06T18:05:49Z" 42 | }, 43 | { 44 | "checksumSHA1": "xdpUw0E6MSlz1V5Oo/d2qDngv6s=", 45 | "path": "github.com/sebdah/goldie", 46 | "revision": "8784dd1ab561dcf43d141f6678e9e41f3d0dff55", 47 | "revisionTime": "2018-04-24T09:14:53Z" 48 | }, 49 | { 50 | "checksumSHA1": "c6pbpF7eowwO59phRTpF8cQ80Z0=", 51 | "path": "github.com/stretchr/testify/assert", 52 | "revision": "f35b8ab0b5a2cef36673838d662e249dd9c94686", 53 | "revisionTime": "2018-05-06T18:05:49Z" 54 | }, 55 | { 56 | "checksumSHA1": "yzQ4bFHhAZllbMmChdtumg3QWz8=", 57 | "path": "github.com/ziutek/mymysql", 58 | "revision": "6b05b0cf718f8ee11bc5e18fe78ea7cef0388dc6", 59 | "revisionTime": "2018-08-27T08:56:28Z" 60 | }, 61 | { 62 | "checksumSHA1": "oRXWHvweXZQ99jtuUtYVvKv8oI0=", 63 | "path": "github.com/ziutek/mymysql/mysql", 64 | "revision": "d069a5a9cd08c04a2dba12c031dd65c2753f6454", 65 | "revisionTime": "2018-08-14T11:55:21Z" 66 | }, 67 | { 68 | "checksumSHA1": "m3s+OrOHAMX0seOVfuDwt766BQE=", 69 | "path": "github.com/ziutek/mymysql/native", 70 | "revision": "d069a5a9cd08c04a2dba12c031dd65c2753f6454", 71 | "revisionTime": "2018-08-14T11:55:21Z" 72 | }, 73 | { 74 | "path": "golang.org/x/mnet/context", 75 | "revision": "" 76 | } 77 | ], 78 | "rootPath": "github.com/open-falcon/mymon" 79 | } 80 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/unsafe.go-disabled: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "github.com/ziutek/mymysql/mysql" 5 | "time" 6 | "unsafe" 7 | ) 8 | 9 | type paramValue struct { 10 | typ uint16 11 | addr unsafe.Pointer 12 | raw bool 13 | length int // >=0 - length of value, <0 - unknown length 14 | } 15 | 16 | func (pv *paramValue) SetAddr(addr uintptr) { 17 | pv.addr = unsafe.Pointer(addr) 18 | } 19 | 20 | func (val *paramValue) Len() int { 21 | if val.addr == nil { 22 | // Invalid Value was binded 23 | return 0 24 | } 25 | // val.addr always points to the pointer - lets dereference it 26 | ptr := *(*unsafe.Pointer)(val.addr) 27 | if ptr == nil { 28 | // Binded Ptr Value is nil 29 | return 0 30 | } 31 | 32 | if val.length >= 0 { 33 | return val.length 34 | } 35 | 36 | switch val.typ { 37 | case MYSQL_TYPE_STRING: 38 | return lenStr(*(*string)(ptr)) 39 | 40 | case MYSQL_TYPE_DATE: 41 | return lenDate(*(*mysql.Date)(ptr)) 42 | 43 | case MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_DATETIME: 44 | return lenTime(*(*time.Time)(ptr)) 45 | 46 | case MYSQL_TYPE_TIME: 47 | return lenDuration(*(*time.Duration)(ptr)) 48 | 49 | case MYSQL_TYPE_TINY: // val.length < 0 so this is bool 50 | return 1 51 | } 52 | // MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_BLOB and type of Raw value 53 | return lenBin(*(*[]byte)(ptr)) 54 | } 55 | 56 | func (pw *pktWriter) writeValue(val *paramValue) { 57 | if val.addr == nil { 58 | // Invalid Value was binded 59 | return 60 | } 61 | // val.addr always points to the pointer - lets dereference it 62 | ptr := *(*unsafe.Pointer)(val.addr) 63 | if ptr == nil { 64 | // Binded Ptr Value is nil 65 | return 66 | } 67 | 68 | if val.raw || val.typ == MYSQL_TYPE_VAR_STRING || 69 | val.typ == MYSQL_TYPE_BLOB { 70 | pw.writeBin(*(*[]byte)(ptr)) 71 | return 72 | } 73 | // We don't need unsigned bit to check type 74 | switch val.typ & ^MYSQL_UNSIGNED_MASK { 75 | case MYSQL_TYPE_NULL: 76 | // Don't write null values 77 | 78 | case MYSQL_TYPE_STRING: 79 | s := *(*string)(ptr) 80 | pw.writeBin([]byte(s)) 81 | 82 | case MYSQL_TYPE_LONG, MYSQL_TYPE_FLOAT: 83 | pw.writeU32(*(*uint32)(ptr)) 84 | 85 | case MYSQL_TYPE_SHORT: 86 | pw.writeU16(*(*uint16)(ptr)) 87 | 88 | case MYSQL_TYPE_TINY: 89 | if val.length == -1 { 90 | // Translate bool value to MySQL tiny 91 | if *(*bool)(ptr) { 92 | pw.writeByte(1) 93 | } else { 94 | pw.writeByte(0) 95 | } 96 | } else { 97 | pw.writeByte(*(*byte)(ptr)) 98 | } 99 | 100 | case MYSQL_TYPE_LONGLONG, MYSQL_TYPE_DOUBLE: 101 | pw.writeU64(*(*uint64)(ptr)) 102 | 103 | case MYSQL_TYPE_DATE: 104 | pw.writeDate(*(*mysql.Date)(ptr)) 105 | 106 | case MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_DATETIME: 107 | pw.writeTime(*(*time.Time)(ptr)) 108 | 109 | case MYSQL_TYPE_TIME: 110 | pw.writeDuration(*(*time.Duration)(ptr)) 111 | 112 | default: 113 | panic(mysql.ErrBindUnkType) 114 | } 115 | return 116 | } 117 | -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/logs/console.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 beego Author. All Rights Reserved. 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 | package logs 16 | 17 | import ( 18 | "encoding/json" 19 | "os" 20 | "runtime" 21 | "time" 22 | ) 23 | 24 | // brush is a color join function 25 | type brush func(string) string 26 | 27 | // newBrush return a fix color Brush 28 | func newBrush(color string) brush { 29 | pre := "\033[" 30 | reset := "\033[0m" 31 | return func(text string) string { 32 | return pre + color + "m" + text + reset 33 | } 34 | } 35 | 36 | var colors = []brush{ 37 | newBrush("1;37"), // Emergency white 38 | newBrush("1;36"), // Alert cyan 39 | newBrush("1;35"), // Critical magenta 40 | newBrush("1;31"), // Error red 41 | newBrush("1;33"), // Warning yellow 42 | newBrush("1;32"), // Notice green 43 | newBrush("1;34"), // Informational blue 44 | newBrush("1;44"), // Debug Background blue 45 | } 46 | 47 | // consoleWriter implements LoggerInterface and writes messages to terminal. 48 | type consoleWriter struct { 49 | lg *logWriter 50 | Level int `json:"level"` 51 | Colorful bool `json:"color"` //this filed is useful only when system's terminal supports color 52 | } 53 | 54 | // NewConsole create ConsoleWriter returning as LoggerInterface. 55 | func NewConsole() Logger { 56 | cw := &consoleWriter{ 57 | lg: newLogWriter(os.Stdout), 58 | Level: LevelDebug, 59 | Colorful: runtime.GOOS != "windows", 60 | } 61 | return cw 62 | } 63 | 64 | // Init init console logger. 65 | // jsonConfig like '{"level":LevelTrace}'. 66 | func (c *consoleWriter) Init(jsonConfig string) error { 67 | if len(jsonConfig) == 0 { 68 | return nil 69 | } 70 | err := json.Unmarshal([]byte(jsonConfig), c) 71 | if runtime.GOOS == "windows" { 72 | c.Colorful = false 73 | } 74 | return err 75 | } 76 | 77 | // WriteMsg write message in console. 78 | func (c *consoleWriter) WriteMsg(when time.Time, msg string, level int) error { 79 | if level > c.Level { 80 | return nil 81 | } 82 | if c.Colorful { 83 | msg = colors[level](msg) 84 | } 85 | c.lg.println(when, msg) 86 | return nil 87 | } 88 | 89 | // Destroy implementing method. empty. 90 | func (c *consoleWriter) Destroy() { 91 | 92 | } 93 | 94 | // Flush implementing method. empty. 95 | func (c *consoleWriter) Flush() { 96 | 97 | } 98 | 99 | func init() { 100 | Register(AdapterConsole, NewConsole) 101 | } 102 | -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/logs/conn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 beego Author. All Rights Reserved. 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 | package logs 16 | 17 | import ( 18 | "encoding/json" 19 | "io" 20 | "net" 21 | "time" 22 | ) 23 | 24 | // connWriter implements LoggerInterface. 25 | // it writes messages in keep-live tcp connection. 26 | type connWriter struct { 27 | lg *logWriter 28 | innerWriter io.WriteCloser 29 | ReconnectOnMsg bool `json:"reconnectOnMsg"` 30 | Reconnect bool `json:"reconnect"` 31 | Net string `json:"net"` 32 | Addr string `json:"addr"` 33 | Level int `json:"level"` 34 | } 35 | 36 | // NewConn create new ConnWrite returning as LoggerInterface. 37 | func NewConn() Logger { 38 | conn := new(connWriter) 39 | conn.Level = LevelTrace 40 | return conn 41 | } 42 | 43 | // Init init connection writer with json config. 44 | // json config only need key "level". 45 | func (c *connWriter) Init(jsonConfig string) error { 46 | return json.Unmarshal([]byte(jsonConfig), c) 47 | } 48 | 49 | // WriteMsg write message in connection. 50 | // if connection is down, try to re-connect. 51 | func (c *connWriter) WriteMsg(when time.Time, msg string, level int) error { 52 | if level > c.Level { 53 | return nil 54 | } 55 | if c.needToConnectOnMsg() { 56 | err := c.connect() 57 | if err != nil { 58 | return err 59 | } 60 | } 61 | 62 | if c.ReconnectOnMsg { 63 | defer c.innerWriter.Close() 64 | } 65 | 66 | c.lg.println(when, msg) 67 | return nil 68 | } 69 | 70 | // Flush implementing method. empty. 71 | func (c *connWriter) Flush() { 72 | 73 | } 74 | 75 | // Destroy destroy connection writer and close tcp listener. 76 | func (c *connWriter) Destroy() { 77 | if c.innerWriter != nil { 78 | c.innerWriter.Close() 79 | } 80 | } 81 | 82 | func (c *connWriter) connect() error { 83 | if c.innerWriter != nil { 84 | c.innerWriter.Close() 85 | c.innerWriter = nil 86 | } 87 | 88 | conn, err := net.Dial(c.Net, c.Addr) 89 | if err != nil { 90 | return err 91 | } 92 | 93 | if tcpConn, ok := conn.(*net.TCPConn); ok { 94 | tcpConn.SetKeepAlive(true) 95 | } 96 | 97 | c.innerWriter = conn 98 | c.lg = newLogWriter(conn) 99 | return nil 100 | } 101 | 102 | func (c *connWriter) needToConnectOnMsg() bool { 103 | if c.Reconnect { 104 | c.Reconnect = false 105 | return true 106 | } 107 | 108 | if c.innerWriter == nil { 109 | return true 110 | } 111 | 112 | return c.ReconnectOnMsg 113 | } 114 | 115 | func init() { 116 | Register(AdapterConn, NewConn) 117 | } 118 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/mysql/interface.go: -------------------------------------------------------------------------------- 1 | // Package mysql is a MySQL Client API written entirely in Go without any external dependences. 2 | package mysql 3 | 4 | import ( 5 | "net" 6 | "time" 7 | ) 8 | 9 | // ConnCommon is a common interface for the connection. 10 | // See mymysql/native for method documentation. 11 | type ConnCommon interface { 12 | Start(sql string, params ...interface{}) (Result, error) 13 | Prepare(sql string) (Stmt, error) 14 | 15 | Ping() error 16 | ThreadId() uint32 17 | Escape(txt string) string 18 | 19 | Query(sql string, params ...interface{}) ([]Row, Result, error) 20 | QueryFirst(sql string, params ...interface{}) (Row, Result, error) 21 | QueryLast(sql string, params ...interface{}) (Row, Result, error) 22 | } 23 | 24 | // Dialer can be used to dial connections to MySQL. If Dialer returns (nil, nil) 25 | // the hook is skipped and normal dialing proceeds. 26 | type Dialer func(proto, laddr, raddr string, timeout time.Duration) (net.Conn, error) 27 | 28 | // Conn represents connection to the MySQL server. 29 | // See mymysql/native for method documentation. 30 | type Conn interface { 31 | ConnCommon 32 | 33 | Clone() Conn 34 | SetTimeout(time.Duration) 35 | Connect() error 36 | NetConn() net.Conn 37 | SetDialer(Dialer) 38 | Close() error 39 | IsConnected() bool 40 | Reconnect() error 41 | Use(dbname string) error 42 | Register(sql string) 43 | SetMaxPktSize(new_size int) int 44 | NarrowTypeSet(narrow bool) 45 | FullFieldInfo(full bool) 46 | Status() ConnStatus 47 | Credentials() (user, passwd string) 48 | 49 | Begin() (Transaction, error) 50 | } 51 | 52 | // Transaction represents MySQL transaction. 53 | // See mymysql/native for method documentation. 54 | type Transaction interface { 55 | ConnCommon 56 | 57 | Commit() error 58 | Rollback() error 59 | Do(st Stmt) Stmt 60 | IsValid() bool 61 | } 62 | 63 | // Stmt represents MySQL prepared statement. 64 | // See mymysql/native for method documentation. 65 | type Stmt interface { 66 | Bind(params ...interface{}) 67 | Run(params ...interface{}) (Result, error) 68 | Delete() error 69 | Reset() error 70 | SendLongData(pnum int, data interface{}, pkt_size int) error 71 | 72 | Fields() []*Field 73 | NumParam() int 74 | WarnCount() int 75 | 76 | Exec(params ...interface{}) ([]Row, Result, error) 77 | ExecFirst(params ...interface{}) (Row, Result, error) 78 | ExecLast(params ...interface{}) (Row, Result, error) 79 | } 80 | 81 | // Result represents one MySQL result set. 82 | // See mymysql/native for method documentation. 83 | type Result interface { 84 | StatusOnly() bool 85 | ScanRow(Row) error 86 | GetRow() (Row, error) 87 | 88 | MoreResults() bool 89 | NextResult() (Result, error) 90 | 91 | Fields() []*Field 92 | Map(string) int 93 | Message() string 94 | AffectedRows() uint64 95 | InsertId() uint64 96 | WarnCount() int 97 | 98 | MakeRow() Row 99 | GetRows() ([]Row, error) 100 | End() error 101 | GetFirstRow() (Row, error) 102 | GetLastRow() (Row, error) 103 | } 104 | 105 | // New can be used to establish a connection. It is set by imported engine 106 | // (see mymysql/native, mymysql/thrsafe). 107 | var New func(proto, laddr, raddr, user, passwd string, db ...string) Conn 108 | -------------------------------------------------------------------------------- /senddata.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package main 15 | 16 | import ( 17 | "bytes" 18 | "encoding/json" 19 | "io/ioutil" 20 | "net/http" 21 | "os" 22 | "reflect" 23 | "regexp" 24 | "sort" 25 | "strings" 26 | 27 | "github.com/open-falcon/mymon/common" 28 | ) 29 | 30 | // SendData Post the json of all result to falcon-agent 31 | func SendData(conf *common.Config, data []*MetaData) ([]byte, error) { 32 | js, err := json.Marshal(data) 33 | if err != nil { 34 | Log.Debug("parse json data error: %+v", err) 35 | return nil, err 36 | } 37 | Log.Info("Send to %s, size: %d", conf.Base.FalconClient, len(data)) 38 | for _, m := range data { 39 | Log.Info("%v", m) 40 | } 41 | 42 | res, err := http.Post(conf.Base.FalconClient, "Content-Type: application/json", bytes.NewBuffer(js)) 43 | if err != nil { 44 | Log.Debug("send data to falcon-agent error: %+v", err) 45 | return nil, err 46 | } 47 | 48 | defer func() { _ = res.Body.Close() }() 49 | return ioutil.ReadAll(res.Body) 50 | } 51 | 52 | func parseLine(line string) map[string]string { 53 | var parseRes map[string]string 54 | // remove space and \n 55 | line = strings.Replace(strings.TrimSpace(line), "\n", "", -1) 56 | 57 | // match metric, tag and value 58 | reMetricTagValue, _ := regexp.Compile("^([0-9A-Za-z_,]+)" + TagSplitChar + "?([0-9A-Za-z_,=]*)" + ValueSplitChar + "?([0-9A-Za-z_]*)$") 59 | matchMetricTagValue := reMetricTagValue.FindSubmatch([]byte(line)) 60 | if len(matchMetricTagValue) > 0 { 61 | parseRes = map[string]string{ 62 | "metric": string(matchMetricTagValue[1]), 63 | "tag": string(matchMetricTagValue[2]), 64 | "value": string(matchMetricTagValue[3]), 65 | } 66 | } else { 67 | Log.Info("Error format of ignorefile: %s", line) 68 | } 69 | return parseRes 70 | } 71 | 72 | func tagSame(tag1, tag2 string) bool { 73 | x, y := strings.Split(tag1, ","), strings.Split(tag2, ",") 74 | sort.Strings(x) 75 | sort.Strings(y) 76 | return reflect.DeepEqual(x, y) 77 | } 78 | 79 | // Snapshot make a record of note, some metric should be noted before sending 80 | func Snapshot(conf *common.Config, note string, fileNameDay string, fileNameOldDay string) error { 81 | if conf.Base.SnapshotDay < 0 { 82 | // Just remind but do not stop 83 | Log.Info("snapshot_day setted error!") 84 | } 85 | f, err := os.OpenFile(fileNameDay, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) 86 | if err != nil { 87 | Log.Debug("open snapshot file %s error: %+v", fileNameDay, err) 88 | return err 89 | } 90 | defer f.Close() 91 | _, err = f.WriteString(note) 92 | if err != nil { 93 | Log.Debug("write info to snapshot file error: %+v", err) 94 | return err 95 | } 96 | e := os.Remove(fileNameOldDay) 97 | if e != nil { 98 | // Just remind but do not stop 99 | Log.Info("Error remove %s, %s", fileNameOldDay, e.Error()) 100 | } 101 | return err 102 | } 103 | -------------------------------------------------------------------------------- /common/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package common 15 | 16 | import ( 17 | "fmt" 18 | "os" 19 | 20 | "github.com/go-ini/ini" 21 | ) 22 | 23 | // BaseConf config about dir, log, etc. 24 | type BaseConf struct { 25 | BaseDir string 26 | SnapshotDir string 27 | SnapshotDay int 28 | LogDir string 29 | Endpoint string 30 | LogFile string 31 | LogLevel int 32 | FalconClient string 33 | IgnoreFile string 34 | } 35 | 36 | // DatabaseConf config about database 37 | type DatabaseConf struct { 38 | User string 39 | Password string 40 | Host string 41 | Port int 42 | } 43 | 44 | // Config for initializing. This can be loaded from TOML file with -c 45 | type Config struct { 46 | Base BaseConf 47 | DataBase DatabaseConf 48 | } 49 | 50 | // NewConfig the constructor of config 51 | func NewConfig(file string) (*Config, error) { 52 | conf, err := readConf(file) 53 | return &conf, err 54 | } 55 | 56 | func readConf(file string) (conf Config, err error) { 57 | _, err = os.Stat(file) 58 | if err != nil { 59 | file = fmt.Sprint("etc/", file) 60 | _, err = os.Stat(file) 61 | if err != nil { 62 | panic(err) 63 | } 64 | } 65 | cfg, err := ini.Load(file) 66 | if err != nil { 67 | panic(err) 68 | } 69 | snapshotDay, err := cfg.Section("default").Key("snapshot_day").Int() 70 | if err != nil { 71 | fmt.Println("No Snapshot!") 72 | snapshotDay = -1 73 | } 74 | logLevel, err := cfg.Section("default").Key("log_level").Int() 75 | if err != nil { 76 | fmt.Println("Log level default: 7!") 77 | logLevel = 7 78 | } 79 | host := cfg.Section("mysql").Key("host").String() 80 | if host == "" { 81 | fmt.Println("Host default: 127.0.0.1!") 82 | host = "127.0.0.1" 83 | } 84 | snapshotDir := cfg.Section("default").Key("snapshot_dir").String() 85 | if snapshotDir == "" { 86 | fmt.Println("SnapshotDir default current dir ") 87 | snapshotDir = "." 88 | } 89 | port, err := cfg.Section("mysql").Key("port").Int() 90 | if err != nil { 91 | fmt.Println("Port: default 3306!") 92 | port = 3306 93 | err = nil 94 | } 95 | conf = Config{ 96 | BaseConf{ 97 | BaseDir: cfg.Section("default").Key("basedir").String(), 98 | SnapshotDir: snapshotDir, 99 | SnapshotDay: snapshotDay, 100 | LogDir: cfg.Section("default").Key("log_dir").String(), 101 | LogFile: cfg.Section("default").Key("log_file").String(), 102 | Endpoint: cfg.Section("default").Key("endpoint").String(), 103 | LogLevel: logLevel, 104 | FalconClient: cfg.Section("default").Key("falcon_client").String(), 105 | IgnoreFile: cfg.Section("default").Key("ignore_file").String(), 106 | }, 107 | DatabaseConf{ 108 | User: cfg.Section("mysql").Key("user").String(), 109 | Password: cfg.Section("mysql").Key("password").String(), 110 | Host: host, 111 | Port: port, 112 | }, 113 | } 114 | return 115 | } 116 | -------------------------------------------------------------------------------- /senddata_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package main 15 | 16 | import ( 17 | "io/ioutil" 18 | "os" 19 | "testing" 20 | 21 | "github.com/stretchr/testify/assert" 22 | ) 23 | 24 | func TestFilterIgnoreData(t *testing.T) { 25 | testDataMetrics := []*MetaData{ 26 | //no ignore 27 | { 28 | Metric: "testMetric", 29 | Endpoint: "localhost", 30 | CounterType: "type", 31 | Value: "test", 32 | Tags: "tag", 33 | Timestamp: 66, 34 | Step: 60, 35 | }, 36 | //ignore: longest_transaction/port=3306$100 37 | { 38 | Metric: "longest_transaction", 39 | Endpoint: "localhost", 40 | CounterType: "type", 41 | Value: 1, 42 | Tags: "port=3306", 43 | Timestamp: 66, 44 | Step: 60, 45 | }, 46 | //ignore: Com_insert_select/isSlave=0,port=3306,readOnly=0,type=mysql 47 | { 48 | Metric: "Com_insert_select", 49 | Endpoint: "localhost", 50 | CounterType: "type", 51 | Value: 1, 52 | Tags: "isSlave=0,port=3306,type=mysql,readOnly=0", 53 | Timestamp: 66, 54 | Step: 60, 55 | }, 56 | } 57 | metricsExpectResult := []*MetaData{ 58 | { 59 | Metric: "testMetric", 60 | Endpoint: "localhost", 61 | CounterType: "type", 62 | Value: "test", 63 | Tags: "tag", 64 | Timestamp: 66, 65 | Step: 60, 66 | }, 67 | { 68 | Metric: "longest_transaction", 69 | Endpoint: "localhost", 70 | CounterType: "type", 71 | //change value 72 | Value: "100", 73 | Tags: "port=3306", 74 | Timestamp: 66, 75 | Step: 60, 76 | }, 77 | { 78 | //change name 79 | Metric: "_Com_insert_select", 80 | Endpoint: "localhost", 81 | CounterType: "type", 82 | Value: 1, 83 | Tags: "isSlave=0,port=3306,type=mysql,readOnly=0", 84 | Timestamp: 66, 85 | Step: 60, 86 | }, 87 | } 88 | resDataMetrics := filterIgnoreData(confTestMaster, testDataMetrics) 89 | assert.EqualValues(t, metricsExpectResult, resDataMetrics) 90 | } 91 | func TestTagSame(t *testing.T) { 92 | tests := []struct { 93 | x string 94 | y string 95 | result bool 96 | }{ 97 | {x: "a,b,c", y: "c,b,a", result: true}, 98 | {x: "a,b", y: "a,b,c", result: false}, 99 | {x: "a,b, c", y: "a,b,d", result: false}, 100 | } 101 | 102 | for _, test := range tests { 103 | assert.Equal(t, test.result, tagSame(test.x, test.y), "Wrong compare tag") 104 | } 105 | } 106 | 107 | func TestSnapshot(t *testing.T) { 108 | testNote := "test note string!" 109 | testOldDayFile := "fixtures/old_day_file" 110 | f, err := os.Create(testOldDayFile) 111 | assert.Nil(t, err) 112 | defer f.Close() 113 | testDayFile := "fixtures/day_file" 114 | 115 | err = Snapshot(confTestMaster, testNote, testDayFile, testOldDayFile) 116 | assert.Nil(t, err) 117 | resNote, err := ioutil.ReadFile(testDayFile) 118 | assert.Nil(t, err) 119 | assert.Equal(t, testNote, string(resNote)) 120 | err = os.Remove(testDayFile) 121 | assert.Nil(t, err) 122 | } 123 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/binding.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "github.com/ziutek/mymysql/mysql" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | var ( 10 | timeType = reflect.TypeOf(time.Time{}) 11 | timestampType = reflect.TypeOf(mysql.Timestamp{}) 12 | dateType = reflect.TypeOf(mysql.Date{}) 13 | durationType = reflect.TypeOf(time.Duration(0)) 14 | blobType = reflect.TypeOf(mysql.Blob{}) 15 | rawType = reflect.TypeOf(mysql.Raw{}) 16 | ) 17 | 18 | // val should be an addressable value 19 | func bindValue(val reflect.Value) (out paramValue) { 20 | if !val.IsValid() { 21 | out.typ = MYSQL_TYPE_NULL 22 | return 23 | } 24 | typ := val.Type() 25 | if typ.Kind() == reflect.Ptr { 26 | // We have addressable pointer 27 | out.addr = val.Addr() 28 | // Dereference pointer for next operation on its value 29 | typ = typ.Elem() 30 | val = val.Elem() 31 | } else { 32 | // We have addressable value. Create a pointer to it 33 | pv := val.Addr() 34 | // This pointer is unaddressable so copy it and return an address 35 | out.addr = reflect.New(pv.Type()) 36 | out.addr.Elem().Set(pv) 37 | } 38 | 39 | // Obtain value type 40 | switch typ.Kind() { 41 | case reflect.String: 42 | out.typ = MYSQL_TYPE_STRING 43 | out.length = -1 44 | return 45 | 46 | case reflect.Int: 47 | out.typ = _INT_TYPE 48 | out.length = _SIZE_OF_INT 49 | return 50 | 51 | case reflect.Int8: 52 | out.typ = MYSQL_TYPE_TINY 53 | out.length = 1 54 | return 55 | 56 | case reflect.Int16: 57 | out.typ = MYSQL_TYPE_SHORT 58 | out.length = 2 59 | return 60 | 61 | case reflect.Int32: 62 | out.typ = MYSQL_TYPE_LONG 63 | out.length = 4 64 | return 65 | 66 | case reflect.Int64: 67 | if typ == durationType { 68 | out.typ = MYSQL_TYPE_TIME 69 | out.length = -1 70 | return 71 | } 72 | out.typ = MYSQL_TYPE_LONGLONG 73 | out.length = 8 74 | return 75 | 76 | case reflect.Uint: 77 | out.typ = _INT_TYPE | MYSQL_UNSIGNED_MASK 78 | out.length = _SIZE_OF_INT 79 | return 80 | 81 | case reflect.Uint8: 82 | out.typ = MYSQL_TYPE_TINY | MYSQL_UNSIGNED_MASK 83 | out.length = 1 84 | return 85 | 86 | case reflect.Uint16: 87 | out.typ = MYSQL_TYPE_SHORT | MYSQL_UNSIGNED_MASK 88 | out.length = 2 89 | return 90 | 91 | case reflect.Uint32: 92 | out.typ = MYSQL_TYPE_LONG | MYSQL_UNSIGNED_MASK 93 | out.length = 4 94 | return 95 | 96 | case reflect.Uint64: 97 | out.typ = MYSQL_TYPE_LONGLONG | MYSQL_UNSIGNED_MASK 98 | out.length = 8 99 | return 100 | 101 | case reflect.Float32: 102 | out.typ = MYSQL_TYPE_FLOAT 103 | out.length = 4 104 | return 105 | 106 | case reflect.Float64: 107 | out.typ = MYSQL_TYPE_DOUBLE 108 | out.length = 8 109 | return 110 | 111 | case reflect.Slice: 112 | out.length = -1 113 | if typ == blobType { 114 | out.typ = MYSQL_TYPE_BLOB 115 | return 116 | } 117 | if typ.Elem().Kind() == reflect.Uint8 { 118 | out.typ = MYSQL_TYPE_VAR_STRING 119 | return 120 | } 121 | 122 | case reflect.Struct: 123 | out.length = -1 124 | if typ == timeType { 125 | out.typ = MYSQL_TYPE_DATETIME 126 | return 127 | } 128 | if typ == dateType { 129 | out.typ = MYSQL_TYPE_DATE 130 | return 131 | } 132 | if typ == timestampType { 133 | out.typ = MYSQL_TYPE_TIMESTAMP 134 | return 135 | } 136 | if typ == rawType { 137 | out.typ = val.FieldByName("Typ").Interface().(uint16) 138 | out.addr = val.FieldByName("Val").Addr() 139 | out.raw = true 140 | return 141 | } 142 | 143 | case reflect.Bool: 144 | out.typ = MYSQL_TYPE_TINY 145 | // bool implementation isn't documented so we treat it in special way 146 | out.length = -1 147 | return 148 | } 149 | panic(mysql.ErrBindUnkType) 150 | } 151 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/decode_meta.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import "strings" 4 | 5 | // MetaData allows access to meta information about TOML data that may not 6 | // be inferrable via reflection. In particular, whether a key has been defined 7 | // and the TOML type of a key. 8 | type MetaData struct { 9 | mapping map[string]interface{} 10 | types map[string]tomlType 11 | keys []Key 12 | decoded map[string]bool 13 | context Key // Used only during decoding. 14 | } 15 | 16 | // IsDefined returns true if the key given exists in the TOML data. The key 17 | // should be specified hierarchially. e.g., 18 | // 19 | // // access the TOML key 'a.b.c' 20 | // IsDefined("a", "b", "c") 21 | // 22 | // IsDefined will return false if an empty key given. Keys are case sensitive. 23 | func (md *MetaData) IsDefined(key ...string) bool { 24 | if len(key) == 0 { 25 | return false 26 | } 27 | 28 | var hash map[string]interface{} 29 | var ok bool 30 | var hashOrVal interface{} = md.mapping 31 | for _, k := range key { 32 | if hash, ok = hashOrVal.(map[string]interface{}); !ok { 33 | return false 34 | } 35 | if hashOrVal, ok = hash[k]; !ok { 36 | return false 37 | } 38 | } 39 | return true 40 | } 41 | 42 | // Type returns a string representation of the type of the key specified. 43 | // 44 | // Type will return the empty string if given an empty key or a key that 45 | // does not exist. Keys are case sensitive. 46 | func (md *MetaData) Type(key ...string) string { 47 | fullkey := strings.Join(key, ".") 48 | if typ, ok := md.types[fullkey]; ok { 49 | return typ.typeString() 50 | } 51 | return "" 52 | } 53 | 54 | // Key is the type of any TOML key, including key groups. Use (MetaData).Keys 55 | // to get values of this type. 56 | type Key []string 57 | 58 | func (k Key) String() string { 59 | return strings.Join(k, ".") 60 | } 61 | 62 | func (k Key) maybeQuotedAll() string { 63 | var ss []string 64 | for i := range k { 65 | ss = append(ss, k.maybeQuoted(i)) 66 | } 67 | return strings.Join(ss, ".") 68 | } 69 | 70 | func (k Key) maybeQuoted(i int) string { 71 | quote := false 72 | for _, c := range k[i] { 73 | if !isBareKeyChar(c) { 74 | quote = true 75 | break 76 | } 77 | } 78 | if quote { 79 | return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\"" 80 | } 81 | return k[i] 82 | } 83 | 84 | func (k Key) add(piece string) Key { 85 | newKey := make(Key, len(k)+1) 86 | copy(newKey, k) 87 | newKey[len(k)] = piece 88 | return newKey 89 | } 90 | 91 | // Keys returns a slice of every key in the TOML data, including key groups. 92 | // Each key is itself a slice, where the first element is the top of the 93 | // hierarchy and the last is the most specific. 94 | // 95 | // The list will have the same order as the keys appeared in the TOML data. 96 | // 97 | // All keys returned are non-empty. 98 | func (md *MetaData) Keys() []Key { 99 | return md.keys 100 | } 101 | 102 | // Undecoded returns all keys that have not been decoded in the order in which 103 | // they appear in the original TOML document. 104 | // 105 | // This includes keys that haven't been decoded because of a Primitive value. 106 | // Once the Primitive value is decoded, the keys will be considered decoded. 107 | // 108 | // Also note that decoding into an empty interface will result in no decoding, 109 | // and so no keys will be considered decoded. 110 | // 111 | // In this sense, the Undecoded keys correspond to keys in the TOML document 112 | // that do not have a concrete type in your representation. 113 | func (md *MetaData) Undecoded() []Key { 114 | undecoded := make([]Key, 0, len(md.keys)) 115 | for _, key := range md.keys { 116 | if !md.decoded[key.String()] { 117 | undecoded = append(undecoded, key) 118 | } 119 | } 120 | return undecoded 121 | } 122 | -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/logs/multifile.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 beego Author. All Rights Reserved. 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 | package logs 16 | 17 | import ( 18 | "encoding/json" 19 | "time" 20 | ) 21 | 22 | // A filesLogWriter manages several fileLogWriter 23 | // filesLogWriter will write logs to the file in json configuration and write the same level log to correspond file 24 | // means if the file name in configuration is project.log filesLogWriter will create project.error.log/project.debug.log 25 | // and write the error-level logs to project.error.log and write the debug-level logs to project.debug.log 26 | // the rotate attribute also acts like fileLogWriter 27 | type multiFileLogWriter struct { 28 | writers [LevelDebug + 1 + 1]*fileLogWriter // the last one for fullLogWriter 29 | fullLogWriter *fileLogWriter 30 | Separate []string `json:"separate"` 31 | } 32 | 33 | var levelNames = [...]string{"emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"} 34 | 35 | // Init file logger with json config. 36 | // jsonConfig like: 37 | // { 38 | // "filename":"logs/beego.log", 39 | // "maxLines":0, 40 | // "maxsize":0, 41 | // "daily":true, 42 | // "maxDays":15, 43 | // "rotate":true, 44 | // "perm":0600, 45 | // "separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"], 46 | // } 47 | 48 | func (f *multiFileLogWriter) Init(config string) error { 49 | writer := newFileWriter().(*fileLogWriter) 50 | err := writer.Init(config) 51 | if err != nil { 52 | return err 53 | } 54 | f.fullLogWriter = writer 55 | f.writers[LevelDebug+1] = writer 56 | 57 | //unmarshal "separate" field to f.Separate 58 | json.Unmarshal([]byte(config), f) 59 | 60 | jsonMap := map[string]interface{}{} 61 | json.Unmarshal([]byte(config), &jsonMap) 62 | 63 | for i := LevelEmergency; i < LevelDebug+1; i++ { 64 | for _, v := range f.Separate { 65 | if v == levelNames[i] { 66 | jsonMap["filename"] = f.fullLogWriter.fileNameOnly + "." + levelNames[i] + f.fullLogWriter.suffix 67 | jsonMap["level"] = i 68 | bs, _ := json.Marshal(jsonMap) 69 | writer = newFileWriter().(*fileLogWriter) 70 | writer.Init(string(bs)) 71 | f.writers[i] = writer 72 | } 73 | } 74 | } 75 | 76 | return nil 77 | } 78 | 79 | func (f *multiFileLogWriter) Destroy() { 80 | for i := 0; i < len(f.writers); i++ { 81 | if f.writers[i] != nil { 82 | f.writers[i].Destroy() 83 | } 84 | } 85 | } 86 | 87 | func (f *multiFileLogWriter) WriteMsg(when time.Time, msg string, level int) error { 88 | if f.fullLogWriter != nil { 89 | f.fullLogWriter.WriteMsg(when, msg, level) 90 | } 91 | for i := 0; i < len(f.writers)-1; i++ { 92 | if f.writers[i] != nil { 93 | if level == f.writers[i].Level { 94 | f.writers[i].WriteMsg(when, msg, level) 95 | } 96 | } 97 | } 98 | return nil 99 | } 100 | 101 | func (f *multiFileLogWriter) Flush() { 102 | for i := 0; i < len(f.writers); i++ { 103 | if f.writers[i] != nil { 104 | f.writers[i].Flush() 105 | } 106 | } 107 | } 108 | 109 | // newFilesWriter create a FileLogWriter returning as LoggerInterface. 110 | func newFilesWriter() Logger { 111 | return &multiFileLogWriter{} 112 | } 113 | 114 | func init() { 115 | Register(AdapterMultiFile, newFilesWriter) 116 | } 117 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/passwd.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "crypto/sha1" 5 | "crypto/sha256" 6 | "math" 7 | ) 8 | 9 | // Borrowed from GoMySQL 10 | // SHA1(SHA1(SHA1(password)), scramble) XOR SHA1(password) 11 | func encryptedPasswd(password string, scramble []byte) (out []byte) { 12 | if len(password) == 0 { 13 | return 14 | } 15 | // stage1_hash = SHA1(password) 16 | // SHA1 encode 17 | crypt := sha1.New() 18 | crypt.Write([]byte(password)) 19 | stg1Hash := crypt.Sum(nil) 20 | // token = SHA1(SHA1(stage1_hash), scramble) XOR stage1_hash 21 | // SHA1 encode again 22 | crypt.Reset() 23 | crypt.Write(stg1Hash) 24 | stg2Hash := crypt.Sum(nil) 25 | // SHA1 2nd hash and scramble 26 | crypt.Reset() 27 | crypt.Write(scramble) 28 | crypt.Write(stg2Hash) 29 | stg3Hash := crypt.Sum(nil) 30 | // XOR with first hash 31 | out = make([]byte, len(scramble)) 32 | for ii := range scramble { 33 | out[ii] = stg3Hash[ii] ^ stg1Hash[ii] 34 | } 35 | return 36 | } 37 | 38 | // Hash password using MySQL 8+ method (SHA256) 39 | func encryptedSHA256Passwd(password string, scramble []byte) []byte { 40 | if len(password) == 0 { 41 | return nil 42 | } 43 | 44 | // XOR(SHA256(password), SHA256(SHA256(SHA256(password)), scramble)) 45 | 46 | crypt := sha256.New() 47 | crypt.Write([]byte(password)) 48 | message1 := crypt.Sum(nil) 49 | 50 | crypt.Reset() 51 | crypt.Write(message1) 52 | message1Hash := crypt.Sum(nil) 53 | 54 | crypt.Reset() 55 | crypt.Write(message1Hash) 56 | crypt.Write(scramble) 57 | message2 := crypt.Sum(nil) 58 | 59 | for i := range message1 { 60 | message1[i] ^= message2[i] 61 | } 62 | 63 | return message1 64 | } 65 | 66 | // Old password handling based on translating to Go some functions from 67 | // libmysql 68 | 69 | // The main idea is that no password are sent between client & server on 70 | // connection and that no password are saved in mysql in a decodable form. 71 | // 72 | // On connection a random string is generated and sent to the client. 73 | // The client generates a new string with a random generator inited with 74 | // the hash values from the password and the sent string. 75 | // This 'check' string is sent to the server where it is compared with 76 | // a string generated from the stored hash_value of the password and the 77 | // random string. 78 | 79 | // libmysql/my_rnd.c 80 | type myRnd struct { 81 | seed1, seed2 uint32 82 | } 83 | 84 | const myRndMaxVal = 0x3FFFFFFF 85 | 86 | func newMyRnd(seed1, seed2 uint32) *myRnd { 87 | r := new(myRnd) 88 | r.seed1 = seed1 % myRndMaxVal 89 | r.seed2 = seed2 % myRndMaxVal 90 | return r 91 | } 92 | 93 | func (r *myRnd) Float64() float64 { 94 | r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal 95 | r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal 96 | return float64(r.seed1) / myRndMaxVal 97 | } 98 | 99 | // libmysql/password.c 100 | func pwHash(password []byte) (result [2]uint32) { 101 | var nr, add, nr2, tmp uint32 102 | nr, add, nr2 = 1345345333, 7, 0x12345671 103 | 104 | for _, c := range password { 105 | if c == ' ' || c == '\t' { 106 | continue // skip space in password 107 | } 108 | 109 | tmp = uint32(c) 110 | nr ^= (((nr & 63) + add) * tmp) + (nr << 8) 111 | nr2 += (nr2 << 8) ^ nr 112 | add += tmp 113 | } 114 | 115 | result[0] = nr & ((1 << 31) - 1) // Don't use sign bit (str2int) 116 | result[1] = nr2 & ((1 << 31) - 1) 117 | return 118 | } 119 | 120 | func encryptedOldPassword(password string, scramble []byte) []byte { 121 | if len(password) == 0 { 122 | return nil 123 | } 124 | scramble = scramble[:8] 125 | hashPw := pwHash([]byte(password)) 126 | hashSc := pwHash(scramble) 127 | r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1]) 128 | var out [8]byte 129 | for i := range out { 130 | out[i] = byte(math.Floor(r.Float64()*31) + 64) 131 | } 132 | extra := byte(math.Floor(r.Float64() * 31)) 133 | for i := range out { 134 | out[i] ^= extra 135 | } 136 | return out[:] 137 | } 138 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/stack.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "path" 7 | "runtime" 8 | "strings" 9 | ) 10 | 11 | // Frame represents a program counter inside a stack frame. 12 | type Frame uintptr 13 | 14 | // pc returns the program counter for this frame; 15 | // multiple frames may have the same PC value. 16 | func (f Frame) pc() uintptr { return uintptr(f) - 1 } 17 | 18 | // file returns the full path to the file that contains the 19 | // function for this Frame's pc. 20 | func (f Frame) file() string { 21 | fn := runtime.FuncForPC(f.pc()) 22 | if fn == nil { 23 | return "unknown" 24 | } 25 | file, _ := fn.FileLine(f.pc()) 26 | return file 27 | } 28 | 29 | // line returns the line number of source code of the 30 | // function for this Frame's pc. 31 | func (f Frame) line() int { 32 | fn := runtime.FuncForPC(f.pc()) 33 | if fn == nil { 34 | return 0 35 | } 36 | _, line := fn.FileLine(f.pc()) 37 | return line 38 | } 39 | 40 | // Format formats the frame according to the fmt.Formatter interface. 41 | // 42 | // %s source file 43 | // %d source line 44 | // %n function name 45 | // %v equivalent to %s:%d 46 | // 47 | // Format accepts flags that alter the printing of some verbs, as follows: 48 | // 49 | // %+s function name and path of source file relative to the compile time 50 | // GOPATH separated by \n\t (\n\t) 51 | // %+v equivalent to %+s:%d 52 | func (f Frame) Format(s fmt.State, verb rune) { 53 | switch verb { 54 | case 's': 55 | switch { 56 | case s.Flag('+'): 57 | pc := f.pc() 58 | fn := runtime.FuncForPC(pc) 59 | if fn == nil { 60 | io.WriteString(s, "unknown") 61 | } else { 62 | file, _ := fn.FileLine(pc) 63 | fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) 64 | } 65 | default: 66 | io.WriteString(s, path.Base(f.file())) 67 | } 68 | case 'd': 69 | fmt.Fprintf(s, "%d", f.line()) 70 | case 'n': 71 | name := runtime.FuncForPC(f.pc()).Name() 72 | io.WriteString(s, funcname(name)) 73 | case 'v': 74 | f.Format(s, 's') 75 | io.WriteString(s, ":") 76 | f.Format(s, 'd') 77 | } 78 | } 79 | 80 | // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). 81 | type StackTrace []Frame 82 | 83 | // Format formats the stack of Frames according to the fmt.Formatter interface. 84 | // 85 | // %s lists source files for each Frame in the stack 86 | // %v lists the source file and line number for each Frame in the stack 87 | // 88 | // Format accepts flags that alter the printing of some verbs, as follows: 89 | // 90 | // %+v Prints filename, function, and line number for each Frame in the stack. 91 | func (st StackTrace) Format(s fmt.State, verb rune) { 92 | switch verb { 93 | case 'v': 94 | switch { 95 | case s.Flag('+'): 96 | for _, f := range st { 97 | fmt.Fprintf(s, "\n%+v", f) 98 | } 99 | case s.Flag('#'): 100 | fmt.Fprintf(s, "%#v", []Frame(st)) 101 | default: 102 | fmt.Fprintf(s, "%v", []Frame(st)) 103 | } 104 | case 's': 105 | fmt.Fprintf(s, "%s", []Frame(st)) 106 | } 107 | } 108 | 109 | // stack represents a stack of program counters. 110 | type stack []uintptr 111 | 112 | func (s *stack) Format(st fmt.State, verb rune) { 113 | switch verb { 114 | case 'v': 115 | switch { 116 | case st.Flag('+'): 117 | for _, pc := range *s { 118 | f := Frame(pc) 119 | fmt.Fprintf(st, "\n%+v", f) 120 | } 121 | } 122 | } 123 | } 124 | 125 | func (s *stack) StackTrace() StackTrace { 126 | f := make([]Frame, len(*s)) 127 | for i := 0; i < len(f); i++ { 128 | f[i] = Frame((*s)[i]) 129 | } 130 | return f 131 | } 132 | 133 | func callers() *stack { 134 | const depth = 32 135 | var pcs [depth]uintptr 136 | n := runtime.Callers(3, pcs[:]) 137 | var st stack = pcs[0:n] 138 | return &st 139 | } 140 | 141 | // funcname removes the path prefix component of a function's name reported by func.Name(). 142 | func funcname(name string) string { 143 | i := strings.LastIndex(name, "/") 144 | name = name[i+1:] 145 | i = strings.Index(name, ".") 146 | return name[i+1:] 147 | } 148 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package main 15 | 16 | import ( 17 | "flag" 18 | "fmt" 19 | "io" 20 | "os" 21 | "time" 22 | 23 | "github.com/open-falcon/mymon/common" 24 | 25 | "github.com/astaxie/beego/logs" 26 | "github.com/ziutek/mymysql/mysql" 27 | _ "github.com/ziutek/mymysql/native" 28 | ) 29 | 30 | // Global tag var 31 | var ( 32 | IsSlave int 33 | IsReadOnly int 34 | Tag string 35 | ) 36 | 37 | //Log logger of project 38 | var Log *logs.BeeLogger 39 | 40 | func main() { 41 | // parse config file 42 | var confFile string 43 | flag.StringVar(&confFile, "c", "myMon.cfg", "myMon configure file") 44 | version := flag.Bool("v", false, "show version") 45 | flag.Parse() 46 | if *version { 47 | fmt.Println(fmt.Sprintf("%10s: %s", "Version", Version)) 48 | fmt.Println(fmt.Sprintf("%10s: %s", "Compile", Compile)) 49 | fmt.Println(fmt.Sprintf("%10s: %s", "Branch", Branch)) 50 | fmt.Println(fmt.Sprintf("%10s: %d", "GitDirty", GitDirty)) 51 | os.Exit(0) 52 | } 53 | conf, err := common.NewConfig(confFile) 54 | if err != nil { 55 | fmt.Printf("NewConfig Error: %s\n", err.Error()) 56 | return 57 | } 58 | if conf.Base.LogDir != "" { 59 | err = os.MkdirAll(conf.Base.LogDir, 0755) 60 | if err != nil { 61 | fmt.Printf("MkdirAll Error: %s\n", err.Error()) 62 | return 63 | } 64 | } 65 | if conf.Base.SnapshotDir != "" { 66 | err = os.MkdirAll(conf.Base.SnapshotDir, 0755) 67 | if err != nil { 68 | fmt.Printf("MkdirAll Error: %s\n", err.Error()) 69 | return 70 | } 71 | } 72 | 73 | // init log and other necessary 74 | Log = common.MyNewLogger(conf, common.CompatibleLog(conf)) 75 | 76 | db, err := common.NewMySQLConnection(conf) 77 | if err != nil { 78 | fmt.Printf("NewMySQLConnection Error: %s\n", err.Error()) 79 | return 80 | } 81 | defer func() { _ = db.Close() }() 82 | 83 | // start... 84 | Log.Info("MySQL Monitor for falcon") 85 | go timeout() 86 | err = fetchData(conf, db) 87 | if err != nil && err != io.EOF { 88 | Log.Error("Error: %s", err.Error()) 89 | } 90 | } 91 | 92 | func timeout() { 93 | time.AfterFunc(TimeOut*time.Second, func() { 94 | Log.Error("Execute timeout") 95 | os.Exit(1) 96 | }) 97 | } 98 | 99 | func fetchData(conf *common.Config, db mysql.Conn) (err error) { 100 | defer func() { 101 | MySQLAlive(conf, err == nil) 102 | }() 103 | 104 | // Get GLOBAL variables 105 | IsReadOnly, err = GetIsReadOnly(db) 106 | if err != nil { 107 | return 108 | } 109 | 110 | // SHOW XXX Metric 111 | var data []*MetaData 112 | 113 | // Get slave status and set IsSlave global var 114 | slaveState, err := ShowSlaveStatus(conf, db) 115 | if err != nil { 116 | return 117 | } 118 | 119 | globalStatus, err := ShowGlobalStatus(conf, db) 120 | if err != nil { 121 | return 122 | } 123 | data = append(data, globalStatus...) 124 | 125 | globalVars, err := ShowGlobalVariables(conf, db) 126 | if err != nil { 127 | return 128 | } 129 | data = append(data, globalVars...) 130 | 131 | innodbState, err := ShowInnodbStatus(conf, db) 132 | if err != nil { 133 | return 134 | } 135 | data = append(data, innodbState...) 136 | 137 | data = append(data, slaveState...) 138 | 139 | binaryLogStatus, err := ShowBinaryLogs(conf, db) 140 | if err != nil { 141 | return 142 | } 143 | data = append(data, binaryLogStatus...) 144 | 145 | // Send Data to falcon-agent 146 | msg, err := SendData(conf, data) 147 | if err != nil { 148 | Log.Error("Send response %s:%d - %s", conf.DataBase.Host, conf.DataBase.Port, string(msg)) 149 | } else { 150 | Log.Info("Send response %s:%d - %s", conf.DataBase.Host, conf.DataBase.Port, string(msg)) 151 | } 152 | 153 | err = ShowProcesslist(conf, db) 154 | if err != nil { 155 | return 156 | } 157 | return 158 | } 159 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This how we want to name the binary output 2 | BINARY=mymon 3 | GO_VERSION_MIN=1.10 4 | 5 | # Add mysql version for testing `MYSQL_VERSION=5.7 make docker` 6 | # use mysql:latest as default 7 | MYSQL_VERSION := $(or ${MYSQL_VERSION}, ${MYSQL_VERSION}, latest) 8 | 9 | .PHONY: all 10 | all: fmt build 11 | 12 | # Format code 13 | .PHONY: fmt 14 | fmt: 15 | @echo "\033[92mRun gofmt on all source files ...\033[0m" 16 | @echo "gofmt -l -s -w ..." 17 | @ret=0 && for d in $$(go list -f '{{.Dir}}' ./... | grep -v /vendor/); do \ 18 | gofmt -l -s -w $$d/*.go || ret=$$? ; \ 19 | done ; exit $$ret 20 | 21 | # Run all test cases 22 | .PHONY: test 23 | test: 24 | go test `go list ./... | grep -Ev '/fixtures|/vendor/'` 25 | 26 | .PHONY: cover 27 | cover: 28 | go test `go list ./... | grep -Ev '/fixtures|/vendor/'` \ 29 | -coverpkg=./... -coverprofile=coverage.data ./... | column -t 30 | go tool cover -html=coverage.data -o coverage.html 31 | go tool cover -func=coverage.data -o coverage.txt 32 | @tail -n 1 coverage.txt | awk '{sub(/%/, "", $$NF); \ 33 | if($$NF < 80) \ 34 | {print "\033[91m"$$0"%\033[0m"} \ 35 | else if ($$NF >= 90) \ 36 | {print "\033[92m"$$0"%\033[0m"} \ 37 | else \ 38 | {print "\033[93m"$$0"%\033[0m"}}' 39 | 40 | # Builds the project 41 | .PHONY: build 42 | build: 43 | @bash ./genver.sh $(GO_VERSION_MIN) 44 | go build -o ${BINARY} 45 | 46 | # Installs our project: copies binaries 47 | .PHONY: install 48 | install: 49 | go install 50 | 51 | # Cleans our projects: deletes binaries 52 | .PHONY: clean 53 | clean: 54 | $(info rm -f ${BINARY}) 55 | @if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi 56 | @rm -f coverage.* innodb_mymon.* ./fixtures/innodb_mymon.* ./fixtures/process_mymon.* ./fixtures/*.log 57 | @for GOOS in darwin linux windows; do \ 58 | for GOARCH in 386 amd64; do \ 59 | rm -f ./release/${BINARY}.$${GOOS}-$${GOARCH} ;\ 60 | done ;\ 61 | done 62 | @find . -name "innodb_*" -delete 63 | @find . -name "process_*" -delete 64 | @find . -name "*.log" -delete 65 | @find . -name "push_metric.txt" -delete 66 | @docker stop mymon-master 2>/dev/null || true 67 | @docker stop mymon-slave 2>/dev/null || true 68 | @kill -9 `lsof -ti tcp:1988` 2>/dev/null || true 69 | 70 | .PHONY: lint 71 | lint: 72 | gometalinter.v1 --config metalinter.json ./... 73 | 74 | .PHONY: release 75 | release: 76 | @echo "\033[92mCross platform building for release ...\033[0m" 77 | @bash ./genver.sh $(GO_VERSION_MIN) 78 | @for GOOS in darwin linux windows; do \ 79 | for GOARCH in 386 amd64; do \ 80 | GOOS=$${GOOS} GOARCH=$${GOARCH} go build -v -o ./release/${BINARY}.$${GOOS}-$${GOARCH} 2>/dev/null ; \ 81 | done ; \ 82 | done 83 | 84 | .PHONY: test_env 85 | test_env: 86 | @echo "\033[92mBuild mysql test enviorment\033[0m" 87 | @docker stop mymon-master 2>/dev/null || true 88 | @docker stop mymon-slave 2>/dev/null || true 89 | @kill -9 `lsof -ti tcp:1988` 2>/dev/null || true 90 | 91 | @docker run --name mymon-master --rm -d \ 92 | -e MYSQL_ROOT_PASSWORD=1tIsB1g3rt \ 93 | -e MYSQL_DATABASE=mysql \ 94 | -p 3306:3306 \ 95 | -v `pwd`/fixtures/setup_master.sql:/docker-entrypoint-initdb.d/setup_master.sql \ 96 | mysql:$(MYSQL_VERSION) \ 97 | --server_id=1 98 | @echo -n "waiting for master initializing " 99 | @while ! mysql -h 127.0.0.1 -uroot -P3306 -p1tIsB1g3rt -NBe "do 1;" 2>/dev/null; do \ 100 | printf '.' ; sleep 1 ; done ; echo '.' 101 | @echo "mysql master environment is ready!" 102 | 103 | @echo "begin to set slave environment: " 104 | @docker run --name mymon-slave --rm -d --link=mymon-master:mymon-master \ 105 | -e MYSQL_ROOT_PASSWORD=1tIsB1g3rt \ 106 | -e MYSQL_DATABASE=mysql \ 107 | -p 3308:3306 \ 108 | -v `pwd`/fixtures/setup_slave.sql:/docker-entrypoint-initdb.d/setup_slave.sql \ 109 | mysql:$(MYSQL_VERSION) \ 110 | --server_id=2 \ 111 | --read_only 112 | @echo -n "waiting for slave initializing " 113 | @while ! mysql -h 127.0.0.1 -uroot -P3308 -p1tIsB1g3rt -NBe "do 1;" 2>/dev/null; do \ 114 | printf '.' ; sleep 1 ; done ; echo '.' 115 | @echo "mysql slave environment is ready!" 116 | 117 | @echo "begin to set falcon push environment: " 118 | go run fixtures/push_mock.go & 119 | 120 | .PHONY: daily 121 | daily: fmt test_env test cover lint clean 122 | @echo "\033[93mdaily build successed! \033[m" 123 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/prepared.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "github.com/ziutek/mymysql/mysql" 5 | "log" 6 | ) 7 | 8 | type Stmt struct { 9 | my *Conn 10 | 11 | id uint32 12 | sql string // For reprepare during reconnect 13 | 14 | params []paramValue // Parameters binding 15 | rebind bool 16 | binded bool 17 | 18 | fields []*mysql.Field 19 | 20 | field_count int 21 | param_count int 22 | warning_count int 23 | status mysql.ConnStatus 24 | 25 | null_bitmap []byte 26 | } 27 | 28 | func (stmt *Stmt) Fields() []*mysql.Field { 29 | return stmt.fields 30 | } 31 | 32 | func (stmt *Stmt) NumParam() int { 33 | return stmt.param_count 34 | } 35 | 36 | func (stmt *Stmt) WarnCount() int { 37 | return stmt.warning_count 38 | } 39 | 40 | func (stmt *Stmt) sendCmdExec() { 41 | // Calculate packet length and NULL bitmap 42 | pkt_len := 1 + 4 + 1 + 4 + 1 + len(stmt.null_bitmap) 43 | for ii := range stmt.null_bitmap { 44 | stmt.null_bitmap[ii] = 0 45 | } 46 | for ii, param := range stmt.params { 47 | par_len := param.Len() 48 | pkt_len += par_len 49 | if par_len == 0 { 50 | null_byte := ii >> 3 51 | null_mask := byte(1) << uint(ii-(null_byte<<3)) 52 | stmt.null_bitmap[null_byte] |= null_mask 53 | } 54 | } 55 | if stmt.rebind { 56 | pkt_len += stmt.param_count * 2 57 | } 58 | // Reset sequence number 59 | stmt.my.seq = 0 60 | // Packet sending 61 | pw := stmt.my.newPktWriter(pkt_len) 62 | pw.writeByte(_COM_STMT_EXECUTE) 63 | pw.writeU32(stmt.id) 64 | pw.writeByte(0) // flags = CURSOR_TYPE_NO_CURSOR 65 | pw.writeU32(1) // iteration_count 66 | pw.write(stmt.null_bitmap) 67 | if stmt.rebind { 68 | pw.writeByte(1) 69 | // Types 70 | for _, param := range stmt.params { 71 | pw.writeU16(param.typ) 72 | } 73 | } else { 74 | pw.writeByte(0) 75 | } 76 | // Values 77 | for i := range stmt.params { 78 | pw.writeValue(&stmt.params[i]) 79 | } 80 | 81 | if stmt.my.Debug { 82 | log.Printf("[%2d <-] Exec command packet: len=%d, null_bitmap=%v, rebind=%t", 83 | stmt.my.seq-1, pkt_len, stmt.null_bitmap, stmt.rebind) 84 | } 85 | 86 | // Mark that we sended information about binded types 87 | stmt.rebind = false 88 | } 89 | 90 | func (my *Conn) getPrepareResult(stmt *Stmt) interface{} { 91 | loop: 92 | pr := my.newPktReader() // New reader for next packet 93 | pkt0 := pr.readByte() 94 | 95 | //log.Println("pkt0:", pkt0, "stmt:", stmt) 96 | 97 | if pkt0 == 255 { 98 | // Error packet 99 | my.getErrorPacket(pr) 100 | } 101 | 102 | if stmt == nil { 103 | if pkt0 == 0 { 104 | // OK packet 105 | return my.getPrepareOkPacket(pr) 106 | } 107 | } else { 108 | unreaded_params := (stmt.param_count < len(stmt.params)) 109 | switch { 110 | case pkt0 == 254: 111 | // EOF packet 112 | stmt.warning_count, stmt.status = my.getEofPacket(pr) 113 | stmt.my.status = stmt.status 114 | return stmt 115 | 116 | case pkt0 > 0 && pkt0 < 251 && (stmt.field_count < len(stmt.fields) || 117 | unreaded_params): 118 | // Field packet 119 | if unreaded_params { 120 | // Read and ignore parameter field. Sentence from MySQL source: 121 | /* skip parameters data: we don't support it yet */ 122 | pr.skipAll() 123 | // Increment param_count count 124 | stmt.param_count++ 125 | } else { 126 | field := my.getFieldPacket(pr) 127 | stmt.fields[stmt.field_count] = field 128 | // Increment field count 129 | stmt.field_count++ 130 | } 131 | // Read next packet 132 | goto loop 133 | } 134 | } 135 | panic(mysql.ErrUnkResultPkt) 136 | } 137 | 138 | func (my *Conn) getPrepareOkPacket(pr *pktReader) (stmt *Stmt) { 139 | if my.Debug { 140 | log.Printf("[%2d ->] Perpared OK packet:", my.seq-1) 141 | } 142 | 143 | stmt = new(Stmt) 144 | stmt.my = my 145 | // First byte was readed by getPrepRes 146 | stmt.id = pr.readU32() 147 | stmt.fields = make([]*mysql.Field, int(pr.readU16())) // FieldCount 148 | pl := int(pr.readU16()) // ParamCount 149 | if pl > 0 { 150 | stmt.params = make([]paramValue, pl) 151 | stmt.null_bitmap = make([]byte, (pl+7)>>3) 152 | } 153 | pr.skipN(1) 154 | stmt.warning_count = int(pr.readU16()) 155 | pr.checkEof() 156 | 157 | if my.Debug { 158 | log.Printf(tab8s+"ID=0x%x ParamCount=%d FieldsCount=%d WarnCount=%d", 159 | stmt.id, len(stmt.params), len(stmt.fields), stmt.warning_count, 160 | ) 161 | } 162 | return 163 | } 164 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/command.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | //import "log" 8 | 9 | // _COM_QUIT, _COM_STATISTICS, _COM_PROCESS_INFO, _COM_DEBUG, _COM_PING: 10 | func (my *Conn) sendCmd(cmd byte) { 11 | my.seq = 0 12 | pw := my.newPktWriter(1) 13 | pw.writeByte(cmd) 14 | if my.Debug { 15 | log.Printf("[%2d <-] Command packet: Cmd=0x%x", my.seq-1, cmd) 16 | } 17 | } 18 | 19 | // _COM_QUERY, _COM_INIT_DB, _COM_CREATE_DB, _COM_DROP_DB, _COM_STMT_PREPARE: 20 | func (my *Conn) sendCmdStr(cmd byte, s string) { 21 | my.seq = 0 22 | pw := my.newPktWriter(1 + len(s)) 23 | pw.writeByte(cmd) 24 | pw.write([]byte(s)) 25 | if my.Debug { 26 | log.Printf("[%2d <-] Command packet: Cmd=0x%x %s", my.seq-1, cmd, s) 27 | } 28 | } 29 | 30 | // _COM_PROCESS_KILL, _COM_STMT_CLOSE, _COM_STMT_RESET: 31 | func (my *Conn) sendCmdU32(cmd byte, u uint32) { 32 | my.seq = 0 33 | pw := my.newPktWriter(1 + 4) 34 | pw.writeByte(cmd) 35 | pw.writeU32(u) 36 | if my.Debug { 37 | log.Printf("[%2d <-] Command packet: Cmd=0x%x %d", my.seq-1, cmd, u) 38 | } 39 | } 40 | 41 | func (my *Conn) sendLongData(stmtid uint32, pnum uint16, data []byte) { 42 | my.seq = 0 43 | pw := my.newPktWriter(1 + 4 + 2 + len(data)) 44 | pw.writeByte(_COM_STMT_SEND_LONG_DATA) 45 | pw.writeU32(stmtid) // Statement ID 46 | pw.writeU16(pnum) // Parameter number 47 | pw.write(data) // payload 48 | if my.Debug { 49 | log.Printf("[%2d <-] SendLongData packet: pnum=%d", my.seq-1, pnum) 50 | } 51 | } 52 | 53 | /*func (my *Conn) sendCmd(cmd byte, argv ...interface{}) { 54 | // Reset sequence number 55 | my.seq = 0 56 | // Write command 57 | switch cmd { 58 | case _COM_QUERY, _COM_INIT_DB, _COM_CREATE_DB, _COM_DROP_DB, 59 | _COM_STMT_PREPARE: 60 | pw := my.newPktWriter(1 + lenBS(argv[0])) 61 | writeByte(pw, cmd) 62 | writeBS(pw, argv[0]) 63 | 64 | case _COM_STMT_SEND_LONG_DATA: 65 | pw := my.newPktWriter(1 + 4 + 2 + lenBS(argv[2])) 66 | writeByte(pw, cmd) 67 | writeU32(pw, argv[0].(uint32)) // Statement ID 68 | writeU16(pw, argv[1].(uint16)) // Parameter number 69 | writeBS(pw, argv[2]) // payload 70 | 71 | case _COM_QUIT, _COM_STATISTICS, _COM_PROCESS_INFO, _COM_DEBUG, _COM_PING: 72 | pw := my.newPktWriter(1) 73 | writeByte(pw, cmd) 74 | 75 | case _COM_FIELD_LIST: 76 | pay_len := 1 + lenBS(argv[0]) + 1 77 | if len(argv) > 1 { 78 | pay_len += lenBS(argv[1]) 79 | } 80 | 81 | pw := my.newPktWriter(pay_len) 82 | writeByte(pw, cmd) 83 | writeNT(pw, argv[0]) 84 | if len(argv) > 1 { 85 | writeBS(pw, argv[1]) 86 | } 87 | 88 | case _COM_TABLE_DUMP: 89 | pw := my.newPktWriter(1 + lenLC(argv[0]) + lenLC(argv[1])) 90 | writeByte(pw, cmd) 91 | writeLC(pw, argv[0]) 92 | writeLC(pw, argv[1]) 93 | 94 | case _COM_REFRESH, _COM_SHUTDOWN: 95 | pw := my.newPktWriter(1 + 1) 96 | writeByte(pw, cmd) 97 | writeByte(pw, argv[0].(byte)) 98 | 99 | case _COM_STMT_FETCH: 100 | pw := my.newPktWriter(1 + 4 + 4) 101 | writeByte(pw, cmd) 102 | writeU32(pw, argv[0].(uint32)) 103 | writeU32(pw, argv[1].(uint32)) 104 | 105 | case _COM_PROCESS_KILL, _COM_STMT_CLOSE, _COM_STMT_RESET: 106 | pw := my.newPktWriter(1 + 4) 107 | writeByte(pw, cmd) 108 | writeU32(pw, argv[0].(uint32)) 109 | 110 | case _COM_SET_OPTION: 111 | pw := my.newPktWriter(1 + 2) 112 | writeByte(pw, cmd) 113 | writeU16(pw, argv[0].(uint16)) 114 | 115 | case _COM_CHANGE_USER: 116 | pw := my.newPktWriter( 117 | 1 + lenBS(argv[0]) + 1 + lenLC(argv[1]) + lenBS(argv[2]) + 1, 118 | ) 119 | writeByte(pw, cmd) 120 | writeNT(pw, argv[0]) // User name 121 | writeLC(pw, argv[1]) // Scrambled password 122 | writeNT(pw, argv[2]) // Database name 123 | //writeU16(pw, argv[3]) // Character set number (since 5.1.23?) 124 | 125 | case _COM_BINLOG_DUMP: 126 | pay_len := 1 + 4 + 2 + 4 127 | if len(argv) > 3 { 128 | pay_len += lenBS(argv[3]) 129 | } 130 | 131 | pw := my.newPktWriter(pay_len) 132 | writeByte(pw, cmd) 133 | writeU32(pw, argv[0].(uint32)) // Start position 134 | writeU16(pw, argv[1].(uint16)) // Flags 135 | writeU32(pw, argv[2].(uint32)) // Slave server id 136 | if len(argv) > 3 { 137 | writeBS(pw, argv[3]) 138 | } 139 | 140 | // TODO: case COM_REGISTER_SLAVE: 141 | 142 | default: 143 | panic("Unknown code for MySQL command") 144 | } 145 | 146 | if my.Debug { 147 | log.Printf("[%2d <-] Command packet: Cmd=0x%x", my.seq-1, cmd) 148 | } 149 | }*/ 150 | -------------------------------------------------------------------------------- /vendor/github.com/sebdah/goldie/README.md: -------------------------------------------------------------------------------- 1 | # goldie - Golden test utility for Go 2 | 3 | [![GoDoc](https://godoc.org/github.com/sebdah/goldie?status.svg)](https://godoc.org/github.com/sebdah/goldie) 4 | [![CircleCI](https://circleci.com/gh/sebdah/goldie.svg?style=svg)](https://circleci.com/gh/sebdah/goldie) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/sebdah/goldie)](https://goreportcard.com/report/github.com/sebdah/goldie) 6 | 7 | `goldie` is a golden file test utility for Go projects. It's typically used for 8 | testing responses with larger data bodies. 9 | 10 | The concept is straight forward. Valid response data is stored in a "golden 11 | file". The actual response data will be byte compared with the golden file and 12 | the test will fail if there is a difference. 13 | 14 | Updating the golden file can be done by running `go test -update ./...`. 15 | 16 | See the [GoDoc](https://godoc.org/github.com/sebdah/goldie) for API reference 17 | and configuration options. 18 | 19 | ## Example usage 20 | 21 | The below example fetches data from a REST API. The last line in the test is the 22 | actual usage of `goldie`. It takes the HTTP response body and asserts that it's 23 | what is present in the golden test file. 24 | 25 | ``` 26 | func TestExample(t *testing.T) { 27 | recorder := httptest.NewRecorder() 28 | 29 | req, err := http.NewRequest("GET", "/example", nil) 30 | assert.Nil(t, err) 31 | 32 | handler := http.HandlerFunc(ExampleHandler) 33 | handler.ServeHTTP() 34 | 35 | goldie.Assert(t, "example", recorder.Body.Bytes()) 36 | } 37 | ``` 38 | 39 | ## Using template golden file 40 | 41 | If some values in the golden file can change depending on the test, you can use golang 42 | template in the golden file and pass the data to `goldie.AssertWithTemplate`. 43 | 44 | ### example.golden 45 | ``` 46 | This is a {{ .Type }} file. 47 | ``` 48 | 49 | ### Test 50 | ``` 51 | func TestTemplateExample(t *testing.T) { 52 | recorder := httptest.NewRecorder() 53 | 54 | req, err := http.NewRequest("POST", "/example/Golden", nil) 55 | assert.Nil(t, err) 56 | 57 | handler := http.HandlerFunc(ExampleHandler) 58 | handler.ServeHTTP() 59 | 60 | data := struct { 61 | Type string 62 | }{ 63 | Type: "Golden", 64 | } 65 | 66 | goldie.AssertWithTemplate(t, "example", data, recorder.Body.Bytes()) 67 | } 68 | ``` 69 | 70 | Then run your test with the `-update` flag the first time to store the result. 71 | 72 | `go test -update ./...` 73 | 74 | For any consecutive runs where you actually want to compare the data, simply 75 | drop the `-update` flag. 76 | 77 | `go test ./...` 78 | 79 | ## FAQ 80 | 81 | ### Do you need any help in the project? 82 | 83 | Yes, please! Pull requests are most welcome. On the wish list: 84 | 85 | - Unit tests. 86 | - Better output for failed tests. A diff of some sort would be great. 87 | 88 | ### Why the name `goldie`? 89 | 90 | The name comes from the fact that it's for Go and handles golden file testing. 91 | But yes, it may not be the best name in the world. 92 | 93 | ### How did you come up with the idea? 94 | 95 | This is based on the great [Advanced Go 96 | testing](https://www.youtube.com/watch?v=yszygk1cpEc) talk by 97 | [@mitchellh](https://twitter.com/mitchellh). 98 | 99 | ## License 100 | 101 | MIT 102 | 103 | Copyright 2016 Sebastian Dahlgren 104 | 105 | Permission is hereby granted, free of charge, to any person obtaining a copy of 106 | this software and associated documentation files (the "Software"), to deal in 107 | the Software without restriction, including without limitation the rights to 108 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 109 | the Software, and to permit persons to whom the Software is furnished to do so, 110 | subject to the following conditions: 111 | 112 | The above copyright notice and this permission notice shall be included in all 113 | copies or substantial portions of the Software. 114 | 115 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 116 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 117 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 118 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 119 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 120 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 121 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/paramvalue.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "github.com/ziutek/mymysql/mysql" 5 | "math" 6 | "reflect" 7 | "time" 8 | ) 9 | 10 | type paramValue struct { 11 | typ uint16 12 | addr reflect.Value 13 | raw bool 14 | length int // >=0 - length of value, <0 - unknown length 15 | } 16 | 17 | func (val *paramValue) Len() int { 18 | if !val.addr.IsValid() { 19 | // Invalid Value was binded 20 | return 0 21 | } 22 | // val.addr always points to the pointer - lets dereference it 23 | v := val.addr.Elem() 24 | if v.IsNil() { 25 | // Binded Ptr Value is nil 26 | return 0 27 | } 28 | v = v.Elem() 29 | 30 | if val.length >= 0 { 31 | return val.length 32 | } 33 | 34 | switch val.typ { 35 | case MYSQL_TYPE_STRING: 36 | return lenStr(v.String()) 37 | 38 | case MYSQL_TYPE_DATE: 39 | return lenDate(v.Interface().(mysql.Date)) 40 | 41 | case MYSQL_TYPE_TIMESTAMP: 42 | return lenTime(v.Interface().(mysql.Timestamp).Time) 43 | case MYSQL_TYPE_DATETIME: 44 | return lenTime(v.Interface().(time.Time)) 45 | 46 | case MYSQL_TYPE_TIME: 47 | return lenDuration(v.Interface().(time.Duration)) 48 | 49 | case MYSQL_TYPE_TINY: // val.length < 0 so this is bool 50 | return 1 51 | } 52 | // MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_BLOB and type of Raw value 53 | return lenBin(v.Bytes()) 54 | } 55 | 56 | func (pw *pktWriter) writeValue(val *paramValue) { 57 | if !val.addr.IsValid() { 58 | // Invalid Value was binded 59 | return 60 | } 61 | // val.addr always points to the pointer - lets dereference it 62 | v := val.addr.Elem() 63 | if v.IsNil() { 64 | // Binded Ptr Value is nil 65 | return 66 | } 67 | v = v.Elem() 68 | 69 | if val.raw || val.typ == MYSQL_TYPE_VAR_STRING || 70 | val.typ == MYSQL_TYPE_BLOB { 71 | pw.writeBin(v.Bytes()) 72 | return 73 | } 74 | // We don't need unsigned bit to check type 75 | unsign := (val.typ & MYSQL_UNSIGNED_MASK) != 0 76 | switch val.typ & ^MYSQL_UNSIGNED_MASK { 77 | case MYSQL_TYPE_NULL: 78 | // Don't write null values 79 | 80 | case MYSQL_TYPE_STRING: 81 | pw.writeBin([]byte(v.String())) 82 | 83 | case MYSQL_TYPE_LONG: 84 | i := v.Interface() 85 | if unsign { 86 | l, ok := i.(uint32) 87 | if !ok { 88 | l = uint32(i.(uint)) 89 | } 90 | pw.writeU32(l) 91 | } else { 92 | l, ok := i.(int32) 93 | if !ok { 94 | l = int32(i.(int)) 95 | } 96 | pw.writeU32(uint32(l)) 97 | } 98 | 99 | case MYSQL_TYPE_FLOAT: 100 | pw.writeU32(math.Float32bits(v.Interface().(float32))) 101 | 102 | case MYSQL_TYPE_SHORT: 103 | if unsign { 104 | pw.writeU16(v.Interface().(uint16)) 105 | } else { 106 | pw.writeU16(uint16(v.Interface().(int16))) 107 | 108 | } 109 | 110 | case MYSQL_TYPE_TINY: 111 | if val.length == -1 { 112 | // Translate bool value to MySQL tiny 113 | if v.Bool() { 114 | pw.writeByte(1) 115 | } else { 116 | pw.writeByte(0) 117 | } 118 | } else { 119 | if unsign { 120 | pw.writeByte(v.Interface().(uint8)) 121 | } else { 122 | pw.writeByte(uint8(v.Interface().(int8))) 123 | } 124 | } 125 | 126 | case MYSQL_TYPE_LONGLONG: 127 | i := v.Interface() 128 | if unsign { 129 | l, ok := i.(uint64) 130 | if !ok { 131 | l = uint64(i.(uint)) 132 | } 133 | pw.writeU64(l) 134 | } else { 135 | l, ok := i.(int64) 136 | if !ok { 137 | l = int64(i.(int)) 138 | } 139 | pw.writeU64(uint64(l)) 140 | } 141 | 142 | case MYSQL_TYPE_DOUBLE: 143 | pw.writeU64(math.Float64bits(v.Interface().(float64))) 144 | 145 | case MYSQL_TYPE_DATE: 146 | pw.writeDate(v.Interface().(mysql.Date)) 147 | 148 | case MYSQL_TYPE_TIMESTAMP: 149 | pw.writeTime(v.Interface().(mysql.Timestamp).Time) 150 | 151 | case MYSQL_TYPE_DATETIME: 152 | pw.writeTime(v.Interface().(time.Time)) 153 | 154 | case MYSQL_TYPE_TIME: 155 | pw.writeDuration(v.Interface().(time.Duration)) 156 | 157 | default: 158 | panic(mysql.ErrBindUnkType) 159 | } 160 | return 161 | } 162 | 163 | // encodes a uint64 value and appends it to the given bytes slice 164 | func appendLengthEncodedInteger(b []byte, n uint64) []byte { 165 | switch { 166 | case n <= 250: 167 | return append(b, byte(n)) 168 | 169 | case n <= 0xffff: 170 | return append(b, 0xfc, byte(n), byte(n>>8)) 171 | 172 | case n <= 0xffffff: 173 | return append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16)) 174 | } 175 | return append(b, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24), 176 | byte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56)) 177 | } -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/logs/smtp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 beego Author. All Rights Reserved. 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 | package logs 16 | 17 | import ( 18 | "crypto/tls" 19 | "encoding/json" 20 | "fmt" 21 | "net" 22 | "net/smtp" 23 | "strings" 24 | "time" 25 | ) 26 | 27 | // SMTPWriter implements LoggerInterface and is used to send emails via given SMTP-server. 28 | type SMTPWriter struct { 29 | Username string `json:"username"` 30 | Password string `json:"password"` 31 | Host string `json:"host"` 32 | Subject string `json:"subject"` 33 | FromAddress string `json:"fromAddress"` 34 | RecipientAddresses []string `json:"sendTos"` 35 | Level int `json:"level"` 36 | } 37 | 38 | // NewSMTPWriter create smtp writer. 39 | func newSMTPWriter() Logger { 40 | return &SMTPWriter{Level: LevelTrace} 41 | } 42 | 43 | // Init smtp writer with json config. 44 | // config like: 45 | // { 46 | // "username":"example@gmail.com", 47 | // "password:"password", 48 | // "host":"smtp.gmail.com:465", 49 | // "subject":"email title", 50 | // "fromAddress":"from@example.com", 51 | // "sendTos":["email1","email2"], 52 | // "level":LevelError 53 | // } 54 | func (s *SMTPWriter) Init(jsonconfig string) error { 55 | return json.Unmarshal([]byte(jsonconfig), s) 56 | } 57 | 58 | func (s *SMTPWriter) getSMTPAuth(host string) smtp.Auth { 59 | if len(strings.Trim(s.Username, " ")) == 0 && len(strings.Trim(s.Password, " ")) == 0 { 60 | return nil 61 | } 62 | return smtp.PlainAuth( 63 | "", 64 | s.Username, 65 | s.Password, 66 | host, 67 | ) 68 | } 69 | 70 | func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAddress string, recipients []string, msgContent []byte) error { 71 | client, err := smtp.Dial(hostAddressWithPort) 72 | if err != nil { 73 | return err 74 | } 75 | 76 | host, _, _ := net.SplitHostPort(hostAddressWithPort) 77 | tlsConn := &tls.Config{ 78 | InsecureSkipVerify: true, 79 | ServerName: host, 80 | } 81 | if err = client.StartTLS(tlsConn); err != nil { 82 | return err 83 | } 84 | 85 | if auth != nil { 86 | if err = client.Auth(auth); err != nil { 87 | return err 88 | } 89 | } 90 | 91 | if err = client.Mail(fromAddress); err != nil { 92 | return err 93 | } 94 | 95 | for _, rec := range recipients { 96 | if err = client.Rcpt(rec); err != nil { 97 | return err 98 | } 99 | } 100 | 101 | w, err := client.Data() 102 | if err != nil { 103 | return err 104 | } 105 | _, err = w.Write(msgContent) 106 | if err != nil { 107 | return err 108 | } 109 | 110 | err = w.Close() 111 | if err != nil { 112 | return err 113 | } 114 | 115 | return client.Quit() 116 | } 117 | 118 | // WriteMsg write message in smtp writer. 119 | // it will send an email with subject and only this message. 120 | func (s *SMTPWriter) WriteMsg(when time.Time, msg string, level int) error { 121 | if level > s.Level { 122 | return nil 123 | } 124 | 125 | hp := strings.Split(s.Host, ":") 126 | 127 | // Set up authentication information. 128 | auth := s.getSMTPAuth(hp[0]) 129 | 130 | // Connect to the server, authenticate, set the sender and recipient, 131 | // and send the email all in one step. 132 | contentType := "Content-Type: text/plain" + "; charset=UTF-8" 133 | mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.FromAddress + "<" + s.FromAddress + 134 | ">\r\nSubject: " + s.Subject + "\r\n" + contentType + "\r\n\r\n" + fmt.Sprintf(".%s", when.Format("2006-01-02 15:04:05")) + msg) 135 | 136 | return s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg) 137 | } 138 | 139 | // Flush implementing method. empty. 140 | func (s *SMTPWriter) Flush() { 141 | } 142 | 143 | // Destroy implementing method. empty. 144 | func (s *SMTPWriter) Destroy() { 145 | } 146 | 147 | func init() { 148 | Register(AdapterMail, newSMTPWriter) 149 | } 150 | -------------------------------------------------------------------------------- /show_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Open-Falcon 3 | * 4 | * Copyright (c) 2014-2018 Xiaomi, Inc. All Rights Reserved. 5 | * 6 | * This product is licensed to you under the Apache License, Version 2.0 (the "License"). 7 | * You may not use this product except in compliance with the License. 8 | * 9 | * This product may include a number of subcomponents with separate copyright notices 10 | * and license terms. Your use of these subcomponents is subject to the terms and 11 | * conditions of the subcomponent's license, as noted in the LICENSE file. 12 | */ 13 | 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "io/ioutil" 19 | "strings" 20 | "testing" 21 | 22 | "github.com/open-falcon/mymon/common" 23 | 24 | "github.com/sebdah/goldie" 25 | "github.com/stretchr/testify/assert" 26 | "github.com/ziutek/mymysql/mysql" 27 | ) 28 | 29 | // testConfigFile is used to make test 30 | const testConfigFile = "fixtures/test.master.cfg" 31 | const testSlaveConfigFile = "fixtures/test.slave.cfg" 32 | 33 | var confTestMaster, confTestSlave *common.Config 34 | var dbTestMaster, dbTestSlave mysql.Conn 35 | 36 | func init() { 37 | var err error 38 | confTestMaster, err = common.NewConfig(testConfigFile) 39 | if err != nil { 40 | panic(err) 41 | } 42 | dbTestMaster, err = common.NewMySQLConnection(confTestMaster) 43 | if err != nil { 44 | panic(err) 45 | } 46 | 47 | confTestSlave, err = common.NewConfig(testSlaveConfigFile) 48 | if err != nil { 49 | panic(err) 50 | } 51 | dbTestSlave, err = common.NewMySQLConnection(confTestSlave) 52 | if err != nil { 53 | panic(err) 54 | } 55 | } 56 | 57 | /**************** TEST SHOW GLOBAL *******************/ 58 | func TestShowGlobalStatus(t *testing.T) { 59 | data, err := ShowGlobalStatus(confTestMaster, dbTestMaster) 60 | assert.Nil(t, err) 61 | assert.NotEmpty(t, data) 62 | } 63 | 64 | func TestShowGlobalVariables(t *testing.T) { 65 | data, err := ShowGlobalStatus(confTestMaster, dbTestMaster) 66 | assert.Nil(t, err) 67 | assert.NotEmpty(t, data) 68 | } 69 | 70 | /**************** TEST INNODB*******************/ 71 | func TestParseInnodbStatus(t *testing.T) { 72 | inputbuf, err := ioutil.ReadFile("fixtures/test_innodb_source.golden") 73 | assert.Nil(t, err) 74 | rows := strings.Split(string(inputbuf), "\n") 75 | 76 | //Test parseInnodbStatus 77 | res, err := parseInnodbStatus(confTestMaster, rows) 78 | assert.Nil(t, err) 79 | var actualRes string 80 | for i, m := range res { 81 | fmtLine := fmt.Sprintf("%d: MetaData Metric:%s Endpoint:%s Value:%v CounterType:%s Tags:%s Timestamp:%d Step:%d\n", 82 | i, m.Metric, "localhost", m.Value, m.CounterType, "test_tag", 0, m.Step) 83 | actualRes += fmtLine 84 | } 85 | goldie.Assert(t, "test_innodb_result", []byte(actualRes)) 86 | } 87 | 88 | /**************** TEST BINARY *******************/ 89 | func TestShowBinaryLogStatus(t *testing.T) { 90 | data, err := ShowBinaryLogs(confTestMaster, dbTestMaster) 91 | assert.Nil(t, err) 92 | for _, eachData := range data { 93 | assert.NotNilf(t, eachData, "binlog value cannot be %v", eachData.Value) 94 | } 95 | } 96 | 97 | func TestShowSlaveStatus(t *testing.T) { 98 | var res []*MetaData 99 | var err error 100 | tempIsSlave := IsSlave 101 | defer func() { IsSlave = tempIsSlave }() 102 | 103 | //test master 104 | res, err = ShowSlaveStatus(confTestMaster, dbTestMaster) 105 | assert.Equal(t, 0, IsSlave) 106 | assert.NoError(t, err) 107 | assert.Equal(t, 4, len(res), "Wrong length of Metric with master!") 108 | 109 | //test slave 110 | res, err = ShowSlaveStatus(confTestSlave, dbTestSlave) 111 | assert.Equal(t, 1, IsSlave) 112 | assert.NoError(t, err) 113 | assert.Equal(t, len(SlaveStatus)+4, len(res), "Wrong length of Metric with slave!") 114 | } 115 | 116 | func TestShowOtherMetric(t *testing.T) { 117 | tempIsReadOnly := IsReadOnly 118 | defer func() { IsReadOnly = tempIsReadOnly }() 119 | testMetaDataStr := []string{ 120 | "master_is_read_only", "Master_is_readonly", "slave_is_read_only", 121 | "innodb_stats_on_metadata", "io_thread_dela", "Heartbeats_Behind_Master", "others"} 122 | expectIntValues := []int{0, 0, 1} 123 | 124 | // test master readonly 125 | IsReadOnly = 0 126 | for i, meta := range testMetaDataStr[:2] { 127 | getData, _ := ShowOtherMetric(confTestMaster, dbTestMaster, meta) 128 | assert.Equal(t, expectIntValues[i], getData.Value, "Wrong value!") 129 | } 130 | // test slave readonly 131 | IsReadOnly = 1 132 | getData, _ := ShowOtherMetric(confTestSlave, dbTestSlave, testMetaDataStr[2]) 133 | assert.Equal(t, expectIntValues[2], getData.Value, "Wrong value!") 134 | 135 | for i, meta := range testMetaDataStr[3:6] { 136 | getData, _ = ShowOtherMetric(confTestMaster, dbTestMaster, meta) 137 | assert.NotNil(t, expectIntValues[i], getData.Value, "Wrong value!") 138 | } 139 | getData, _ = ShowOtherMetric(confTestMaster, dbTestMaster, testMetaDataStr[6]) 140 | assert.Nil(t, getData.Value, "Wrong default value of metric!") 141 | } 142 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/packet.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "bufio" 5 | "github.com/ziutek/mymysql/mysql" 6 | "io" 7 | "io/ioutil" 8 | ) 9 | 10 | type pktReader struct { 11 | rd *bufio.Reader 12 | seq *byte 13 | remain int 14 | last bool 15 | buf [12]byte 16 | ibuf [3]byte 17 | } 18 | 19 | func (my *Conn) newPktReader() *pktReader { 20 | return &pktReader{rd: my.rd, seq: &my.seq} 21 | } 22 | 23 | func (pr *pktReader) readHeader() { 24 | // Read next packet header 25 | buf := pr.ibuf[:] 26 | for { 27 | n, err := pr.rd.Read(buf) 28 | if err != nil { 29 | panic(err) 30 | } 31 | buf = buf[n:] 32 | if len(buf) == 0 { 33 | break 34 | } 35 | } 36 | pr.remain = int(DecodeU24(pr.ibuf[:])) 37 | seq, err := pr.rd.ReadByte() 38 | if err != nil { 39 | panic(err) 40 | } 41 | // Chceck sequence number 42 | if *pr.seq != seq { 43 | panic(mysql.ErrSeq) 44 | } 45 | *pr.seq++ 46 | // Last packet? 47 | pr.last = (pr.remain != 0xffffff) 48 | } 49 | 50 | func (pr *pktReader) readFull(buf []byte) { 51 | for len(buf) > 0 { 52 | if pr.remain == 0 { 53 | if pr.last { 54 | // No more packets 55 | panic(io.EOF) 56 | } 57 | pr.readHeader() 58 | } 59 | n := len(buf) 60 | if n > pr.remain { 61 | n = pr.remain 62 | } 63 | n, err := pr.rd.Read(buf[:n]) 64 | pr.remain -= n 65 | if err != nil { 66 | panic(err) 67 | } 68 | buf = buf[n:] 69 | } 70 | return 71 | } 72 | 73 | func (pr *pktReader) readByte() byte { 74 | if pr.remain == 0 { 75 | if pr.last { 76 | // No more packets 77 | panic(io.EOF) 78 | } 79 | pr.readHeader() 80 | } 81 | b, err := pr.rd.ReadByte() 82 | if err != nil { 83 | panic(err) 84 | } 85 | pr.remain-- 86 | return b 87 | } 88 | 89 | func (pr *pktReader) readAll() (buf []byte) { 90 | m := 0 91 | for { 92 | if pr.remain == 0 { 93 | if pr.last { 94 | break 95 | } 96 | pr.readHeader() 97 | } 98 | new_buf := make([]byte, m+pr.remain) 99 | copy(new_buf, buf) 100 | buf = new_buf 101 | n, err := pr.rd.Read(buf[m:]) 102 | pr.remain -= n 103 | m += n 104 | if err != nil { 105 | panic(err) 106 | } 107 | } 108 | return 109 | } 110 | 111 | func (pr *pktReader) skipAll() { 112 | for { 113 | if pr.remain == 0 { 114 | if pr.last { 115 | break 116 | } 117 | pr.readHeader() 118 | } 119 | n, err := io.CopyN(ioutil.Discard, pr.rd, int64(pr.remain)) 120 | pr.remain -= int(n) 121 | if err != nil { 122 | panic(err) 123 | } 124 | } 125 | return 126 | } 127 | 128 | func (pr *pktReader) skipN(n int) { 129 | for n > 0 { 130 | if pr.remain == 0 { 131 | if pr.last { 132 | panic(io.EOF) 133 | } 134 | pr.readHeader() 135 | } 136 | m := int64(n) 137 | if n > pr.remain { 138 | m = int64(pr.remain) 139 | } 140 | m, err := io.CopyN(ioutil.Discard, pr.rd, m) 141 | pr.remain -= int(m) 142 | n -= int(m) 143 | if err != nil { 144 | panic(err) 145 | } 146 | } 147 | return 148 | } 149 | 150 | func (pr *pktReader) unreadByte() { 151 | if err := pr.rd.UnreadByte(); err != nil { 152 | panic(err) 153 | } 154 | pr.remain++ 155 | } 156 | 157 | func (pr *pktReader) eof() bool { 158 | return pr.remain == 0 && pr.last 159 | } 160 | 161 | func (pr *pktReader) checkEof() { 162 | if !pr.eof() { 163 | panic(mysql.ErrPktLong) 164 | } 165 | } 166 | 167 | type pktWriter struct { 168 | wr *bufio.Writer 169 | seq *byte 170 | remain int 171 | to_write int 172 | last bool 173 | buf [23]byte 174 | ibuf [3]byte 175 | } 176 | 177 | func (my *Conn) newPktWriter(to_write int) *pktWriter { 178 | return &pktWriter{wr: my.wr, seq: &my.seq, to_write: to_write} 179 | } 180 | 181 | func (pw *pktWriter) writeHeader(l int) { 182 | buf := pw.ibuf[:] 183 | EncodeU24(buf, uint32(l)) 184 | if _, err := pw.wr.Write(buf); err != nil { 185 | panic(err) 186 | } 187 | if err := pw.wr.WriteByte(*pw.seq); err != nil { 188 | panic(err) 189 | } 190 | // Update sequence number 191 | *pw.seq++ 192 | } 193 | 194 | func (pw *pktWriter) write(buf []byte) { 195 | if len(buf) == 0 { 196 | return 197 | } 198 | var nn int 199 | for len(buf) != 0 { 200 | if pw.remain == 0 { 201 | if pw.to_write == 0 { 202 | panic("too many data for write as packet") 203 | } 204 | if pw.to_write >= 0xffffff { 205 | pw.remain = 0xffffff 206 | } else { 207 | pw.remain = pw.to_write 208 | pw.last = true 209 | } 210 | pw.to_write -= pw.remain 211 | pw.writeHeader(pw.remain) 212 | } 213 | nn = len(buf) 214 | if nn > pw.remain { 215 | nn = pw.remain 216 | } 217 | var err error 218 | nn, err = pw.wr.Write(buf[0:nn]) 219 | pw.remain -= nn 220 | if err != nil { 221 | panic(err) 222 | } 223 | buf = buf[nn:] 224 | } 225 | if pw.remain+pw.to_write == 0 { 226 | if !pw.last { 227 | // Write header for empty packet 228 | pw.writeHeader(0) 229 | } 230 | // Flush bufio buffers 231 | if err := pw.wr.Flush(); err != nil { 232 | panic(err) 233 | } 234 | } 235 | return 236 | } 237 | 238 | func (pw *pktWriter) writeByte(b byte) { 239 | pw.buf[0] = b 240 | pw.write(pw.buf[:1]) 241 | } 242 | 243 | // n should be <= 23 244 | func (pw *pktWriter) writeZeros(n int) { 245 | buf := pw.buf[:n] 246 | for i := range buf { 247 | buf[i] = 0 248 | } 249 | pw.write(buf) 250 | } 251 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/README.md: -------------------------------------------------------------------------------- 1 | ## TOML parser and encoder for Go with reflection 2 | 3 | TOML stands for Tom's Obvious, Minimal Language. This Go package provides a 4 | reflection interface similar to Go's standard library `json` and `xml` 5 | packages. This package also supports the `encoding.TextUnmarshaler` and 6 | `encoding.TextMarshaler` interfaces so that you can define custom data 7 | representations. (There is an example of this below.) 8 | 9 | Spec: https://github.com/toml-lang/toml 10 | 11 | Compatible with TOML version 12 | [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) 13 | 14 | Documentation: https://godoc.org/github.com/BurntSushi/toml 15 | 16 | Installation: 17 | 18 | ```bash 19 | go get github.com/BurntSushi/toml 20 | ``` 21 | 22 | Try the toml validator: 23 | 24 | ```bash 25 | go get github.com/BurntSushi/toml/cmd/tomlv 26 | tomlv some-toml-file.toml 27 | ``` 28 | 29 | [![Build Status](https://travis-ci.org/BurntSushi/toml.svg?branch=master)](https://travis-ci.org/BurntSushi/toml) [![GoDoc](https://godoc.org/github.com/BurntSushi/toml?status.svg)](https://godoc.org/github.com/BurntSushi/toml) 30 | 31 | ### Testing 32 | 33 | This package passes all tests in 34 | [toml-test](https://github.com/BurntSushi/toml-test) for both the decoder 35 | and the encoder. 36 | 37 | ### Examples 38 | 39 | This package works similarly to how the Go standard library handles `XML` 40 | and `JSON`. Namely, data is loaded into Go values via reflection. 41 | 42 | For the simplest example, consider some TOML file as just a list of keys 43 | and values: 44 | 45 | ```toml 46 | Age = 25 47 | Cats = [ "Cauchy", "Plato" ] 48 | Pi = 3.14 49 | Perfection = [ 6, 28, 496, 8128 ] 50 | DOB = 1987-07-05T05:45:00Z 51 | ``` 52 | 53 | Which could be defined in Go as: 54 | 55 | ```go 56 | type Config struct { 57 | Age int 58 | Cats []string 59 | Pi float64 60 | Perfection []int 61 | DOB time.Time // requires `import time` 62 | } 63 | ``` 64 | 65 | And then decoded with: 66 | 67 | ```go 68 | var conf Config 69 | if _, err := toml.Decode(tomlData, &conf); err != nil { 70 | // handle error 71 | } 72 | ``` 73 | 74 | You can also use struct tags if your struct field name doesn't map to a TOML 75 | key value directly: 76 | 77 | ```toml 78 | some_key_NAME = "wat" 79 | ``` 80 | 81 | ```go 82 | type TOML struct { 83 | ObscureKey string `toml:"some_key_NAME"` 84 | } 85 | ``` 86 | 87 | ### Using the `encoding.TextUnmarshaler` interface 88 | 89 | Here's an example that automatically parses duration strings into 90 | `time.Duration` values: 91 | 92 | ```toml 93 | [[song]] 94 | name = "Thunder Road" 95 | duration = "4m49s" 96 | 97 | [[song]] 98 | name = "Stairway to Heaven" 99 | duration = "8m03s" 100 | ``` 101 | 102 | Which can be decoded with: 103 | 104 | ```go 105 | type song struct { 106 | Name string 107 | Duration duration 108 | } 109 | type songs struct { 110 | Song []song 111 | } 112 | var favorites songs 113 | if _, err := toml.Decode(blob, &favorites); err != nil { 114 | log.Fatal(err) 115 | } 116 | 117 | for _, s := range favorites.Song { 118 | fmt.Printf("%s (%s)\n", s.Name, s.Duration) 119 | } 120 | ``` 121 | 122 | And you'll also need a `duration` type that satisfies the 123 | `encoding.TextUnmarshaler` interface: 124 | 125 | ```go 126 | type duration struct { 127 | time.Duration 128 | } 129 | 130 | func (d *duration) UnmarshalText(text []byte) error { 131 | var err error 132 | d.Duration, err = time.ParseDuration(string(text)) 133 | return err 134 | } 135 | ``` 136 | 137 | ### More complex usage 138 | 139 | Here's an example of how to load the example from the official spec page: 140 | 141 | ```toml 142 | # This is a TOML document. Boom. 143 | 144 | title = "TOML Example" 145 | 146 | [owner] 147 | name = "Tom Preston-Werner" 148 | organization = "GitHub" 149 | bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." 150 | dob = 1979-05-27T07:32:00Z # First class dates? Why not? 151 | 152 | [database] 153 | server = "192.168.1.1" 154 | ports = [ 8001, 8001, 8002 ] 155 | connection_max = 5000 156 | enabled = true 157 | 158 | [servers] 159 | 160 | # You can indent as you please. Tabs or spaces. TOML don't care. 161 | [servers.alpha] 162 | ip = "10.0.0.1" 163 | dc = "eqdc10" 164 | 165 | [servers.beta] 166 | ip = "10.0.0.2" 167 | dc = "eqdc10" 168 | 169 | [clients] 170 | data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it 171 | 172 | # Line breaks are OK when inside arrays 173 | hosts = [ 174 | "alpha", 175 | "omega" 176 | ] 177 | ``` 178 | 179 | And the corresponding Go types are: 180 | 181 | ```go 182 | type tomlConfig struct { 183 | Title string 184 | Owner ownerInfo 185 | DB database `toml:"database"` 186 | Servers map[string]server 187 | Clients clients 188 | } 189 | 190 | type ownerInfo struct { 191 | Name string 192 | Org string `toml:"organization"` 193 | Bio string 194 | DOB time.Time 195 | } 196 | 197 | type database struct { 198 | Server string 199 | Ports []int 200 | ConnMax int `toml:"connection_max"` 201 | Enabled bool 202 | } 203 | 204 | type server struct { 205 | IP string 206 | DC string 207 | } 208 | 209 | type clients struct { 210 | Data [][]interface{} 211 | Hosts []string 212 | } 213 | ``` 214 | 215 | Note that a case insensitive match will be tried if an exact match can't be 216 | found. 217 | 218 | A working example of the above can be found in `_examples/example.{go,toml}`. 219 | -------------------------------------------------------------------------------- /vendor/github.com/sebdah/goldie/goldie.go: -------------------------------------------------------------------------------- 1 | // Package goldie provides test assertions based on golden files. It's typically 2 | // used for testing responses with larger data bodies. 3 | // 4 | // The concept is straight forward. Valid response data is stored in a "golden 5 | // file". The actual response data will be byte compared with the golden file 6 | // and the test will fail if there is a difference. 7 | // 8 | // Updating the golden file can be done by running `go test -update ./...`. 9 | package goldie 10 | 11 | import ( 12 | "bytes" 13 | "flag" 14 | "fmt" 15 | "io/ioutil" 16 | "os" 17 | "path/filepath" 18 | "testing" 19 | "text/template" 20 | ) 21 | 22 | var ( 23 | // FixtureDir is the folder name for where the fixtures are stored. It's 24 | // relative to the "go test" path. 25 | FixtureDir = "fixtures" 26 | 27 | // FileNameSuffix is the suffix appended to the fixtures. Set to empty 28 | // string to disable file name suffixes. 29 | FileNameSuffix = ".golden" 30 | 31 | // FlagName is the name of the command line flag for go test. 32 | FlagName = "update" 33 | 34 | // FilePerms is used to set the permissions on the golden fixture files. 35 | FilePerms os.FileMode = 0644 36 | 37 | // DirPerms is used to set the permissions on the golden fixture folder. 38 | DirPerms os.FileMode = 0755 39 | 40 | // update determines if the actual received data should be written to the 41 | // golden files or not. This should be true when you need to update the 42 | // data, but false when actually running the tests. 43 | update = flag.Bool(FlagName, false, "Update golden test file fixture") 44 | ) 45 | 46 | // Assert compares the actual data received with the expected data in the 47 | // golden files. If the update flag is set, it will also update the golden 48 | // file. 49 | // 50 | // `name` refers to the name of the test and it should typically be unique 51 | // within the package. Also it should be a valid file name (so keeping to 52 | // `a-z0-9\-\_` is a good idea). 53 | func Assert(t *testing.T, name string, actualData []byte) { 54 | AssertWithTemplate(t, name, nil, actualData) 55 | } 56 | 57 | // Assert compares the actual data received with the expected data in the 58 | // golden files after executing it as a template with data parameter. 59 | // If the update flag is set, it will also update the golden file. 60 | // `name` refers to the name of the test and it should typically be unique 61 | // within the package. Also it should be a valid file name (so keeping to 62 | // `a-z0-9\-\_` is a good idea). 63 | func AssertWithTemplate(t *testing.T, name string, data interface{}, actualData []byte) { 64 | if *update { 65 | err := Update(name, actualData) 66 | if err != nil { 67 | t.Error(err) 68 | t.FailNow() 69 | } 70 | } 71 | 72 | err := compare(name, data, actualData) 73 | if err != nil { 74 | switch err.(type) { 75 | case errFixtureNotFound: 76 | t.Error(err) 77 | t.FailNow() 78 | case errFixtureMismatch: 79 | t.Error(err) 80 | default: 81 | t.Error(err) 82 | } 83 | } 84 | } 85 | 86 | // Update will update the golden fixtures with the received actual data. 87 | // 88 | // This method does not need to be called from code, but it's exposed so that it 89 | // can be explicitly called if needed. The more common approach would be to 90 | // update using `go test -update ./...`. 91 | func Update(name string, actualData []byte) error { 92 | if err := ensureDir(filepath.Dir(goldenFileName(name))); err != nil { 93 | return err 94 | } 95 | 96 | return ioutil.WriteFile(goldenFileName(name), actualData, FilePerms) 97 | } 98 | 99 | // compare is reading the golden fixture file and compare the stored data with 100 | // the actual data. 101 | func compare(name string, data interface{}, actualData []byte) error { 102 | expectedDataTmpl, err := ioutil.ReadFile(goldenFileName(name)) 103 | 104 | if err != nil { 105 | if os.IsNotExist(err) { 106 | return newErrFixtureNotFound() 107 | } 108 | 109 | return fmt.Errorf("Expected %s to be nil", err.Error()) 110 | } 111 | 112 | tmpl, err := template.New("test").Parse(string(expectedDataTmpl)) 113 | if err != nil { 114 | return fmt.Errorf("Expected %s to be nil", err.Error()) 115 | } 116 | 117 | var expectedData bytes.Buffer 118 | err = tmpl.Execute(&expectedData, data) 119 | if err != nil { 120 | return fmt.Errorf("Expected %s to be nil", err.Error()) 121 | } 122 | 123 | if !bytes.Equal(actualData, expectedData.Bytes()) { 124 | return newErrFixtureMismatch( 125 | fmt.Sprintf("Result did not match the golden fixture.\n"+ 126 | "Expected: %s\n"+ 127 | "Got: %s", 128 | string(expectedData.Bytes()), 129 | string(actualData))) 130 | } 131 | 132 | return nil 133 | } 134 | 135 | // ensureDir will create the fixture folder if it does not already exist. 136 | func ensureDir(loc string) error { 137 | s, err := os.Stat(loc) 138 | switch { 139 | case err != nil && os.IsNotExist(err): 140 | // the location does not exist, so make directories to there 141 | err = os.MkdirAll(loc, DirPerms) 142 | if err != nil { 143 | return err 144 | } 145 | return err 146 | case err == nil && !s.IsDir(): 147 | return newErrFixtureDirectoryIsFile(loc) 148 | default: 149 | return err 150 | } 151 | } 152 | 153 | // goldenFileName simply returns the file name of the golden file fixture. 154 | func goldenFileName(name string) string { 155 | return filepath.Join(FixtureDir, fmt.Sprintf("%s%s", name, FileNameSuffix)) 156 | } 157 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/http_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/http/httptest" 7 | "net/url" 8 | "strings" 9 | ) 10 | 11 | // httpCode is a helper that returns HTTP code of the response. It returns -1 and 12 | // an error if building a new request fails. 13 | func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { 14 | w := httptest.NewRecorder() 15 | req, err := http.NewRequest(method, url, nil) 16 | if err != nil { 17 | return -1, err 18 | } 19 | req.URL.RawQuery = values.Encode() 20 | handler(w, req) 21 | return w.Code, nil 22 | } 23 | 24 | // HTTPSuccess asserts that a specified handler returns a success status code. 25 | // 26 | // assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) 27 | // 28 | // Returns whether the assertion was successful (true) or not (false). 29 | func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 30 | if h, ok := t.(tHelper); ok { 31 | h.Helper() 32 | } 33 | code, err := httpCode(handler, method, url, values) 34 | if err != nil { 35 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) 36 | return false 37 | } 38 | 39 | isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent 40 | if !isSuccessCode { 41 | Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code)) 42 | } 43 | 44 | return isSuccessCode 45 | } 46 | 47 | // HTTPRedirect asserts that a specified handler returns a redirect status code. 48 | // 49 | // assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} 50 | // 51 | // Returns whether the assertion was successful (true) or not (false). 52 | func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 53 | if h, ok := t.(tHelper); ok { 54 | h.Helper() 55 | } 56 | code, err := httpCode(handler, method, url, values) 57 | if err != nil { 58 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) 59 | return false 60 | } 61 | 62 | isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect 63 | if !isRedirectCode { 64 | Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code)) 65 | } 66 | 67 | return isRedirectCode 68 | } 69 | 70 | // HTTPError asserts that a specified handler returns an error status code. 71 | // 72 | // assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} 73 | // 74 | // Returns whether the assertion was successful (true) or not (false). 75 | func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 76 | if h, ok := t.(tHelper); ok { 77 | h.Helper() 78 | } 79 | code, err := httpCode(handler, method, url, values) 80 | if err != nil { 81 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) 82 | return false 83 | } 84 | 85 | isErrorCode := code >= http.StatusBadRequest 86 | if !isErrorCode { 87 | Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code)) 88 | } 89 | 90 | return isErrorCode 91 | } 92 | 93 | // HTTPBody is a helper that returns HTTP body of the response. It returns 94 | // empty string if building a new request fails. 95 | func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { 96 | w := httptest.NewRecorder() 97 | req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) 98 | if err != nil { 99 | return "" 100 | } 101 | handler(w, req) 102 | return w.Body.String() 103 | } 104 | 105 | // HTTPBodyContains asserts that a specified handler returns a 106 | // body that contains a string. 107 | // 108 | // assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") 109 | // 110 | // Returns whether the assertion was successful (true) or not (false). 111 | func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { 112 | if h, ok := t.(tHelper); ok { 113 | h.Helper() 114 | } 115 | body := HTTPBody(handler, method, url, values) 116 | 117 | contains := strings.Contains(body, fmt.Sprint(str)) 118 | if !contains { 119 | Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) 120 | } 121 | 122 | return contains 123 | } 124 | 125 | // HTTPBodyNotContains asserts that a specified handler returns a 126 | // body that does not contain a string. 127 | // 128 | // assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") 129 | // 130 | // Returns whether the assertion was successful (true) or not (false). 131 | func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { 132 | if h, ok := t.(tHelper); ok { 133 | h.Helper() 134 | } 135 | body := HTTPBody(handler, method, url, values) 136 | 137 | contains := strings.Contains(body, fmt.Sprint(str)) 138 | if contains { 139 | Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) 140 | } 141 | 142 | return !contains 143 | } 144 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/mysql/types.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strconv" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | // For MySQL DATE type 12 | type Date struct { 13 | Year int16 14 | Month, Day byte 15 | } 16 | 17 | func (dd Date) String() string { 18 | return fmt.Sprintf("%04d-%02d-%02d", dd.Year, dd.Month, dd.Day) 19 | } 20 | 21 | // True if date is 0000-00-00 22 | func (dd Date) IsZero() bool { 23 | return dd.Day == 0 && dd.Month == 0 && dd.Year == 0 24 | } 25 | 26 | // Converts Date to time.Time using loc location. 27 | // Converts MySQL zero to time.Time zero. 28 | func (dd Date) Time(loc *time.Location) (t time.Time) { 29 | if !dd.IsZero() { 30 | t = time.Date( 31 | int(dd.Year), time.Month(dd.Month), int(dd.Day), 32 | 0, 0, 0, 0, 33 | loc, 34 | ) 35 | } 36 | return 37 | } 38 | 39 | // Converts Date to time.Time using Local location. 40 | // Converts MySQL zero to time.Time zero. 41 | func (dd Date) Localtime() time.Time { 42 | return dd.Time(time.Local) 43 | } 44 | 45 | // Convert string date in format YYYY-MM-DD to Date. 46 | // Leading and trailing spaces are ignored. 47 | func ParseDate(str string) (dd Date, err error) { 48 | str = strings.TrimSpace(str) 49 | if str == "0000-00-00" { 50 | return 51 | } 52 | var ( 53 | y, m, d int 54 | ) 55 | if len(str) != 10 || str[4] != '-' || str[7] != '-' { 56 | goto invalid 57 | } 58 | if y, err = strconv.Atoi(str[0:4]); err != nil { 59 | return 60 | } 61 | if m, err = strconv.Atoi(str[5:7]); err != nil { 62 | return 63 | } 64 | if m < 0 || m > 12 { // MySQL permits month == 0 65 | goto invalid 66 | } 67 | if d, err = strconv.Atoi(str[8:10]); err != nil { 68 | return 69 | } 70 | if d < 0 { // MySQL permits day == 0 71 | goto invalid 72 | } 73 | switch m { 74 | case 1, 3, 5, 7, 8, 10, 12: 75 | if d > 31 { 76 | goto invalid 77 | } 78 | case 4, 6, 9, 11: 79 | if d > 30 { 80 | goto invalid 81 | } 82 | case 2: 83 | if d > 29 { 84 | goto invalid 85 | } 86 | } 87 | dd.Year = int16(y) 88 | dd.Month = byte(m) 89 | dd.Day = byte(d) 90 | return 91 | 92 | invalid: 93 | err = errors.New("Invalid MySQL DATE string: " + str) 94 | return 95 | } 96 | 97 | // Sandard MySQL datetime format 98 | const TimeFormat = "2006-01-02 15:04:05.000000000" 99 | 100 | // Returns t as string in MySQL format Converts time.Time zero to MySQL zero. 101 | func TimeString(t time.Time) string { 102 | if t.IsZero() { 103 | return "0000-00-00 00:00:00" 104 | } 105 | if t.Nanosecond() == 0 { 106 | return t.Format(TimeFormat[:19]) 107 | } 108 | return t.Format(TimeFormat) 109 | } 110 | 111 | // Parses string datetime in TimeFormat using loc location. 112 | // Converts MySQL zero to time.Time zero. 113 | func ParseTime(str string, loc *time.Location) (t time.Time, err error) { 114 | str = strings.TrimSpace(str) 115 | format := TimeFormat[:19] 116 | switch len(str) { 117 | case 10: 118 | if str == "0000-00-00" { 119 | return 120 | } 121 | format = format[:10] 122 | case 19: 123 | if str == "0000-00-00 00:00:00" { 124 | return 125 | } 126 | } 127 | // Don't expect 0000-00-00 00:00:00.0+ 128 | t, err = time.ParseInLocation(format, str, loc) 129 | return 130 | } 131 | 132 | // Convert time.Duration to string representation of mysql.TIME 133 | func DurationString(d time.Duration) string { 134 | sign := 1 135 | if d < 0 { 136 | sign = -1 137 | d = -d 138 | } 139 | ns := int(d % 1e9) 140 | d /= 1e9 141 | sec := int(d % 60) 142 | d /= 60 143 | min := int(d % 60) 144 | hour := int(d/60) * sign 145 | if ns == 0 { 146 | return fmt.Sprintf("%d:%02d:%02d", hour, min, sec) 147 | } 148 | return fmt.Sprintf("%d:%02d:%02d.%09d", hour, min, sec, ns) 149 | } 150 | 151 | // Parse duration from MySQL string format [+-]H+:MM:SS[.UUUUUUUUU]. 152 | // Leading and trailing spaces are ignored. If format is invalid returns nil. 153 | func ParseDuration(str string) (dur time.Duration, err error) { 154 | str = strings.TrimSpace(str) 155 | orig := str 156 | // Check sign 157 | sign := int64(1) 158 | switch str[0] { 159 | case '-': 160 | sign = -1 161 | fallthrough 162 | case '+': 163 | str = str[1:] 164 | } 165 | var i, d int64 166 | // Find houre 167 | if nn := strings.IndexRune(str, ':'); nn != -1 { 168 | if i, err = strconv.ParseInt(str[0:nn], 10, 64); err != nil { 169 | return 170 | } 171 | d = i * 3600 172 | str = str[nn+1:] 173 | } else { 174 | goto invalid 175 | } 176 | if len(str) != 5 && len(str) != 15 || str[2] != ':' { 177 | goto invalid 178 | } 179 | if i, err = strconv.ParseInt(str[0:2], 10, 64); err != nil { 180 | return 181 | } 182 | if i < 0 || i > 59 { 183 | goto invalid 184 | } 185 | d += i * 60 186 | if i, err = strconv.ParseInt(str[3:5], 10, 64); err != nil { 187 | return 188 | } 189 | if i < 0 || i > 59 { 190 | goto invalid 191 | } 192 | d += i 193 | d *= 1e9 194 | if len(str) == 15 { 195 | if str[5] != '.' { 196 | goto invalid 197 | } 198 | if i, err = strconv.ParseInt(str[6:15], 10, 64); err != nil { 199 | return 200 | } 201 | d += i 202 | } 203 | dur = time.Duration(d * sign) 204 | return 205 | 206 | invalid: 207 | err = errors.New("invalid MySQL TIME string: " + orig) 208 | return 209 | 210 | } 211 | 212 | type Blob []byte 213 | 214 | type Raw struct { 215 | Typ uint16 216 | Val *[]byte 217 | } 218 | 219 | type Timestamp struct { 220 | time.Time 221 | } 222 | 223 | func (t Timestamp) String() string { 224 | return TimeString(t.Time) 225 | } 226 | -------------------------------------------------------------------------------- /fixtures/test_innodb_source.golden: -------------------------------------------------------------------------------- 1 | ===================================== 2 | 2018-07-20 17:04:00 0x7fb07c0f0700 INNODB MONITOR OUTPUT 3 | ===================================== 4 | Per second averages calculated from the last 13 seconds 5 | ----------------- 6 | BACKGROUND THREAD 7 | ----------------- 8 | srv_master_thread loops: 40 srv_active, 0 srv_shutdown, 935995 srv_idle 9 | srv_master_thread log flush and writes: 0 10 | ---------- 11 | SEMAPHORES 12 | ---------- 13 | OS WAIT ARRAY INFO: reservation count 107 14 | OS WAIT ARRAY INFO: signal count 108 15 | Mutex spin waits 5870888, rounds 19812448, OS waits 375285 16 | RW-shared spins 34, rounds 59, OS waits 27 17 | RW-excl spins 63, rounds 506, OS waits 3 18 | RW-sx spins 1, rounds 3, OS waits 0 19 | Spin rounds per wait: 1.74 RW-shared, 8.03 RW-excl, 3.00 RW-sx 20 | ------------ 21 | TRANSACTIONS 22 | ------------ 23 | Trx id counter 3157 24 | Purge done for trx's n:o < 3157 undo n:o < 0 state: running but idle 25 | History list length 35 26 | LIST OF TRANSACTIONS FOR EACH SESSION: 27 | ---TRANSACTION 421871135909728, not started 28 | 0 lock struct(s), heap size 1136, 0 row lock(s) 29 | ---TRANSACTION 11114640964, ACTIVE (PREPARED) 0 sec 30 | 4 lock struct(s), heap size 1184, 2 row lock(s), undo log entries 2 31 | ---TRANSACTION 2834, ACTIVE 11 sec inserting 32 | mysql tables in use 1, locked 1 33 | 1 lock struct(s), heap size 1136, 0 row lock(s), undo log entries 1929 34 | MySQL thread id 3959, OS thread handle 140395972331264, query id 1797 10.231.66.70 lzd update 35 | INSERT INTO payment VALUES (1,1,1,76,'2.99','2005-05-25 11:30:37','2006-02-15 22:12:30'),(2,1,1,573,'0.99','2005-05-28 10:35:23','2006-02-15 22:12:30'),(3,1,1,1185,'5.99','2005-06-15 00:54:12','2006-02-15 22:12:30'),(4,1,2,1422,'0.99','2005-06-15 18:02:53','2006-02-15 22:12:30'),(5,1,2,1476,'9.99','2005-06-15 21:08:46','2006-02-15 22:12:30'),(6,1,1,1725,'4.99','2005-06-16 15:18:57','2006-02-15 22:12:30'),(7,1,1,2308,'4.99','2005-06-18 08:41:48',) 36 | ---TRANSACTION 28345, ACTIVE 1 sec inserting 37 | mysql tables in use 1, locked 1 38 | 1 lock struct(s), heap size 1136, 0 row lock(s), undo log entries 1929 39 | MySQL thread id 3959, OS thread handle 140395972331264, query id 1797 10.231.66.70 lzd update 40 | INSERT INTO payment VALUES (1,1,1,76,'2.99','2005-05-25 11:30:37','2006-02-15 22:12:30') 41 | -------- 42 | FILE I/O 43 | -------- 44 | I/O thread 0 state: waiting for completed aio requests (insert buffer thread) 45 | I/O thread 1 state: waiting for completed aio requests (log thread) 46 | I/O thread 2 state: waiting for completed aio requests (read thread) 47 | I/O thread 3 state: waiting for completed aio requests (read thread) 48 | I/O thread 4 state: waiting for completed aio requests (read thread) 49 | I/O thread 5 state: waiting for completed aio requests (read thread) 50 | I/O thread 6 state: waiting for completed aio requests (write thread) 51 | I/O thread 7 state: waiting for completed aio requests (write thread) 52 | I/O thread 8 state: waiting for completed aio requests (write thread) 53 | I/O thread 9 state: waiting for completed aio requests (write thread) 54 | Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] , 55 | ibuf aio reads:, log i/o's:, sync i/o's: 56 | Pending flushes (fsync) log: 0; buffer pool: 0 57 | 882 OS file reads, 80603 OS file writes, 3783 OS fsyncs 58 | 0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s 59 | ------------------------------------- 60 | INSERT BUFFER AND ADAPTIVE HASH INDEX 61 | ------------------------------------- 62 | Ibuf: size 1, free list len 0, seg size 2, 0 merges 63 | merged operations: 64 | insert 0, delete mark 0, delete 0 65 | discarded operations: 66 | insert 0, delete mark 0, delete 0 67 | Hash table size 34679, node heap has 1 buffer(s) 68 | Hash table size 34679, node heap has 2 buffer(s) 69 | Hash table size 34679, node heap has 4 buffer(s) 70 | Hash table size 34679, node heap has 1 buffer(s) 71 | Hash table size 34679, node heap has 1 buffer(s) 72 | Hash table size 34679, node heap has 2 buffer(s) 73 | Hash table size 34679, node heap has 2 buffer(s) 74 | Hash table size 34679, node heap has 9 buffer(s) 75 | 0.00 hash searches/s, 0.00 non-hash searches/s 76 | --- 77 | LOG 78 | --- 79 | Log sequence number 27640063 80 | Log buffer assigned up to 27640063 81 | Log buffer completed up to 27640063 82 | Log written up to 27640063 83 | Log flushed up to 27640063 84 | Added dirty pages up to 27640063 85 | Pages flushed up to 27640063 86 | Last checkpoint at 27640063 87 | 78255 log i/o's done, 0.00 log i/o's/second 88 | ---------------------- 89 | BUFFER POOL AND MEMORY 90 | ---------------------- 91 | Total large memory allocated 137428992 92 | Dictionary memory allocated 657058 93 | Buffer pool size 8192 94 | Free buffers 6673 95 | Database pages 1497 96 | Old database pages 532 97 | Modified dbTestMaster pages 0 98 | Pending reads 0 99 | Pending writes: LRU 0, flush list 0, single page 0 100 | Pages made young 3, not young 0 101 | 0.00 youngs/s, 0.00 non-youngs/s 102 | Pages read 859, created 638, written 1977 103 | 0.00 reads/s, 0.00 creates/s, 0.00 writes/s 104 | No buffer pool page gets since the last printout 105 | Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s 106 | LRU len: 1497, unzip_LRU len: 0 107 | I/O sum[0]:cur[0], unzip sum[0]:cur[0] 108 | -------------- 109 | ROW OPERATIONS 110 | -------------- 111 | 0 queries inside InnoDB, 0 queries in queue 112 | 0 read views open inside InnoDB 113 | Process ID=7680, Main thread ID=140395649316608 , state=sleeping 114 | Number of rows inserted 47214, updated 1972, deleted 137, read 12173 115 | 0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s 116 | ---------------------------- 117 | END OF INNODB MONITOR OUTPUT 118 | ============================ -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypass.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is not running on Google App Engine, compiled by GopherJS, and 17 | // "-tags safe" is not added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build !js,!appengine,!safe,!disableunsafe 20 | 21 | package spew 22 | 23 | import ( 24 | "reflect" 25 | "unsafe" 26 | ) 27 | 28 | const ( 29 | // UnsafeDisabled is a build-time constant which specifies whether or 30 | // not access to the unsafe package is available. 31 | UnsafeDisabled = false 32 | 33 | // ptrSize is the size of a pointer on the current arch. 34 | ptrSize = unsafe.Sizeof((*byte)(nil)) 35 | ) 36 | 37 | var ( 38 | // offsetPtr, offsetScalar, and offsetFlag are the offsets for the 39 | // internal reflect.Value fields. These values are valid before golang 40 | // commit ecccf07e7f9d which changed the format. The are also valid 41 | // after commit 82f48826c6c7 which changed the format again to mirror 42 | // the original format. Code in the init function updates these offsets 43 | // as necessary. 44 | offsetPtr = uintptr(ptrSize) 45 | offsetScalar = uintptr(0) 46 | offsetFlag = uintptr(ptrSize * 2) 47 | 48 | // flagKindWidth and flagKindShift indicate various bits that the 49 | // reflect package uses internally to track kind information. 50 | // 51 | // flagRO indicates whether or not the value field of a reflect.Value is 52 | // read-only. 53 | // 54 | // flagIndir indicates whether the value field of a reflect.Value is 55 | // the actual data or a pointer to the data. 56 | // 57 | // These values are valid before golang commit 90a7c3c86944 which 58 | // changed their positions. Code in the init function updates these 59 | // flags as necessary. 60 | flagKindWidth = uintptr(5) 61 | flagKindShift = uintptr(flagKindWidth - 1) 62 | flagRO = uintptr(1 << 0) 63 | flagIndir = uintptr(1 << 1) 64 | ) 65 | 66 | func init() { 67 | // Older versions of reflect.Value stored small integers directly in the 68 | // ptr field (which is named val in the older versions). Versions 69 | // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named 70 | // scalar for this purpose which unfortunately came before the flag 71 | // field, so the offset of the flag field is different for those 72 | // versions. 73 | // 74 | // This code constructs a new reflect.Value from a known small integer 75 | // and checks if the size of the reflect.Value struct indicates it has 76 | // the scalar field. When it does, the offsets are updated accordingly. 77 | vv := reflect.ValueOf(0xf00) 78 | if unsafe.Sizeof(vv) == (ptrSize * 4) { 79 | offsetScalar = ptrSize * 2 80 | offsetFlag = ptrSize * 3 81 | } 82 | 83 | // Commit 90a7c3c86944 changed the flag positions such that the low 84 | // order bits are the kind. This code extracts the kind from the flags 85 | // field and ensures it's the correct type. When it's not, the flag 86 | // order has been changed to the newer format, so the flags are updated 87 | // accordingly. 88 | upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) 89 | upfv := *(*uintptr)(upf) 90 | flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) { 92 | flagKindShift = 0 93 | flagRO = 1 << 5 94 | flagIndir = 1 << 6 95 | 96 | // Commit adf9b30e5594 modified the flags to separate the 97 | // flagRO flag into two bits which specifies whether or not the 98 | // field is embedded. This causes flagIndir to move over a bit 99 | // and means that flagRO is the combination of either of the 100 | // original flagRO bit and the new bit. 101 | // 102 | // This code detects the change by extracting what used to be 103 | // the indirect bit to ensure it's set. When it's not, the flag 104 | // order has been changed to the newer format, so the flags are 105 | // updated accordingly. 106 | if upfv&flagIndir == 0 { 107 | flagRO = 3 << 5 108 | flagIndir = 1 << 7 109 | } 110 | } 111 | } 112 | 113 | // unsafeReflectValue converts the passed reflect.Value into a one that bypasses 114 | // the typical safety restrictions preventing access to unaddressable and 115 | // unexported data. It works by digging the raw pointer to the underlying 116 | // value out of the protected value and generating a new unprotected (unsafe) 117 | // reflect.Value to it. 118 | // 119 | // This allows us to check for implementations of the Stringer and error 120 | // interfaces to be used for pretty printing ordinarily unaddressable and 121 | // inaccessible values such as unexported struct fields. 122 | func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { 123 | indirects := 1 124 | vt := v.Type() 125 | upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) 126 | rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) 127 | if rvf&flagIndir != 0 { 128 | vt = reflect.PtrTo(v.Type()) 129 | indirects++ 130 | } else if offsetScalar != 0 { 131 | // The value is in the scalar field when it's not one of the 132 | // reference types. 133 | switch vt.Kind() { 134 | case reflect.Uintptr: 135 | case reflect.Chan: 136 | case reflect.Func: 137 | case reflect.Map: 138 | case reflect.Ptr: 139 | case reflect.UnsafePointer: 140 | default: 141 | upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + 142 | offsetScalar) 143 | } 144 | } 145 | 146 | pv := reflect.NewAt(vt, upv) 147 | rv = pv 148 | for i := 0; i < indirects; i++ { 149 | rv = rv.Elem() 150 | } 151 | return rv 152 | } 153 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/spew.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | ) 23 | 24 | // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were 25 | // passed with a default Formatter interface returned by NewFormatter. It 26 | // returns the formatted string as a value that satisfies error. See 27 | // NewFormatter for formatting details. 28 | // 29 | // This function is shorthand for the following syntax: 30 | // 31 | // fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 32 | func Errorf(format string, a ...interface{}) (err error) { 33 | return fmt.Errorf(format, convertArgs(a)...) 34 | } 35 | 36 | // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were 37 | // passed with a default Formatter interface returned by NewFormatter. It 38 | // returns the number of bytes written and any write error encountered. See 39 | // NewFormatter for formatting details. 40 | // 41 | // This function is shorthand for the following syntax: 42 | // 43 | // fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) 44 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) { 45 | return fmt.Fprint(w, convertArgs(a)...) 46 | } 47 | 48 | // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were 49 | // passed with a default Formatter interface returned by NewFormatter. It 50 | // returns the number of bytes written and any write error encountered. See 51 | // NewFormatter for formatting details. 52 | // 53 | // This function is shorthand for the following syntax: 54 | // 55 | // fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) 56 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { 57 | return fmt.Fprintf(w, format, convertArgs(a)...) 58 | } 59 | 60 | // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it 61 | // passed with a default Formatter interface returned by NewFormatter. See 62 | // NewFormatter for formatting details. 63 | // 64 | // This function is shorthand for the following syntax: 65 | // 66 | // fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) 67 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { 68 | return fmt.Fprintln(w, convertArgs(a)...) 69 | } 70 | 71 | // Print is a wrapper for fmt.Print that treats each argument as if it were 72 | // passed with a default Formatter interface returned by NewFormatter. It 73 | // returns the number of bytes written and any write error encountered. See 74 | // NewFormatter for formatting details. 75 | // 76 | // This function is shorthand for the following syntax: 77 | // 78 | // fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) 79 | func Print(a ...interface{}) (n int, err error) { 80 | return fmt.Print(convertArgs(a)...) 81 | } 82 | 83 | // Printf is a wrapper for fmt.Printf that treats each argument as if it were 84 | // passed with a default Formatter interface returned by NewFormatter. It 85 | // returns the number of bytes written and any write error encountered. See 86 | // NewFormatter for formatting details. 87 | // 88 | // This function is shorthand for the following syntax: 89 | // 90 | // fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 91 | func Printf(format string, a ...interface{}) (n int, err error) { 92 | return fmt.Printf(format, convertArgs(a)...) 93 | } 94 | 95 | // Println is a wrapper for fmt.Println that treats each argument as if it were 96 | // passed with a default Formatter interface returned by NewFormatter. It 97 | // returns the number of bytes written and any write error encountered. See 98 | // NewFormatter for formatting details. 99 | // 100 | // This function is shorthand for the following syntax: 101 | // 102 | // fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) 103 | func Println(a ...interface{}) (n int, err error) { 104 | return fmt.Println(convertArgs(a)...) 105 | } 106 | 107 | // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were 108 | // passed with a default Formatter interface returned by NewFormatter. It 109 | // returns the resulting string. See NewFormatter for formatting details. 110 | // 111 | // This function is shorthand for the following syntax: 112 | // 113 | // fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) 114 | func Sprint(a ...interface{}) string { 115 | return fmt.Sprint(convertArgs(a)...) 116 | } 117 | 118 | // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were 119 | // passed with a default Formatter interface returned by NewFormatter. It 120 | // returns the resulting string. See NewFormatter for formatting details. 121 | // 122 | // This function is shorthand for the following syntax: 123 | // 124 | // fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 125 | func Sprintf(format string, a ...interface{}) string { 126 | return fmt.Sprintf(format, convertArgs(a)...) 127 | } 128 | 129 | // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it 130 | // were passed with a default Formatter interface returned by NewFormatter. It 131 | // returns the resulting string. See NewFormatter for formatting details. 132 | // 133 | // This function is shorthand for the following syntax: 134 | // 135 | // fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) 136 | func Sprintln(a ...interface{}) string { 137 | return fmt.Sprintln(convertArgs(a)...) 138 | } 139 | 140 | // convertArgs accepts a slice of arguments and returns a slice of the same 141 | // length with each argument converted to a default spew Formatter interface. 142 | func convertArgs(args []interface{}) (formatters []interface{}) { 143 | formatters = make([]interface{}, len(args)) 144 | for index, arg := range args { 145 | formatters[index] = NewFormatter(arg) 146 | } 147 | return formatters 148 | } 149 | -------------------------------------------------------------------------------- /vendor/github.com/astaxie/beego/logs/logger.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 beego Author. All Rights Reserved. 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 | package logs 16 | 17 | import ( 18 | "fmt" 19 | "io" 20 | "os" 21 | "sync" 22 | "time" 23 | ) 24 | 25 | type logWriter struct { 26 | sync.Mutex 27 | writer io.Writer 28 | } 29 | 30 | func newLogWriter(wr io.Writer) *logWriter { 31 | return &logWriter{writer: wr} 32 | } 33 | 34 | func (lg *logWriter) println(when time.Time, msg string) { 35 | lg.Lock() 36 | h, _ := formatTimeHeader(when) 37 | lg.writer.Write(append(append(h, msg...), '\n')) 38 | lg.Unlock() 39 | } 40 | 41 | type outputMode int 42 | 43 | // DiscardNonColorEscSeq supports the divided color escape sequence. 44 | // But non-color escape sequence is not output. 45 | // Please use the OutputNonColorEscSeq If you want to output a non-color 46 | // escape sequences such as ncurses. However, it does not support the divided 47 | // color escape sequence. 48 | const ( 49 | _ outputMode = iota 50 | DiscardNonColorEscSeq 51 | OutputNonColorEscSeq 52 | ) 53 | 54 | // NewAnsiColorWriter creates and initializes a new ansiColorWriter 55 | // using io.Writer w as its initial contents. 56 | // In the console of Windows, which change the foreground and background 57 | // colors of the text by the escape sequence. 58 | // In the console of other systems, which writes to w all text. 59 | func NewAnsiColorWriter(w io.Writer) io.Writer { 60 | return NewModeAnsiColorWriter(w, DiscardNonColorEscSeq) 61 | } 62 | 63 | // NewModeAnsiColorWriter create and initializes a new ansiColorWriter 64 | // by specifying the outputMode. 65 | func NewModeAnsiColorWriter(w io.Writer, mode outputMode) io.Writer { 66 | if _, ok := w.(*ansiColorWriter); !ok { 67 | return &ansiColorWriter{ 68 | w: w, 69 | mode: mode, 70 | } 71 | } 72 | return w 73 | } 74 | 75 | const ( 76 | y1 = `0123456789` 77 | y2 = `0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789` 78 | y3 = `0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999` 79 | y4 = `0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789` 80 | mo1 = `000000000111` 81 | mo2 = `123456789012` 82 | d1 = `0000000001111111111222222222233` 83 | d2 = `1234567890123456789012345678901` 84 | h1 = `000000000011111111112222` 85 | h2 = `012345678901234567890123` 86 | mi1 = `000000000011111111112222222222333333333344444444445555555555` 87 | mi2 = `012345678901234567890123456789012345678901234567890123456789` 88 | s1 = `000000000011111111112222222222333333333344444444445555555555` 89 | s2 = `012345678901234567890123456789012345678901234567890123456789` 90 | ns1 = `0123456789` 91 | ) 92 | 93 | func formatTimeHeader(when time.Time) ([]byte, int) { 94 | y, mo, d := when.Date() 95 | h, mi, s := when.Clock() 96 | ns := when.Nanosecond()/1000000 97 | //len("2006/01/02 15:04:05.123 ")==24 98 | var buf [24]byte 99 | 100 | buf[0] = y1[y/1000%10] 101 | buf[1] = y2[y/100] 102 | buf[2] = y3[y-y/100*100] 103 | buf[3] = y4[y-y/100*100] 104 | buf[4] = '/' 105 | buf[5] = mo1[mo-1] 106 | buf[6] = mo2[mo-1] 107 | buf[7] = '/' 108 | buf[8] = d1[d-1] 109 | buf[9] = d2[d-1] 110 | buf[10] = ' ' 111 | buf[11] = h1[h] 112 | buf[12] = h2[h] 113 | buf[13] = ':' 114 | buf[14] = mi1[mi] 115 | buf[15] = mi2[mi] 116 | buf[16] = ':' 117 | buf[17] = s1[s] 118 | buf[18] = s2[s] 119 | buf[19] = '.' 120 | buf[20] = ns1[ns/100] 121 | buf[21] = ns1[ns%100/10] 122 | buf[22] = ns1[ns%10] 123 | 124 | buf[23] = ' ' 125 | 126 | return buf[0:], d 127 | } 128 | 129 | var ( 130 | green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) 131 | white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) 132 | yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109}) 133 | red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109}) 134 | blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109}) 135 | magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109}) 136 | cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109}) 137 | 138 | w32Green = string([]byte{27, 91, 52, 50, 109}) 139 | w32White = string([]byte{27, 91, 52, 55, 109}) 140 | w32Yellow = string([]byte{27, 91, 52, 51, 109}) 141 | w32Red = string([]byte{27, 91, 52, 49, 109}) 142 | w32Blue = string([]byte{27, 91, 52, 52, 109}) 143 | w32Magenta = string([]byte{27, 91, 52, 53, 109}) 144 | w32Cyan = string([]byte{27, 91, 52, 54, 109}) 145 | 146 | reset = string([]byte{27, 91, 48, 109}) 147 | ) 148 | 149 | // ColorByStatus return color by http code 150 | // 2xx return Green 151 | // 3xx return White 152 | // 4xx return Yellow 153 | // 5xx return Red 154 | func ColorByStatus(cond bool, code int) string { 155 | switch { 156 | case code >= 200 && code < 300: 157 | return map[bool]string{true: green, false: w32Green}[cond] 158 | case code >= 300 && code < 400: 159 | return map[bool]string{true: white, false: w32White}[cond] 160 | case code >= 400 && code < 500: 161 | return map[bool]string{true: yellow, false: w32Yellow}[cond] 162 | default: 163 | return map[bool]string{true: red, false: w32Red}[cond] 164 | } 165 | } 166 | 167 | // ColorByMethod return color by http code 168 | // GET return Blue 169 | // POST return Cyan 170 | // PUT return Yellow 171 | // DELETE return Red 172 | // PATCH return Green 173 | // HEAD return Magenta 174 | // OPTIONS return WHITE 175 | func ColorByMethod(cond bool, method string) string { 176 | switch method { 177 | case "GET": 178 | return map[bool]string{true: blue, false: w32Blue}[cond] 179 | case "POST": 180 | return map[bool]string{true: cyan, false: w32Cyan}[cond] 181 | case "PUT": 182 | return map[bool]string{true: yellow, false: w32Yellow}[cond] 183 | case "DELETE": 184 | return map[bool]string{true: red, false: w32Red}[cond] 185 | case "PATCH": 186 | return map[bool]string{true: green, false: w32Green}[cond] 187 | case "HEAD": 188 | return map[bool]string{true: magenta, false: w32Magenta}[cond] 189 | case "OPTIONS": 190 | return map[bool]string{true: white, false: w32White}[cond] 191 | default: 192 | return reset 193 | } 194 | } 195 | 196 | // Guard Mutex to guarantee atomic of W32Debug(string) function 197 | var mu sync.Mutex 198 | 199 | // W32Debug Helper method to output colored logs in Windows terminals 200 | func W32Debug(msg string) { 201 | mu.Lock() 202 | defer mu.Unlock() 203 | 204 | current := time.Now() 205 | w := NewAnsiColorWriter(os.Stdout) 206 | 207 | fmt.Fprintf(w, "[beego] %v %s\n", current.Format("2006/01/02 - 15:04:05"), msg) 208 | } 209 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/native/init.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/rsa" 6 | "crypto/sha1" 7 | "crypto/x509" 8 | "encoding/pem" 9 | "log" 10 | 11 | "github.com/ziutek/mymysql/mysql" 12 | ) 13 | 14 | func (my *Conn) init() { 15 | my.seq = 0 // Reset sequence number, mainly for reconnect 16 | if my.Debug { 17 | log.Printf("[%2d ->] Init packet:", my.seq) 18 | } 19 | pr := my.newPktReader() 20 | 21 | my.info.prot_ver = pr.readByte() 22 | my.info.serv_ver = pr.readNTB() 23 | my.info.thr_id = pr.readU32() 24 | pr.readFull(my.info.scramble[0:8]) 25 | pr.skipN(1) 26 | my.info.caps = uint32(pr.readU16()) // lower two bytes 27 | my.info.lang = pr.readByte() 28 | my.status = mysql.ConnStatus(pr.readU16()) 29 | my.info.caps = uint32(pr.readU16())<<16 | my.info.caps // upper two bytes 30 | pr.skipN(11) 31 | if my.info.caps&_CLIENT_PROTOCOL_41 != 0 { 32 | pr.readFull(my.info.scramble[8:]) 33 | } 34 | pr.skipN(1) // reserved (all [00]) 35 | if my.info.caps&_CLIENT_PLUGIN_AUTH != 0 { 36 | my.info.plugin = pr.readNTB() 37 | } 38 | pr.skipAll() // Skip other information 39 | if my.Debug { 40 | log.Printf(tab8s+"ProtVer=%d, ServVer=\"%s\" Status=0x%x", 41 | my.info.prot_ver, my.info.serv_ver, my.status, 42 | ) 43 | } 44 | if my.info.caps&_CLIENT_PROTOCOL_41 == 0 { 45 | panic(mysql.ErrOldProtocol) 46 | } 47 | } 48 | 49 | func (my *Conn) auth() { 50 | if my.Debug { 51 | log.Printf("[%2d <-] Authentication packet", my.seq) 52 | } 53 | flags := uint32( 54 | _CLIENT_PROTOCOL_41 | 55 | _CLIENT_LONG_PASSWORD | 56 | _CLIENT_LONG_FLAG | 57 | _CLIENT_TRANSACTIONS | 58 | _CLIENT_SECURE_CONN | 59 | _CLIENT_LOCAL_FILES | 60 | _CLIENT_MULTI_STATEMENTS | 61 | _CLIENT_MULTI_RESULTS) 62 | // Reset flags not supported by server 63 | flags &= uint32(my.info.caps) | 0xffff0000 64 | if my.plugin != string(my.info.plugin) { 65 | my.plugin = string(my.info.plugin) 66 | } 67 | var scrPasswd []byte 68 | switch my.plugin { 69 | case "caching_sha2_password": 70 | flags |= _CLIENT_PLUGIN_AUTH 71 | scrPasswd = encryptedSHA256Passwd(my.passwd, my.info.scramble[:]) 72 | case "mysql_old_password": 73 | my.oldPasswd() 74 | return 75 | default: 76 | // mysql_native_password by default 77 | scrPasswd = encryptedPasswd(my.passwd, my.info.scramble[:]) 78 | } 79 | 80 | // encode length of the auth plugin data 81 | var authRespLEIBuf [9]byte 82 | authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(len(scrPasswd))) 83 | if len(authRespLEI) > 1 { 84 | // if the length can not be written in 1 byte, it must be written as a 85 | // length encoded integer 86 | flags |= _CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA 87 | } 88 | 89 | pay_len := 4 + 4 + 1 + 23 + len(my.user) + 1 + len(authRespLEI) + len(scrPasswd) + 21 + 1 90 | 91 | if len(my.dbname) > 0 { 92 | pay_len += len(my.dbname) + 1 93 | flags |= _CLIENT_CONNECT_WITH_DB 94 | } 95 | pw := my.newPktWriter(pay_len) 96 | pw.writeU32(flags) 97 | pw.writeU32(uint32(my.max_pkt_size)) 98 | pw.writeByte(my.info.lang) // Charset number 99 | pw.writeZeros(23) // Filler 100 | pw.writeNTB([]byte(my.user)) // Username 101 | pw.writeBin(scrPasswd) // Encrypted password 102 | 103 | // write database name 104 | if len(my.dbname) > 0 { 105 | pw.writeNTB([]byte(my.dbname)) 106 | } 107 | 108 | // write plugin name 109 | if my.plugin != "" { 110 | pw.writeNTB([]byte(my.plugin)) 111 | } else { 112 | pw.writeNTB([]byte("mysql_native_password")) 113 | } 114 | return 115 | } 116 | 117 | func (my *Conn) authResponse() { 118 | // Read Result Packet 119 | authData, newPlugin := my.getAuthResult() 120 | 121 | // handle auth plugin switch, if requested 122 | if newPlugin != "" { 123 | var scrPasswd []byte 124 | if len(authData) >= 20 { 125 | // old_password's len(authData) == 0 126 | copy(my.info.scramble[:], authData[:20]) 127 | } 128 | my.info.plugin = []byte(newPlugin) 129 | my.plugin = newPlugin 130 | switch my.plugin { 131 | case "caching_sha2_password": 132 | scrPasswd = encryptedSHA256Passwd(my.passwd, my.info.scramble[:]) 133 | case "mysql_old_password": 134 | scrPasswd = encryptedOldPassword(my.passwd, my.info.scramble[:]) 135 | // append \0 after old_password 136 | scrPasswd = append(scrPasswd, 0) 137 | case "sha256_password": 138 | // request public key from server 139 | scrPasswd = []byte{1} 140 | default: // mysql_native_password 141 | scrPasswd = encryptedPasswd(my.passwd, my.info.scramble[:]) 142 | } 143 | my.writeAuthSwitchPacket(scrPasswd) 144 | 145 | // Read Result Packet 146 | authData, newPlugin = my.getAuthResult() 147 | 148 | // Do not allow to change the auth plugin more than once 149 | if newPlugin != "" { 150 | return 151 | } 152 | } 153 | 154 | switch my.plugin { 155 | 156 | // https://insidemysql.com/preparing-your-community-connector-for-mysql-8-part-2-sha256/ 157 | case "caching_sha2_password": 158 | switch len(authData) { 159 | case 0: 160 | return // auth successful 161 | case 1: 162 | switch authData[0] { 163 | case 3: // cachingSha2PasswordFastAuthSuccess 164 | my.getResult(nil, nil) 165 | 166 | case 4: // cachingSha2PasswordPerformFullAuthentication 167 | // request public key from server 168 | pw := my.newPktWriter(1) 169 | pw.writeByte(2) 170 | 171 | // parse public key 172 | pr := my.newPktReader() 173 | pr.skipN(1) 174 | data := pr.readAll() 175 | block, _ := pem.Decode(data) 176 | pkix, err := x509.ParsePKIXPublicKey(block.Bytes) 177 | if err != nil { 178 | panic(mysql.ErrAuthentication) 179 | } 180 | pubKey := pkix.(*rsa.PublicKey) 181 | 182 | // send encrypted password 183 | my.sendEncryptedPassword(my.info.scramble[:], pubKey) 184 | my.getResult(nil, nil) 185 | } 186 | } 187 | case "sha256_password": 188 | switch len(authData) { 189 | case 0: 190 | return // auth successful 191 | default: 192 | // parse public key 193 | block, _ := pem.Decode(authData) 194 | pub, err := x509.ParsePKIXPublicKey(block.Bytes) 195 | if err != nil { 196 | panic(mysql.ErrAuthentication) 197 | } 198 | 199 | // send encrypted password 200 | my.sendEncryptedPassword(my.info.scramble[:], pub.(*rsa.PublicKey)) 201 | my.getResult(nil, nil) 202 | } 203 | } 204 | return 205 | } 206 | 207 | // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse 208 | func (my *Conn) writeAuthSwitchPacket(scrPasswd []byte) { 209 | pw := my.newPktWriter(len(scrPasswd)) 210 | pw.write(scrPasswd) // Encrypted password 211 | return 212 | } 213 | 214 | func (my *Conn) sendEncryptedPassword(seed []byte, pub *rsa.PublicKey) { 215 | enc, err := encryptPassword(my.passwd, seed, pub) 216 | if err != nil { 217 | panic(mysql.ErrAuthentication) 218 | } 219 | my.writeAuthSwitchPacket(enc) 220 | } 221 | 222 | func encryptPassword(password string, seed []byte, pub *rsa.PublicKey) ([]byte, error) { 223 | plain := make([]byte, len(password)+1) 224 | copy(plain, password) 225 | for i := range plain { 226 | j := i % len(seed) 227 | plain[i] ^= seed[j] 228 | } 229 | sha1 := sha1.New() 230 | return rsa.EncryptOAEP(sha1, rand.Reader, pub, plain, nil) 231 | } 232 | 233 | func (my *Conn) oldPasswd() { 234 | if my.Debug { 235 | log.Printf("[%2d <-] Password packet", my.seq) 236 | } 237 | scrPasswd := encryptedOldPassword(my.passwd, my.info.scramble[:]) 238 | pw := my.newPktWriter(len(scrPasswd) + 1) 239 | pw.write(scrPasswd) 240 | pw.writeByte(0) 241 | } 242 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/type_fields.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | // Struct field handling is adapted from code in encoding/json: 4 | // 5 | // Copyright 2010 The Go Authors. All rights reserved. 6 | // Use of this source code is governed by a BSD-style 7 | // license that can be found in the Go distribution. 8 | 9 | import ( 10 | "reflect" 11 | "sort" 12 | "sync" 13 | ) 14 | 15 | // A field represents a single field found in a struct. 16 | type field struct { 17 | name string // the name of the field (`toml` tag included) 18 | tag bool // whether field has a `toml` tag 19 | index []int // represents the depth of an anonymous field 20 | typ reflect.Type // the type of the field 21 | } 22 | 23 | // byName sorts field by name, breaking ties with depth, 24 | // then breaking ties with "name came from toml tag", then 25 | // breaking ties with index sequence. 26 | type byName []field 27 | 28 | func (x byName) Len() int { return len(x) } 29 | 30 | func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 31 | 32 | func (x byName) Less(i, j int) bool { 33 | if x[i].name != x[j].name { 34 | return x[i].name < x[j].name 35 | } 36 | if len(x[i].index) != len(x[j].index) { 37 | return len(x[i].index) < len(x[j].index) 38 | } 39 | if x[i].tag != x[j].tag { 40 | return x[i].tag 41 | } 42 | return byIndex(x).Less(i, j) 43 | } 44 | 45 | // byIndex sorts field by index sequence. 46 | type byIndex []field 47 | 48 | func (x byIndex) Len() int { return len(x) } 49 | 50 | func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 51 | 52 | func (x byIndex) Less(i, j int) bool { 53 | for k, xik := range x[i].index { 54 | if k >= len(x[j].index) { 55 | return false 56 | } 57 | if xik != x[j].index[k] { 58 | return xik < x[j].index[k] 59 | } 60 | } 61 | return len(x[i].index) < len(x[j].index) 62 | } 63 | 64 | // typeFields returns a list of fields that TOML should recognize for the given 65 | // type. The algorithm is breadth-first search over the set of structs to 66 | // include - the top struct and then any reachable anonymous structs. 67 | func typeFields(t reflect.Type) []field { 68 | // Anonymous fields to explore at the current level and the next. 69 | current := []field{} 70 | next := []field{{typ: t}} 71 | 72 | // Count of queued names for current level and the next. 73 | count := map[reflect.Type]int{} 74 | nextCount := map[reflect.Type]int{} 75 | 76 | // Types already visited at an earlier level. 77 | visited := map[reflect.Type]bool{} 78 | 79 | // Fields found. 80 | var fields []field 81 | 82 | for len(next) > 0 { 83 | current, next = next, current[:0] 84 | count, nextCount = nextCount, map[reflect.Type]int{} 85 | 86 | for _, f := range current { 87 | if visited[f.typ] { 88 | continue 89 | } 90 | visited[f.typ] = true 91 | 92 | // Scan f.typ for fields to include. 93 | for i := 0; i < f.typ.NumField(); i++ { 94 | sf := f.typ.Field(i) 95 | if sf.PkgPath != "" && !sf.Anonymous { // unexported 96 | continue 97 | } 98 | opts := getOptions(sf.Tag) 99 | if opts.skip { 100 | continue 101 | } 102 | index := make([]int, len(f.index)+1) 103 | copy(index, f.index) 104 | index[len(f.index)] = i 105 | 106 | ft := sf.Type 107 | if ft.Name() == "" && ft.Kind() == reflect.Ptr { 108 | // Follow pointer. 109 | ft = ft.Elem() 110 | } 111 | 112 | // Record found field and index sequence. 113 | if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { 114 | tagged := opts.name != "" 115 | name := opts.name 116 | if name == "" { 117 | name = sf.Name 118 | } 119 | fields = append(fields, field{name, tagged, index, ft}) 120 | if count[f.typ] > 1 { 121 | // If there were multiple instances, add a second, 122 | // so that the annihilation code will see a duplicate. 123 | // It only cares about the distinction between 1 or 2, 124 | // so don't bother generating any more copies. 125 | fields = append(fields, fields[len(fields)-1]) 126 | } 127 | continue 128 | } 129 | 130 | // Record new anonymous struct to explore in next round. 131 | nextCount[ft]++ 132 | if nextCount[ft] == 1 { 133 | f := field{name: ft.Name(), index: index, typ: ft} 134 | next = append(next, f) 135 | } 136 | } 137 | } 138 | } 139 | 140 | sort.Sort(byName(fields)) 141 | 142 | // Delete all fields that are hidden by the Go rules for embedded fields, 143 | // except that fields with TOML tags are promoted. 144 | 145 | // The fields are sorted in primary order of name, secondary order 146 | // of field index length. Loop over names; for each name, delete 147 | // hidden fields by choosing the one dominant field that survives. 148 | out := fields[:0] 149 | for advance, i := 0, 0; i < len(fields); i += advance { 150 | // One iteration per name. 151 | // Find the sequence of fields with the name of this first field. 152 | fi := fields[i] 153 | name := fi.name 154 | for advance = 1; i+advance < len(fields); advance++ { 155 | fj := fields[i+advance] 156 | if fj.name != name { 157 | break 158 | } 159 | } 160 | if advance == 1 { // Only one field with this name 161 | out = append(out, fi) 162 | continue 163 | } 164 | dominant, ok := dominantField(fields[i : i+advance]) 165 | if ok { 166 | out = append(out, dominant) 167 | } 168 | } 169 | 170 | fields = out 171 | sort.Sort(byIndex(fields)) 172 | 173 | return fields 174 | } 175 | 176 | // dominantField looks through the fields, all of which are known to 177 | // have the same name, to find the single field that dominates the 178 | // others using Go's embedding rules, modified by the presence of 179 | // TOML tags. If there are multiple top-level fields, the boolean 180 | // will be false: This condition is an error in Go and we skip all 181 | // the fields. 182 | func dominantField(fields []field) (field, bool) { 183 | // The fields are sorted in increasing index-length order. The winner 184 | // must therefore be one with the shortest index length. Drop all 185 | // longer entries, which is easy: just truncate the slice. 186 | length := len(fields[0].index) 187 | tagged := -1 // Index of first tagged field. 188 | for i, f := range fields { 189 | if len(f.index) > length { 190 | fields = fields[:i] 191 | break 192 | } 193 | if f.tag { 194 | if tagged >= 0 { 195 | // Multiple tagged fields at the same level: conflict. 196 | // Return no field. 197 | return field{}, false 198 | } 199 | tagged = i 200 | } 201 | } 202 | if tagged >= 0 { 203 | return fields[tagged], true 204 | } 205 | // All remaining fields have the same length. If there's more than one, 206 | // we have a conflict (two fields named "X" at the same level) and we 207 | // return no field. 208 | if len(fields) > 1 { 209 | return field{}, false 210 | } 211 | return fields[0], true 212 | } 213 | 214 | var fieldCache struct { 215 | sync.RWMutex 216 | m map[reflect.Type][]field 217 | } 218 | 219 | // cachedTypeFields is like typeFields but uses a cache to avoid repeated work. 220 | func cachedTypeFields(t reflect.Type) []field { 221 | fieldCache.RLock() 222 | f := fieldCache.m[t] 223 | fieldCache.RUnlock() 224 | if f != nil { 225 | return f 226 | } 227 | 228 | // Compute fields without lock. 229 | // Might duplicate effort but won't hold other computations back. 230 | f = typeFields(t) 231 | if f == nil { 232 | f = []field{} 233 | } 234 | 235 | fieldCache.Lock() 236 | if fieldCache.m == nil { 237 | fieldCache.m = map[reflect.Type][]field{} 238 | } 239 | fieldCache.m[t] = f 240 | fieldCache.Unlock() 241 | return f 242 | } 243 | -------------------------------------------------------------------------------- /vendor/github.com/ziutek/mymysql/mysql/utils.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "os" 10 | "strings" 11 | "time" 12 | "unicode" 13 | ) 14 | 15 | // Version returns mymysql version string 16 | func Version() string { 17 | return "1.5.3" 18 | } 19 | 20 | func syntaxError(ln int) error { 21 | return fmt.Errorf("syntax error at line: %d", ln) 22 | } 23 | 24 | // Creates new conneection handler using configuration in cfgFile. Returns 25 | // connection handler and map contains unknown options. 26 | // 27 | // Config file format(example): 28 | // 29 | // # mymysql options (if some option isn't specified it defaults to "") 30 | // 31 | // DbRaddr 127.0.0.1:3306 32 | // # DbRaddr /var/run/mysqld/mysqld.sock 33 | // DbUser testuser 34 | // DbPass TestPasswd9 35 | // # optional: DbName test 36 | // # optional: DbEncd utf8 37 | // # optional: DbLaddr 127.0.0.1:0 38 | // # optional: DbTimeout 15s 39 | // 40 | // # Your options (returned in unk) 41 | // 42 | // MyOpt some text 43 | func NewFromCF(cfgFile string) (con Conn, unk map[string]string, err error) { 44 | var cf *os.File 45 | cf, err = os.Open(cfgFile) 46 | if err != nil { 47 | return 48 | } 49 | br := bufio.NewReader(cf) 50 | um := make(map[string]string) 51 | var proto, laddr, raddr, user, pass, name, encd, to string 52 | for i := 1; ; i++ { 53 | buf, isPrefix, e := br.ReadLine() 54 | if e != nil { 55 | if e == io.EOF { 56 | break 57 | } 58 | err = e 59 | return 60 | } 61 | l := string(buf) 62 | if isPrefix { 63 | err = fmt.Errorf("line %d is too long", i) 64 | return 65 | } 66 | l = strings.TrimFunc(l, unicode.IsSpace) 67 | if len(l) == 0 || l[0] == '#' { 68 | continue 69 | } 70 | n := strings.IndexFunc(l, unicode.IsSpace) 71 | if n == -1 { 72 | err = fmt.Errorf("syntax error at line: %d", i) 73 | return 74 | } 75 | v := l[:n] 76 | l = strings.TrimLeftFunc(l[n:], unicode.IsSpace) 77 | switch v { 78 | case "DbLaddr": 79 | laddr = l 80 | case "DbRaddr": 81 | raddr = l 82 | proto = "tcp" 83 | if strings.IndexRune(l, ':') == -1 { 84 | proto = "unix" 85 | } 86 | case "DbUser": 87 | user = l 88 | case "DbPass": 89 | pass = l 90 | case "DbName": 91 | name = l 92 | case "DbEncd": 93 | encd = l 94 | case "DbTimeout": 95 | to = l 96 | default: 97 | um[v] = l 98 | } 99 | } 100 | if raddr == "" { 101 | err = errors.New("DbRaddr option is empty") 102 | return 103 | } 104 | unk = um 105 | if name != "" { 106 | con = New(proto, laddr, raddr, user, pass, name) 107 | } else { 108 | con = New(proto, laddr, raddr, user, pass) 109 | } 110 | if encd != "" { 111 | con.Register(fmt.Sprintf("SET NAMES %s", encd)) 112 | } 113 | if to != "" { 114 | var timeout time.Duration 115 | timeout, err = time.ParseDuration(to) 116 | if err != nil { 117 | return 118 | } 119 | con.SetTimeout(timeout) 120 | } 121 | return 122 | } 123 | 124 | // Calls Start and next calls GetRow as long as it reads all rows from the 125 | // result. Next it returns all readed rows as the slice of rows. 126 | func Query(c Conn, sql string, params ...interface{}) (rows []Row, res Result, err error) { 127 | res, err = c.Start(sql, params...) 128 | if err != nil { 129 | return 130 | } 131 | rows, err = GetRows(res) 132 | return 133 | } 134 | 135 | // Calls Start and next calls GetFirstRow 136 | func QueryFirst(c Conn, sql string, params ...interface{}) (row Row, res Result, err error) { 137 | res, err = c.Start(sql, params...) 138 | if err != nil { 139 | return 140 | } 141 | row, err = GetFirstRow(res) 142 | return 143 | } 144 | 145 | // Calls Start and next calls GetLastRow 146 | func QueryLast(c Conn, sql string, params ...interface{}) (row Row, res Result, err error) { 147 | res, err = c.Start(sql, params...) 148 | if err != nil { 149 | return 150 | } 151 | row, err = GetLastRow(res) 152 | return 153 | } 154 | 155 | // Calls Run and next call GetRow as long as it reads all rows from the 156 | // result. Next it returns all readed rows as the slice of rows. 157 | func Exec(s Stmt, params ...interface{}) (rows []Row, res Result, err error) { 158 | res, err = s.Run(params...) 159 | if err != nil { 160 | return 161 | } 162 | rows, err = GetRows(res) 163 | return 164 | } 165 | 166 | // Calls Run and next call GetFirstRow 167 | func ExecFirst(s Stmt, params ...interface{}) (row Row, res Result, err error) { 168 | res, err = s.Run(params...) 169 | if err != nil { 170 | return 171 | } 172 | row, err = GetFirstRow(res) 173 | return 174 | } 175 | 176 | // Calls Run and next call GetLastRow 177 | func ExecLast(s Stmt, params ...interface{}) (row Row, res Result, err error) { 178 | res, err = s.Run(params...) 179 | if err != nil { 180 | return 181 | } 182 | row, err = GetLastRow(res) 183 | return 184 | } 185 | 186 | // Calls r.MakeRow and next r.ScanRow. Doesn't return io.EOF error (returns nil 187 | // row insted). 188 | func GetRow(r Result) (Row, error) { 189 | row := r.MakeRow() 190 | err := r.ScanRow(row) 191 | if err != nil { 192 | if err == io.EOF { 193 | return nil, nil 194 | } 195 | return nil, err 196 | } 197 | return row, nil 198 | } 199 | 200 | // Reads all rows from result and returns them as slice. 201 | func GetRows(r Result) (rows []Row, err error) { 202 | var row Row 203 | for { 204 | row, err = r.GetRow() 205 | if err != nil || row == nil { 206 | break 207 | } 208 | rows = append(rows, row) 209 | } 210 | return 211 | } 212 | 213 | // Returns last row and discard others 214 | func GetLastRow(r Result) (Row, error) { 215 | row := r.MakeRow() 216 | err := r.ScanRow(row) 217 | if err == io.EOF { 218 | return nil, nil 219 | } 220 | for err == nil { 221 | err = r.ScanRow(row) 222 | } 223 | if err == io.EOF { 224 | return row, nil 225 | } 226 | return nil, err 227 | } 228 | 229 | // Read all unreaded rows and discard them. This function is useful if you 230 | // don't want to use the remaining rows. It has an impact only on current 231 | // result. If there is multi result query, you must use NextResult method and 232 | // read/discard all rows in this result, before use other method that sends 233 | // data to the server. You can't use this function if last GetRow returned nil. 234 | func End(r Result) error { 235 | _, err := GetLastRow(r) 236 | return err 237 | } 238 | 239 | // Returns first row and discard others 240 | func GetFirstRow(r Result) (row Row, err error) { 241 | row, err = r.GetRow() 242 | if err == nil && row != nil { 243 | err = r.End() 244 | } 245 | return 246 | } 247 | 248 | func escapeString(txt string) string { 249 | var ( 250 | esc string 251 | buf bytes.Buffer 252 | ) 253 | last := 0 254 | for ii, bb := range txt { 255 | switch bb { 256 | case 0: 257 | esc = `\0` 258 | case '\n': 259 | esc = `\n` 260 | case '\r': 261 | esc = `\r` 262 | case '\\': 263 | esc = `\\` 264 | case '\'': 265 | esc = `\'` 266 | case '"': 267 | esc = `\"` 268 | case '\032': 269 | esc = `\Z` 270 | default: 271 | continue 272 | } 273 | io.WriteString(&buf, txt[last:ii]) 274 | io.WriteString(&buf, esc) 275 | last = ii + 1 276 | } 277 | io.WriteString(&buf, txt[last:]) 278 | return buf.String() 279 | } 280 | 281 | func escapeQuotes(txt string) string { 282 | var buf bytes.Buffer 283 | last := 0 284 | for ii, bb := range txt { 285 | if bb == '\'' { 286 | io.WriteString(&buf, txt[last:ii]) 287 | io.WriteString(&buf, `''`) 288 | last = ii + 1 289 | } 290 | } 291 | io.WriteString(&buf, txt[last:]) 292 | return buf.String() 293 | } 294 | 295 | // Escapes special characters in the txt, so it is safe to place returned string 296 | // to Query method. 297 | func Escape(c Conn, txt string) string { 298 | if c.Status()&SERVER_STATUS_NO_BACKSLASH_ESCAPES != 0 { 299 | return escapeQuotes(txt) 300 | } 301 | return escapeString(txt) 302 | } 303 | --------------------------------------------------------------------------------