Repository: open-falcon/falcon-plus
Branch: master
Commit: 93491806585f
Files: 560
Total size: 2.2 MB
Directory structure:
gitextract_lxxa1vqu/
├── .dockerignore
├── .gitignore
├── .travis.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── Dockerfile.module
├── Dockerfile_arm64
├── LICENSE
├── Makefile
├── NOTICE
├── README.md
├── VERSION
├── api-standard.md
├── cmd/
│ ├── check.go
│ ├── monitor.go
│ ├── reload.go
│ ├── restart.go
│ ├── start.go
│ └── stop.go
├── common/
│ ├── .gitignore
│ ├── LICENSE
│ ├── NOTICE
│ ├── backend_pool/
│ │ ├── rpc_backends.go
│ │ └── tsdb_backends.go
│ ├── db/
│ │ └── db.go
│ ├── model/
│ │ ├── agent.go
│ │ ├── event.go
│ │ ├── expression.go
│ │ ├── graph.go
│ │ ├── host.go
│ │ ├── influxdb.go
│ │ ├── judge.go
│ │ ├── metric.go
│ │ ├── nodata.go
│ │ ├── prometheus.go
│ │ ├── rpc.go
│ │ ├── strategy.go
│ │ ├── template.go
│ │ ├── transfer.go
│ │ └── tsdb.go
│ ├── proc/
│ │ └── proc.go
│ ├── sdk/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── requests/
│ │ │ ├── auth_request.go
│ │ │ └── post.go
│ │ └── sender/
│ │ ├── linkedlist.go
│ │ ├── make.go
│ │ ├── push.go
│ │ └── sender.go
│ └── utils/
│ ├── counter.go
│ ├── date.go
│ ├── formatter.go
│ ├── func.go
│ ├── func_test.go
│ ├── map.go
│ ├── md5.go
│ ├── md5_test.go
│ ├── objpool.go
│ ├── statistics.go
│ ├── tags.go
│ └── tags_test.go
├── config/
│ ├── agent.json
│ ├── aggregator.json
│ ├── alarm.json
│ ├── api.json
│ ├── confgen.sh
│ ├── falcon2p8s.json
│ ├── gateway.json
│ ├── graph.json
│ ├── hbs.json
│ ├── judge.json
│ ├── nodata.json
│ └── transfer.json
├── docker/
│ ├── README.md
│ ├── confgen4docker.sh
│ ├── ctrl.sh
│ ├── k8s-cluster/
│ │ ├── Dockerfile.tpl
│ │ ├── README.md
│ │ ├── build.sh
│ │ ├── init.sh
│ │ └── modules/
│ │ ├── falcon-agent.yaml
│ │ ├── falcon-aggregator.yaml
│ │ ├── falcon-alarm.yaml
│ │ ├── falcon-api.yaml
│ │ ├── falcon-dashboard.yaml
│ │ ├── falcon-graph-01.yaml
│ │ ├── falcon-hbs.yaml
│ │ ├── falcon-judge.yaml
│ │ ├── falcon-nodata.yaml
│ │ └── falcon-transfer.yaml
│ ├── k8s-example/
│ │ ├── README.md
│ │ ├── init_mysql_data.sh
│ │ ├── mysql.yaml
│ │ ├── openfalcon-dashboard.yaml
│ │ ├── openfalcon-plus.yaml
│ │ └── redis.yaml
│ ├── mysql-init/
│ │ ├── Dockerfile
│ │ └── init_mysql_data.sh
│ └── supervisord.conf
├── docker-compose.yml
├── docker_test.sh
├── docs/
│ ├── LICENSE.md
│ ├── Makefile
│ ├── README.md
│ ├── _config.yml
│ ├── _includes/
│ │ └── nav.html
│ ├── _layouts/
│ │ └── default.html
│ ├── _posts/
│ │ ├── 2017-01-01-authentication.md
│ │ ├── 2017-01-01-response-status-codes.md
│ │ ├── Admin/
│ │ │ ├── 2017-01-01-admin_change_role.md
│ │ │ ├── 2017-01-01-admin_change_user_passwd.md
│ │ │ ├── 2017-01-01-admin_delete_user.md
│ │ │ └── 2017-12-07-admin_login.md
│ │ ├── Aggregator/
│ │ │ ├── 2017-01-01-aggreator_create.md
│ │ │ ├── 2017-01-01-aggreator_delete.md
│ │ │ ├── 2017-01-01-aggreator_of_hostgroup.md
│ │ │ ├── 2017-01-01-aggreator_update.md
│ │ │ └── 2017-01-01-get_aggreator_by_id.md
│ │ ├── Alarm/
│ │ │ ├── 2017-01-01-alarm_eventcases_get_by_id.md
│ │ │ ├── 2017-01-01-alarm_eventcases_list.md
│ │ │ ├── 2017-01-01-alarm_eventnote_create.md
│ │ │ ├── 2017-01-01-alarm_eventnote_get.md
│ │ │ └── 2017-01-01-alarm_events_create.md
│ │ ├── DashboardGraph/
│ │ │ ├── 2017-01-01-dashboard_graph_create.md
│ │ │ ├── 2017-01-01-dashboard_graph_create_tmpgraph.md
│ │ │ ├── 2017-01-01-dashboard_graph_delete.md
│ │ │ ├── 2017-01-01-dashboard_graph_get.md
│ │ │ ├── 2017-01-01-dashboard_graph_get_tmpgraph_by_id.md
│ │ │ ├── 2017-01-01-dashboard_graph_update.md
│ │ │ └── 2017-01-01-dashboard_graphs_gets_by_screenid.md
│ │ ├── DashboardScreen/
│ │ │ ├── 2017-01-01-dashboard_screen_create.md
│ │ │ ├── 2017-01-01-dashboard_screen_delete.md
│ │ │ ├── 2017-01-01-dashboard_screen_get_by_id.md
│ │ │ ├── 2017-01-01-dashboard_screen_gets_all.md
│ │ │ ├── 2017-01-01-dashboard_screen_gets_by_pid.md
│ │ │ └── 2017-01-01-dashboard_screen_update.md
│ │ ├── Expression/
│ │ │ ├── 2017-01-01-expression_create.md
│ │ │ ├── 2017-01-01-expression_delete.md
│ │ │ ├── 2017-01-01-expression_info_by_id.md
│ │ │ ├── 2017-01-01-expression_list.md
│ │ │ └── 2017-01-01-expression_update.md
│ │ ├── Graph/
│ │ │ ├── 2017-01-01-endpoint_counter.md
│ │ │ ├── 2017-01-01-endpoints.md
│ │ │ ├── 2017-01-01-grafana.md
│ │ │ └── 2017-01-01-graph_histroy.md
│ │ ├── Host/
│ │ │ ├── 2017-01-01-host_maintain.md
│ │ │ ├── 2017-01-01-host_related_hostgroup.md
│ │ │ ├── 2017-01-01-host_related_template.md
│ │ │ └── 2017-01-01-host_reset.md
│ │ ├── HostGroup/
│ │ │ ├── 2017-01-01-hostgroup_add_host.md
│ │ │ ├── 2017-01-01-hostgroup_create.md
│ │ │ ├── 2017-01-01-hostgroup_delete.md
│ │ │ ├── 2017-01-01-hostgroup_get_info_by_id.md
│ │ │ ├── 2017-01-01-hostgroup_list.md
│ │ │ ├── 2017-01-01-hostgroup_template_bind.md
│ │ │ ├── 2017-01-01-hostgroup_template_list.md
│ │ │ ├── 2017-01-01-hostgroup_template_unbind.md
│ │ │ ├── 2017-01-01-hostgroup_unbind_host.md
│ │ │ ├── 2017-01-01-hostgroup_update.md
│ │ │ └── 2017-08-22-hostgroup_update_partial_hosts.md
│ │ ├── NoData/
│ │ │ ├── 2017-01-01-nodata_create.md
│ │ │ ├── 2017-01-01-nodata_delete.md
│ │ │ ├── 2017-01-01-nodata_info_by_id.md
│ │ │ ├── 2017-01-01-nodata_list.md
│ │ │ └── 2017-01-01-nodata_update.md
│ │ ├── Plugin/
│ │ │ ├── 2017-01-01-plugin_create.md
│ │ │ ├── 2017-01-01-plugin_delete.md
│ │ │ └── 2017-01-01-plugin_info_by_id.md
│ │ ├── Strategy/
│ │ │ ├── 2017-01-01-metric_tmplist.md
│ │ │ ├── 2017-01-01-strategy_create.md
│ │ │ ├── 2017-01-01-strategy_delete.md
│ │ │ ├── 2017-01-01-strategy_info_by_id.md
│ │ │ ├── 2017-01-01-strategy_list.md
│ │ │ └── 2017-01-01-strategy_update.md
│ │ ├── Team/
│ │ │ ├── 2017-01-01-team_create.md
│ │ │ ├── 2017-01-01-team_delete_by_id.md
│ │ │ ├── 2017-01-01-team_info_by_id.md
│ │ │ ├── 2017-01-01-team_info_by_name.md
│ │ │ ├── 2017-01-01-team_list.md
│ │ │ ├── 2017-01-01-team_update.md
│ │ │ └── 2018-11-19-add-user-to-team.md
│ │ ├── Template/
│ │ │ ├── 2017-01-01-tpl_action_create.md
│ │ │ ├── 2017-01-01-tpl_action_update.md
│ │ │ ├── 2017-01-01-tpl_create.md
│ │ │ ├── 2017-01-01-tpl_delete.md
│ │ │ ├── 2017-01-01-tpl_hgp_list.md
│ │ │ ├── 2017-01-01-tpl_info_by_id.md
│ │ │ ├── 2017-01-01-tpl_list.md
│ │ │ └── 2017-01-01-tpl_update.md
│ │ └── User/
│ │ ├── 2017-01-01-user_change_password.md
│ │ ├── 2017-01-01-user_create.md
│ │ ├── 2017-01-01-user_current.md
│ │ ├── 2017-01-01-user_get_info_by_id.md
│ │ ├── 2017-01-01-user_get_info_by_name.md
│ │ ├── 2017-01-01-user_get_teams.md
│ │ ├── 2017-01-01-user_is_in_teams.md
│ │ ├── 2017-01-01-user_list.md
│ │ ├── 2017-01-01-user_login.md
│ │ ├── 2017-01-01-user_logout.md
│ │ ├── 2017-01-01-user_update.md
│ │ └── 2019-04-14-update-specific-user.md
│ ├── assets.css
│ ├── assets.js
│ ├── doc/
│ │ ├── admin.html
│ │ ├── admin.html.json
│ │ ├── aggregator.html
│ │ ├── aggregator.html.json
│ │ ├── alarm.html
│ │ ├── alarm.html.json
│ │ ├── expression.html
│ │ ├── expression.html.json
│ │ ├── graph.html
│ │ ├── graph.html.json
│ │ ├── host.html
│ │ ├── host.html.json
│ │ ├── hostgroup.html
│ │ ├── hostgroup.html.json
│ │ ├── nodata.html
│ │ ├── nodata.html.json
│ │ ├── plugin.html
│ │ ├── plugin.html.json
│ │ ├── team.html
│ │ ├── team.html.json
│ │ ├── template.html
│ │ ├── template.html.json
│ │ ├── user.html
│ │ └── user.html.json
│ ├── index.html
│ └── robots.txt
├── g/
│ ├── g.go
│ ├── tool.go
│ └── tool_test.go
├── go.mod
├── go.sum
├── main.go
├── modules/
│ ├── agent/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── README.md
│ │ ├── cfg.example.json
│ │ ├── control
│ │ ├── cron/
│ │ │ ├── builtin.go
│ │ │ ├── collector.go
│ │ │ ├── ips.go
│ │ │ ├── plugin.go
│ │ │ └── reporter.go
│ │ ├── funcs/
│ │ │ ├── agent.go
│ │ │ ├── checker.go
│ │ │ ├── common.go
│ │ │ ├── cpustat.go
│ │ │ ├── dfstat.go
│ │ │ ├── diskstats.go
│ │ │ ├── du.go
│ │ │ ├── du_test.go
│ │ │ ├── funcs.go
│ │ │ ├── gpu.go
│ │ │ ├── ifstat.go
│ │ │ ├── kernel.go
│ │ │ ├── loadavg.go
│ │ │ ├── meminfo.go
│ │ │ ├── netstat.go
│ │ │ ├── portstat.go
│ │ │ ├── procs.go
│ │ │ ├── snmp.go
│ │ │ ├── sockstat.go
│ │ │ └── urlstat.go
│ │ ├── g/
│ │ │ ├── cfg.go
│ │ │ ├── const.go
│ │ │ ├── g.go
│ │ │ ├── logger.go
│ │ │ ├── rpc.go
│ │ │ ├── tool.go
│ │ │ ├── transfer.go
│ │ │ ├── var.go
│ │ │ └── var_test.go
│ │ ├── http/
│ │ │ ├── admin.go
│ │ │ ├── cpu.go
│ │ │ ├── df.go
│ │ │ ├── health.go
│ │ │ ├── http.go
│ │ │ ├── iostat.go
│ │ │ ├── kernel.go
│ │ │ ├── memory.go
│ │ │ ├── page.go
│ │ │ ├── plugin.go
│ │ │ ├── push.go
│ │ │ ├── run.go
│ │ │ └── system.go
│ │ ├── main.go
│ │ ├── plugins/
│ │ │ ├── plugins.go
│ │ │ ├── reader.go
│ │ │ └── scheduler.go
│ │ ├── public/
│ │ │ ├── css/
│ │ │ │ ├── font-awesome/
│ │ │ │ │ ├── css/
│ │ │ │ │ │ └── archive/
│ │ │ │ │ │ ├── font-awesome-ie7.css
│ │ │ │ │ │ └── font-awesome.css
│ │ │ │ │ └── font/
│ │ │ │ │ └── FontAwesome.otf
│ │ │ │ ├── g.css
│ │ │ │ ├── odometer.css
│ │ │ │ ├── pages/
│ │ │ │ │ └── dashboard.css
│ │ │ │ └── style.css
│ │ │ ├── index.html
│ │ │ └── js/
│ │ │ ├── base.js
│ │ │ ├── bootstrap.js
│ │ │ ├── dashboard.js
│ │ │ ├── jquery.js
│ │ │ └── odometer.js
│ │ └── version.go
│ ├── aggregator/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── cfg.example.json
│ │ ├── control
│ │ ├── cron/
│ │ │ ├── computer.go
│ │ │ ├── query.go
│ │ │ ├── run.go
│ │ │ ├── run_test.go
│ │ │ ├── updater.go
│ │ │ └── worker.go
│ │ ├── db/
│ │ │ ├── db.go
│ │ │ └── reader.go
│ │ ├── g/
│ │ │ ├── cfg.go
│ │ │ ├── g.go
│ │ │ └── items.go
│ │ ├── http/
│ │ │ ├── common.go
│ │ │ ├── http.go
│ │ │ └── proc.go
│ │ ├── main.go
│ │ ├── sdk/
│ │ │ ├── sdk.go
│ │ │ └── sdk_test.go
│ │ └── version.go
│ ├── alarm/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── README.md
│ │ ├── api/
│ │ │ ├── links.go
│ │ │ ├── portal.go
│ │ │ ├── portal_test.go
│ │ │ ├── uic.go
│ │ │ └── uic_test.go
│ │ ├── cfg.example.json
│ │ ├── control
│ │ ├── cron/
│ │ │ ├── builder.go
│ │ │ ├── callback.go
│ │ │ ├── combiner.go
│ │ │ ├── event_cleaner.go
│ │ │ ├── event_consumer.go
│ │ │ ├── event_reader.go
│ │ │ ├── im_sender.go
│ │ │ ├── init_sender.go
│ │ │ ├── mail_sender.go
│ │ │ ├── model.go
│ │ │ └── sms_sender.go
│ │ ├── g/
│ │ │ ├── cfg.go
│ │ │ ├── eventdto.go
│ │ │ ├── g.go
│ │ │ ├── logger.go
│ │ │ └── redis.go
│ │ ├── gitversion
│ │ ├── http/
│ │ │ ├── controller.go
│ │ │ └── http.go
│ │ ├── main.go
│ │ ├── model/
│ │ │ ├── database.go
│ │ │ ├── event/
│ │ │ │ ├── event.go
│ │ │ │ └── event_operation.go
│ │ │ ├── im.go
│ │ │ ├── mail.go
│ │ │ └── sms.go
│ │ ├── redi/
│ │ │ ├── msg_reader.go
│ │ │ └── msg_writer.go
│ │ └── version.go
│ ├── falcon2p8s/
│ │ ├── .gitignore
│ │ ├── ReadMe.md
│ │ ├── cfg.example.json
│ │ ├── control
│ │ ├── g/
│ │ │ ├── cfg.go
│ │ │ ├── const.go
│ │ │ ├── g.go
│ │ │ ├── logger.go
│ │ │ └── var.go
│ │ ├── http/
│ │ │ ├── common.go
│ │ │ ├── cron.go
│ │ │ ├── helper.go
│ │ │ └── http.go
│ │ ├── main.go
│ │ ├── middlewares/
│ │ │ └── scraping.go
│ │ ├── rpc/
│ │ │ ├── model.go
│ │ │ ├── receiver.go
│ │ │ └── rpc.go
│ │ ├── sm.example.yaml
│ │ ├── utils/
│ │ │ └── func.go
│ │ └── version.go
│ ├── gateway/
│ │ └── README.md
│ ├── graph/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── README.md
│ │ ├── api/
│ │ │ ├── graph.go
│ │ │ └── rpc.go
│ │ ├── cfg.example.json
│ │ ├── control
│ │ ├── cron/
│ │ │ └── clean.go
│ │ ├── doc/
│ │ │ └── README.md
│ │ ├── g/
│ │ │ ├── cfg.go
│ │ │ ├── db.go
│ │ │ ├── g.go
│ │ │ ├── git.go
│ │ │ ├── logger.go
│ │ │ ├── utils.go
│ │ │ └── utils_test.go
│ │ ├── http/
│ │ │ ├── common.go
│ │ │ ├── helper.go
│ │ │ ├── http.go
│ │ │ ├── index.go
│ │ │ └── proc.go
│ │ ├── index/
│ │ │ ├── cache.go
│ │ │ ├── index.go
│ │ │ ├── index_update_all_task.go
│ │ │ └── index_update_incr_task.go
│ │ ├── main.go
│ │ ├── proc/
│ │ │ └── proc.go
│ │ ├── rrdtool/
│ │ │ ├── migrate.go
│ │ │ ├── rrdtool.go
│ │ │ ├── sync_disk.go
│ │ │ └── utils.go
│ │ ├── store/
│ │ │ ├── history.go
│ │ │ ├── linkedlist.go
│ │ │ └── store.go
│ │ ├── test/
│ │ │ ├── debug
│ │ │ ├── graph.list
│ │ │ └── http.recv.history
│ │ └── version.go
│ ├── hbs/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── README.md
│ │ ├── cache/
│ │ │ ├── agents.go
│ │ │ ├── cache.go
│ │ │ ├── expressions.go
│ │ │ ├── groups.go
│ │ │ ├── hosts.go
│ │ │ ├── plugins.go
│ │ │ ├── strategies.go
│ │ │ └── templates.go
│ │ ├── cfg.example.json
│ │ ├── control
│ │ ├── db/
│ │ │ ├── agent.go
│ │ │ ├── db.go
│ │ │ ├── expression.go
│ │ │ ├── group.go
│ │ │ ├── host.go
│ │ │ ├── plugin.go
│ │ │ ├── strategy.go
│ │ │ └── template.go
│ │ ├── g/
│ │ │ ├── cfg.go
│ │ │ └── g.go
│ │ ├── http/
│ │ │ ├── common.go
│ │ │ ├── http.go
│ │ │ └── proc.go
│ │ ├── main.go
│ │ ├── rpc/
│ │ │ ├── agent.go
│ │ │ ├── hbs.go
│ │ │ └── rpc.go
│ │ └── version.go
│ ├── judge/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── README.md
│ │ ├── cfg.example.json
│ │ ├── control
│ │ ├── cron/
│ │ │ ├── cleaner.go
│ │ │ └── strategy.go
│ │ ├── g/
│ │ │ ├── cfg.go
│ │ │ ├── g.go
│ │ │ ├── redis.go
│ │ │ ├── rpc.go
│ │ │ └── var.go
│ │ ├── http/
│ │ │ ├── common.go
│ │ │ ├── http.go
│ │ │ └── info.go
│ │ ├── main.go
│ │ ├── rpc/
│ │ │ ├── receiver.go
│ │ │ └── rpc.go
│ │ ├── store/
│ │ │ ├── func.go
│ │ │ ├── history.go
│ │ │ ├── judge.go
│ │ │ └── linkedlist.go
│ │ └── version.go
│ ├── nodata/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── cfg.example.json
│ │ ├── collector/
│ │ │ ├── collector.go
│ │ │ └── collector_cron.go
│ │ ├── config/
│ │ │ ├── config.go
│ │ │ ├── config_cron.go
│ │ │ └── service/
│ │ │ ├── db.go
│ │ │ ├── host.go
│ │ │ └── mockcfg.go
│ │ ├── control
│ │ ├── g/
│ │ │ ├── cfg.go
│ │ │ ├── g.go
│ │ │ ├── git.go
│ │ │ └── proc.go
│ │ ├── http/
│ │ │ ├── common.go
│ │ │ ├── debug_http.go
│ │ │ ├── http.go
│ │ │ └── proc_http.go
│ │ ├── judge/
│ │ │ ├── judge.go
│ │ │ ├── judge_cron.go
│ │ │ └── status.go
│ │ ├── main.go
│ │ ├── scripts/
│ │ │ ├── debug
│ │ │ └── nodata-db-schema.sql
│ │ ├── sender/
│ │ │ └── sender.go
│ │ └── version.go
│ └── transfer/
│ ├── .gitignore
│ ├── LICENSE
│ ├── NOTICE
│ ├── README.md
│ ├── cfg.example.json
│ ├── control
│ ├── g/
│ │ ├── cfg.go
│ │ ├── g.go
│ │ └── git.go
│ ├── http/
│ │ ├── api.go
│ │ ├── common.go
│ │ ├── debug_http.go
│ │ ├── http.go
│ │ └── proc_http.go
│ ├── main.go
│ ├── proc/
│ │ └── proc.go
│ ├── receiver/
│ │ ├── receiver.go
│ │ ├── rpc/
│ │ │ ├── rpc.go
│ │ │ └── rpc_transfer.go
│ │ └── socket/
│ │ ├── socket.go
│ │ └── socket_telnet.go
│ ├── scripts/
│ │ ├── info
│ │ ├── info.py
│ │ ├── last
│ │ ├── last_raw
│ │ ├── query
│ │ └── query.py
│ ├── sender/
│ │ ├── conn_pools.go
│ │ ├── node_rings.go
│ │ ├── send_queues.go
│ │ ├── send_tasks.go
│ │ ├── sender.go
│ │ └── sender_cron.go
│ ├── test/
│ │ ├── debug
│ │ └── rpcclient.py
│ └── version.go
├── scripts/
│ └── mysql/
│ ├── .gitignore
│ ├── LICENSE
│ ├── NOTICE
│ └── db_schema/
│ ├── 1_uic-db-schema.sql
│ ├── 2_portal-db-schema.sql
│ ├── 3_dashboard-db-schema.sql
│ ├── 4_graph-db-schema.sql
│ └── 5_alarms-db-schema.sql
├── test/
│ └── README.md
├── vagrant/
│ └── Vagrantfile
└── version.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
docs/
outrun/
tmp/
bin/
*.tar.gz
open-falcon
================================================
FILE: .gitignore
================================================
bin/
out/
*.swp
*.swo
*.tar.gz
docs/_site
.idea
open-falcon
build
================================================
FILE: .travis.yml
================================================
sudo: required
language: go
arch:
- amd64
- arm64
go:
- "1.15"
env:
- DB_USER=root DB_PASSWORD=test123456 DB_HOST=127.0.0.1 DB_PORT=13306 REDIS_HOST=127.0.0.1 REDIS_PORT=16379 API_PORT=18080 API_HOST=127.0.0.1
services:
- docker
before_install:
- tmpdaemon=$(mktemp)
- sudo jq '."registry-mirrors" += ["https://mirror.gcr.io"]' /etc/docker/daemon.json > $tmpdaemon
- sudo mv $tmpdaemon /etc/docker/daemon.json
- sudo systemctl daemon-reload
- sudo systemctl restart docker
- docker system info
script:
- go get -u github.com/go-sql-driver/mysql
- make fmt
- make fmt-check
- make misspell-check
- make all
- bash ./docker_test.sh
after_success:
- go test -race -coverprofile=coverage.txt -covermode=atomic github.com/open-falcon/falcon-plus/modules/api/test
- bash <(curl -s https://codecov.io/bash)
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct
## 1. Purpose
A primary goal of Open-Falcon is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof).
This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior.
We invite all those who participate in Open-Falcon to help us create safe and positive experiences for everyone.
## 2. Open Source Citizenship
A supplemental goal of this Code of Conduct is to increase open source citizenship by encouraging participants to recognize and strengthen the relationships between our actions and their effects on our community.
Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society.
If you see someone who is making an extra effort to ensure our community is welcoming, friendly, and encourages all participants to contribute to the fullest extent, we want to know.
## 3. Expected Behavior
The following behaviors are expected and requested of all community members:
* Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community.
* Exercise consideration and respect in your speech and actions.
* Attempt collaboration before conflict.
* Refrain from demeaning, discriminatory, or harassing behavior and speech.
* Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential.
* Remember that community event venues may be shared with members of the public; please be respectful to all patrons of these locations.
## 4. Unacceptable Behavior
The following behaviors are considered harassment and are unacceptable within our community:
* Violence, threats of violence or violent language directed against another person.
* Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language.
* Posting or displaying sexually explicit or violent material.
* Posting or threatening to post other people’s personally identifying information ("doxing").
* Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability.
* Inappropriate photography or recording.
* Inappropriate physical contact. You should have someone’s consent before touching them.
* Unwelcome sexual attention. This includes, sexualized comments or jokes; inappropriate touching, groping, and unwelcomed sexual advances.
* Deliberate intimidation, stalking or following (online or in person).
* Advocating for, or encouraging, any of the above behavior.
* Sustained disruption of community events, including talks and presentations.
## 5. Consequences of Unacceptable Behavior
Unacceptable behavior from any community member, including sponsors and those with decision-making authority, will not be tolerated.
Anyone asked to stop unacceptable behavior is expected to comply immediately.
If a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning (and without refund in the case of a paid event).
## 6. Reporting Guidelines
If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible. root@open-falcon.com.
Additionally, community organizers are available to help community members engage with local law enforcement or to otherwise help those experiencing unacceptable behavior feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress.
## 7. Addressing Grievances
If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify Open Falcon with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies.
## 8. Scope
We expect all community participants (contributors, paid or otherwise; sponsors; and other guests) to abide by this Code of Conduct in all community venues–online and in-person–as well as in all one-on-one communications pertaining to community business.
This code of conduct and its related procedures also applies to unacceptable behavior occurring outside the scope of community activities when such behavior has the potential to adversely affect the safety and well-being of community members.
## 9. Contact info
root@open-falcon.com
## 10. License and attribution
This Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/).
Portions of text derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/) and the [Geek Feminism Anti-Harassment Policy](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy).
Retrieved on November 22, 2016 from [http://citizencodeofconduct.org/](http://citizencodeofconduct.org/)
================================================
FILE: CONTRIBUTING.md
================================================
### COMMUNITY
Open-Falcon is developed in the open. Here are some of the channels we use to communicate and contribute:
**Mailing lists:**
- [openfalcon-users](https://groups.google.com/forum/#!forum/openfalcon-users) – for discussions around openfalcon usage and community support
- [openfalcon-developers](https://groups.google.com/forum/#!forum/openfalcon-developers) – for discussions around openfalcon development
**Issue tracker:**
- Use the GitHub issue tracker for the various [Open-Falcon repositories](http://github.com/open-falcon) to file bugs and features request. If you need support, please send your questions to the [openfalcon-users](https://groups.google.com/forum/#!forum/openfalcon-users) mailing list rather than filing a GitHub issue.
*Please do not ask individual project members for support. Use the channels above instead, where the whole community can help you and benefit from the solutions provided. If community support is insufficient for your situation, please refer to the Commercial Support section below.*
### CONTRIBUTING
We welcome community contributions! Open-Falcon uses GitHub to manage reviews of pull requests.
- If you have a trivial fix or improvement, go ahead and create a pull request, addressing (with `@...`) the maintainer of this repository in the description of the pull request.
- If you plan to do something more involved, first discuss your ideas on our [mailing list](https://groups.google.com/forum/#!forum/openfalcon-developers). This will avoid unnecessary work and surely give you and us a good deal of inspiration.
================================================
FILE: Dockerfile
================================================
# Build container;
FROM openfalcon/makegcc-golang:1.15-alpine
LABEL maintainer laiwei.ustc@gmail.com
USER root
ENV FALCON_DIR=/open-falcon PROJ_PATH=${GOPATH}/src/github.com/open-falcon/falcon-plus
RUN mkdir -p $FALCON_DIR && \
mkdir -p $FALCON_DIR/logs && \
apk add --no-cache ca-certificates bash git supervisor
COPY . ${PROJ_PATH}
WORKDIR ${PROJ_PATH}
RUN make all \
&& make pack4docker \
&& tar -zxf open-falcon-v*.tar.gz -C ${FALCON_DIR} \
&& rm -rf ${PROJ_PATH}
# Final container;
FROM alpine:3.13
LABEL maintainer laiwei.ustc@gmail.com
USER root
ENV FALCON_DIR=/open-falcon
RUN mkdir -p $FALCON_DIR/logs && \
apk add --no-cache ca-certificates bash git supervisor
ADD docker/supervisord.conf /etc/supervisord.conf
COPY --from=0 ${FALCON_DIR} ${FALCON_DIR}
EXPOSE 8433 8080
WORKDIR ${FALCON_DIR}
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
================================================
FILE: Dockerfile.module
================================================
# Build container;
FROM openfalcon/makegcc-golang:1.15-alpine
LABEL maintainer laiwei.ustc@gmail.com
USER root
ENV FALCON_DIR=/open-falcon PROJ_PATH=${GOPATH}/src/github.com/open-falcon/falcon-plus
RUN mkdir -p $FALCON_DIR && \
apk add --no-cache ca-certificates git
COPY . ${PROJ_PATH}
WORKDIR ${PROJ_PATH}
ARG MODULE
RUN make $MODULE \
&& make pack4docker CMD=$MODULE \
&& tar -zxf open-falcon-v*.tar.gz -C ${FALCON_DIR} \
&& rm -rf ${PROJ_PATH}
# Final container;
FROM alpine:3.13
LABEL maintainer laiwei.ustc@gmail.com
USER root
ENV FALCON_DIR=/open-falcon
RUN mkdir -p $FALCON_DIR/logs && \
apk update && \
apk add --no-cache ca-certificates bash git iproute2
COPY --from=0 ${FALCON_DIR} ${FALCON_DIR}
EXPOSE 8433 8080
WORKDIR ${FALCON_DIR}
================================================
FILE: Dockerfile_arm64
================================================
FROM jimmytinsley/makegcc-golang
LABEL maintainer laiwei.ustc@gmail.com
USER root
ENV FALCON_DIR=/open-falcon PROJ_PATH=${GOPATH}/src/github.com/open-falcon/falcon-plus
RUN mkdir -p $FALCON_DIR && \
mkdir -p $FALCON_DIR/logs && \
apk add --no-cache ca-certificates bash git supervisor
COPY . ${PROJ_PATH}
WORKDIR ${PROJ_PATH}
RUN make all \
&& make pack4docker \
&& tar -zxf open-falcon-v*.tar.gz -C ${FALCON_DIR} \
&& rm -rf ${PROJ_PATH}
# Final container;
FROM alpine:3.7
LABEL maintainer laiwei.ustc@gmail.com
USER root
ENV FALCON_DIR=/open-falcon
RUN mkdir -p $FALCON_DIR/logs && \
apk add --no-cache ca-certificates bash git supervisor
ADD docker/supervisord.conf /etc/supervisord.conf
COPY --from=0 ${FALCON_DIR} ${FALCON_DIR}
EXPOSE 8433 8080
WORKDIR ${FALCON_DIR}
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Makefile
================================================
CMD = agent aggregator graph hbs judge nodata transfer gateway api alarm falcon2p8s
TARGET = open-falcon
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*")
GOFMT ?= gofmt "-s"
VERSION := $(shell cat VERSION)
all: $(CMD) $(TARGET)
.PHONY: misspell-check
misspell-check:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -error $(GOFILES)
.PHONY: misspell
misspell:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -w $(GOFILES)
vet:
go vet $(PACKAGES)
fmt:
$(GOFMT) -w $(GOFILES)
.PHONY: fmt-check
fmt-check:
# get all go files and run go fmt on them
@diff=$$($(GOFMT) -d $(GOFILES)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
$(CMD):
if [ $@ = "gateway" ]; then \
GO111MODULE=on go build -ldflags "-X main.BinaryName=gateway -X main.GitCommit=`git rev-parse --short HEAD` -X main.Version=$(VERSION)" \
-o bin/gateway/falcon-gateway ./modules/transfer ; \
else \
GO111MODULE=on go build -ldflags "-X main.BinaryName=$@ -X main.GitCommit=`git rev-parse --short HEAD` -X main.Version=$(VERSION)" \
-o bin/$@/falcon-$@ ./modules/$@ ; \
fi
.PHONY: $(TARGET)
$(TARGET): $(GOFILES)
GO111MODULE=on go build -ldflags "-X main.BinaryName=Open-Falcon -X main.GitCommit=`git rev-parse --short HEAD` -X main.Version=$(VERSION)" -o open-falcon
checkbin: bin/ config/ open-falcon
pack: checkbin
@if [ -e out ] ; then rm -rf out; fi
@mkdir out
@$(foreach var,$(CMD),mkdir -p ./out/$(var)/bin;)
@$(foreach var,$(CMD),mkdir -p ./out/$(var)/config;)
@$(foreach var,$(CMD),mkdir -p ./out/$(var)/logs;)
@$(foreach var,$(CMD),cp ./config/$(var).json ./out/$(var)/config/cfg.json;)
@$(foreach var,$(CMD),cp ./bin/$(var)/falcon-$(var) ./out/$(var)/bin;)
@cp -r ./modules/agent/public ./out/agent/
@(cd ./out && ln -s ./agent/public ./public)
@(cd ./out && mkdir -p ./agent/plugin && ln -s ./agent/plugin ./plugin)
@cp -r ./modules/api/data ./out/api/
@mkdir out/graph/data
@bash ./config/confgen.sh
@cp $(TARGET) ./out/$(TARGET)
tar -C out -zcf open-falcon-v$(VERSION).tar.gz .
@rm -rf out
pack4docker: checkbin
@if [ -e out ] ; then rm -rf out; fi
@mkdir out
@$(foreach var,$(CMD),mkdir -p ./out/$(var)/bin;)
@$(foreach var,$(CMD),mkdir -p ./out/$(var)/config;)
@$(foreach var,$(CMD),mkdir -p ./out/$(var)/logs;)
@$(foreach var,$(CMD),cp ./config/$(var).json ./out/$(var)/config/cfg.json;)
@$(foreach var,$(CMD),cp ./bin/$(var)/falcon-$(var) ./out/$(var)/bin;)
@if expr "$(CMD)" : "agent" > /dev/null; then \
(cp -r ./modules/agent/public ./out/agent/); \
(cd ./out && ln -s ./agent/public ./public); \
(cd ./out && mkdir -p ./agent/plugin && ln -s ./agent/plugin ./plugin); \
fi
@if expr "$(CMD)" : "api" > /dev/null; then \
cp -r ./modules/api/data ./out/api/; \
fi
@if expr "$(CMD)" : "graph" > /dev/null; then \
mkdir out/graph/data; \
fi
@cp ./docker/ctrl.sh ./out/ && chmod +x ./out/ctrl.sh
@cp $(TARGET) ./out/$(TARGET)
tar -C out -zcf open-falcon-v$(VERSION).tar.gz .
@rm -rf out
.PHONY: test
test:
@go test ./modules/api/test
clean:
@rm -rf ./bin
@rm -rf ./out
@rm -rf ./$(TARGET)
@rm -rf open-falcon-v$(VERSION).tar.gz
.PHONY: clean all agent aggregator graph hbs judge nodata transfer gateway api alarm
================================================
FILE: NOTICE
================================================
Open-Falcon
Copyright (c) 2014-2017 Xiaomi, Inc. All Rights Reserved.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
You may not use this product except in compliance with the License.
This product may include a number of subcomponents with separate copyright notices
and license terms. Your use of these subcomponents is subject to the terms and
conditions of the subcomponent's license, as noted in the LICENSE file.
================================================
FILE: README.md
================================================
# Falcon+

[](https://travis-ci.org/open-falcon/falcon-plus)
[](http://www.apache.org/licenses/LICENSE-2.0.html)
[](#backers)
[](#sponsors)
# Notice
If you are heavily using k8s and adopting microservices architecture, we recommend you to upgrade to use [Nightingale](https://github.com/ccfos/nightingale) building your modern monitoring system.
- [Nightingale](https://github.com/ccfos/nightingale) is an enterprise-level cloud-native monitoring tool, which can be used as drop-in replacement of Prometheus for alerting and management.
- [Categraf](https://github.com/flashcatcloud/categraf) is one-stop telemetry collector for Nightingale / Prometheus / M3DB / VictoriaMetrics / Thanos / Influxdb / TDengine.
It is recommended that you use [FlashDuty](https://flashcat.cloud/product/flashduty?from=categraf) as the OnCall system to realize alarm aggregation convergence, claiming, upgrading, scheduling, and coordination, so that the alarm can be reached efficiently and ensure that the alarm processing is not missed.
# Documentations
- [Usage](http://book.open-falcon.org)
- [Open-Falcon API](http://open-falcon.org/falcon-plus)
# Prerequisite
- Git >= 1.7.5
- Go >= 1.6
# Getting Started
## Docker
Please refer to ./docker/[README.md](https://github.com/open-falcon/falcon-plus/blob/master/docker/README.md).
## Build from source
**before start, please make sure you prepared this:**
```
yum install -y redis
yum install -y mysql-server
```
*NOTE: be sure to check redis and mysql-server have successfully started.*
And then
```
# Please make sure that you have set `$GOPATH` and `$GOROOT` correctly.
# If you have not golang in your host, please follow [https://golang.org/doc/install] to install golang.
mkdir -p $GOPATH/src/github.com/open-falcon
cd $GOPATH/src/github.com/open-falcon
git clone https://github.com/open-falcon/falcon-plus.git
```
**And do not forget to init the database first (if you have not loaded the database schema before)**
```
cd $GOPATH/src/github.com/open-falcon/falcon-plus/scripts/mysql/db_schema/
mysql -h 127.0.0.1 -u root -p < 1_uic-db-schema.sql
mysql -h 127.0.0.1 -u root -p < 2_portal-db-schema.sql
mysql -h 127.0.0.1 -u root -p < 3_dashboard-db-schema.sql
mysql -h 127.0.0.1 -u root -p < 4_graph-db-schema.sql
mysql -h 127.0.0.1 -u root -p < 5_alarms-db-schema.sql
```
**NOTE: if you are upgrading from v0.1 to v0.2.0(or above),then**. [More upgrading instruction](http://www.jianshu.com/p/6fb2c2b4d030)
mysql -h 127.0.0.1 -u root -p < 5_alarms-db-schema.sql
# Compilation
```
cd $GOPATH/src/github.com/open-falcon/falcon-plus/
# make all modules
make all
# make specified module
make agent
# pack all modules
make pack
```
* *after `make pack` you will got `open-falcon-vx.x.x.tar.gz`*
* *if you want to edit configure file for each module, you can edit `config/xxx.json` before you do `make pack`*
# Unpack and Decompose
```
export WorkDir="$HOME/open-falcon"
mkdir -p $WorkDir
tar -xzvf open-falcon-vx.x.x.tar.gz -C $WorkDir
cd $WorkDir
```
# Start all modules in single host
```
cd $WorkDir
./open-falcon start
# check modules status
./open-falcon check
```
# Run More Open-Falcon Commands
for example:
```
# ./open-falcon [start|stop|restart|check|monitor|reload] module
./open-falcon start agent
./open-falcon check
falcon-graph UP 53007
falcon-hbs UP 53014
falcon-judge UP 53020
falcon-transfer UP 53026
falcon-nodata UP 53032
falcon-aggregator UP 53038
falcon-agent UP 53044
falcon-gateway UP 53050
falcon-api UP 53056
falcon-alarm UP 53063
```
* For debugging , You can check `$WorkDir/$moduleName/logs/xxx.log`
# Install Frontend Dashboard
- Follow [this](https://github.com/open-falcon/dashboard).
**NOTE: if you want to use grafana as the dashboard, please check [this](https://github.com/open-falcon/grafana-openfalcon-datasource).**
# Package Release
```
make clean all pack
```
# API Standard
- [API Standard](https://github.com/open-falcon/falcon-plus/blob/master/api-standard.md)
# Q&A
- Any issue or question is welcome, Please feel free to open [github issues](https://github.com/open-falcon/falcon-plus/issues) :)
- [FAQ](http://book.open-falcon.org/zh_0_2/faq/)
## Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
================================================
FILE: VERSION
================================================
0.3.x
================================================
FILE: api-standard.md
================================================
# HTTP API建议规范
## 说明
本规范参考阮一峰的《[RESTful API设计指南](http://www.ruanyifeng.com/blog/2014/05/restful_api.html)》编写,部分内容做了适应性的调整和修改。
## 协议
本文档目前只针对HTTP与HTTPS协议,提供参考规范和建议。
## 域名
应尽量将API模块部署在专用域名之下。
```
http://api.open-falcon.com
```
## 版本(Versioning)
应将API版本号放入URL。
```
http://api.open-falcon.com/v1/
```
## 路径(Endpoint)
路径又称``“终点”(endpoint)``,表示API的具体网址。
路径中以``“/”``区分的每一项都应该是``小写英文单词``,若包含多个单词,需要用``下划线``分隔。
在RESTful架构中,每个网址代表一种``资源(resource)``,所以网址中不应包含动词,如show、delete等。只能有名词,而且所用的名词往往与数据库的表格名对应。
一般来说,数据库中的表都是同种记录的``“集合”(collection)``,所以API中的名词也应该使用``复数``。
以Open-Falcon举例,API模块提供各种关于监控系统的信息,包括数据及报警:
```
· http://api.open-falcon.com/v1/counters
· http://api.open-falcon.com/v1/strategies
· http://api.open-falcon.com/v1/points
```
## HTTP动词
对于资源的具体操作类型,由HTTP动词表示。
常用的HTTP动词有下面五个(括号里是对应的SQL命令)。
```
· GET(SELECT):从服务器取出资源(一项或多项)
· POST(CREATE):在服务器新建一个资源
· PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)
· PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)
· DELETE(DELETE):从服务器删除资源
```
PATCH一般不常用,更新资源建议使用```PUT```。
还有两个不常用的动词。
```
HEAD:获取资源的元数据。
OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。
```
以下是一些例子
```
· GET /v1/users : 获取所有的用户
· GET /v1/users/{int:ID} : 获取指定的用户信息
· POST /v1/users : 新增一个用户
· PUT /v1/users/{int:ID} : 更新某个指定用户的信息(提供用户的全部信息)
· PATCH /v1/users/{int:ID} : 更新某个指定用户的信息(提供用户的部分信息)
```
## 请求参数、请求体
如果记录数很多,服务器不可能都将他们返回给用户。API应该提供参数,支持过滤结果返回。
下面是一些常见的参数。
```
· ?limit=10 : 指定返回记录的数量
· ?offset=10 : 指定返回记录的开始位置
· ?page=2&per_page=100 : 指定第几页,以及每页的记录数
· ?sortby=name&order=asc : 指定返回结果按照哪个属性排序,以及排序顺序
· ?type_id=1 : 指定筛选条件
```
其中,参数的命名规则为``snake_case``,即单词全部小写,单词间使用下划线分隔。
参数的设计允许存在``冗余``,即允许API路径和URL参数偶尔有重复。比如,GET /services/ID/domains 与 GET /services?domain_id=ID 的含义是相同的。
另外,参考HTTP协议(1.0版和1.1版)的主要设计者Roy Thomas Fielding所言,任何HTTP请求都允许包含请求体,但发送一个请求体非空的GET请求是没有意义的。因此GET请求请求体应该为``空``。
对于POST、PUT、DELETE请求,若请求体不为空,则请求体格式应该为JSON,如:
```
{
"id" : 1,
"name" : "ZhangSan"
}
```
需要注意的是,JSON中key的命名规则同样需要遵循``snake_case``。
## 状态码(Status Code)
服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。
```
· 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
· 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
· 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
· 204 NO CONTENT - [DELETE]:用户删除数据成功。
· 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
· 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
· 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
· 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
· 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
· 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
· 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
· 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
```
状态码的完整列表,参见[这里](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)。
## 返回结果
服务器返回的数据格式,统一为``JSON``。针对资源的不同操作,服务器向用户返回的结果
应该符合以下规范:
```
· GET /collection : 返回资源对象的列表(数组)
· DELETE /collection/resource : 返回如下的json响应,其中data为被删除对象.
· GET /collection/resource : 返回单个资源对象
· POST /collection : 返回新生成的资源对象
· PUT /collection/resource : 返回更改后的完整的资源对象
```
响应格式统一如下: ``此处草版略复杂,待讨论修正``
```
{
"code": 200, // http status code
"data": data, // return data if success
"ret_msg": "return message if failed", // return message if failed, when success, it's empty
"debug_msg": "used for debug", // used for debug when failed,when success, it's emptuy
"url_manual": "manual url to show if failed", // manual url to show if failed
"url_redirect": "used for 3xx results", // used for 3xx results
“response_type": "application/json" // response body type
}
```
================================================
FILE: cmd/check.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"strings"
"github.com/open-falcon/falcon-plus/g"
"github.com/spf13/cobra"
)
var Check = &cobra.Command{
Use: "check [Module ...]",
Short: "Check the status of Open-Falcon modules",
Long: `
Check if the specified Open-Falcon modules are running.
Modules:
` + "all " + strings.Join(g.AllModulesInOrder, " "),
RunE: check,
}
func check(c *cobra.Command, args []string) error {
args = g.RmDup(args)
if len(args) == 0 {
args = g.AllModulesInOrder
}
for _, moduleName := range args {
if !g.HasModule(moduleName) {
return fmt.Errorf("%s doesn't exist", moduleName)
}
if g.IsRunning(moduleName) {
fmt.Printf("%20s %10s %15s \n", g.ModuleApps[moduleName], "UP", g.Pid(moduleName))
} else {
fmt.Printf("%20s %10s %15s \n", g.ModuleApps[moduleName], "DOWN", "-")
}
}
return nil
}
================================================
FILE: cmd/monitor.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"os"
"os/exec"
"strings"
"github.com/open-falcon/falcon-plus/g"
"github.com/spf13/cobra"
)
var Monitor = &cobra.Command{
Use: "monitor [Module ...]",
Short: "Display an Open-Falcon module's log",
Long: `
Display the log of the specified Open-Falcon module.
A module represents a single node in a cluster.
Modules:
` + strings.Join(g.AllModulesInOrder, " "),
RunE: monitor,
}
func checkMonReq(name string) error {
if !g.HasModule(name) {
return fmt.Errorf("%s doesn't exist", name)
}
if !g.HasLogfile(name) {
r := g.Rel(g.LogPath(name))
return fmt.Errorf("expect logfile: %s", r)
}
return nil
}
func monitor(c *cobra.Command, args []string) error {
if len(args) < 1 {
return c.Usage()
}
var tailArgs []string = []string{"-f"}
for _, moduleName := range args {
if err := checkMonReq(moduleName); err != nil {
return err
}
tailArgs = append(tailArgs, g.LogPath(moduleName))
}
cmd := exec.Command("tail", tailArgs...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
================================================
FILE: cmd/reload.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import "github.com/spf13/cobra"
var Reload = &cobra.Command{
Use: "reload [Module ...]",
Short: "Reload an Open-Falcon module's configuration file",
Long: `
Reload the configuration file of the specified Open-Falcon module.
A module represents a single node in a cluster.
Modules:
`,
RunE: reload,
}
func reload(c *cobra.Command, args []string) error {
if len(args) != 1 {
return c.Usage()
}
return nil
}
================================================
FILE: cmd/restart.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"strings"
"time"
"github.com/open-falcon/falcon-plus/g"
"github.com/spf13/cobra"
)
var Restart = &cobra.Command{
Use: "restart [Module ...]",
Short: "Restart Open-Falcon modules",
Long: `
Restart the specified Open-Falcon modules and run until a stop command is received.
A module represents a single node in a cluster.
Modules:
` + "all " + strings.Join(g.AllModulesInOrder, " "),
RunE: restart,
}
func restart(c *cobra.Command, args []string) error {
args = g.RmDup(args)
if len(args) == 0 {
args = g.AllModulesInOrder
}
for _, moduleName := range args {
if err := stop(c, []string{moduleName}); err != nil {
return err
}
if strings.Contains(moduleName, "graph") {
time.Sleep(2 * time.Second)
} else {
time.Sleep(1 * time.Second)
}
if err := start(c, []string{moduleName}); err != nil {
return err
}
}
return nil
}
================================================
FILE: cmd/start.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"os"
"os/exec"
"strings"
"time"
"github.com/open-falcon/falcon-plus/g"
"github.com/spf13/cobra"
)
var Start = &cobra.Command{
Use: "start [Module ...]",
Short: "Start Open-Falcon modules",
Long: `
Start the specified Open-Falcon modules and run until a stop command is received.
A module represents a single node in a cluster.
Modules:
` + "all " + strings.Join(g.AllModulesInOrder, " "),
RunE: start,
SilenceUsage: true,
SilenceErrors: true,
}
var PreqOrderFlag bool
var ConsoleOutputFlag bool
func cmdArgs(name string) []string {
return []string{"-c", g.Cfg(name)}
}
func openLogFile(name string) (*os.File, error) {
logDir := g.LogDir(name)
if err := os.MkdirAll(logDir, 0755); err != nil {
return nil, err
}
logPath := g.LogPath(name)
logOutput, err := os.OpenFile(logPath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
if err != nil {
return nil, err
}
return logOutput, nil
}
func execModule(co bool, name string) error {
cmd := exec.Command(g.Bin(name), cmdArgs(name)...)
if co {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
logOutput, err := openLogFile(name)
if err != nil {
return err
}
defer logOutput.Close()
cmd.Stdout = logOutput
cmd.Stderr = logOutput
return cmd.Start()
}
func checkStartReq(name string) error {
if !g.HasModule(name) {
return fmt.Errorf("%s doesn't exist", name)
}
if !g.HasCfg(name) {
r := g.Rel(g.Cfg(name))
return fmt.Errorf("expect config file: %s", r)
}
return nil
}
func isStarted(name string) bool {
ticker := time.NewTicker(time.Millisecond * 100)
defer ticker.Stop()
timeout := time.After(time.Second)
for {
select {
case <-ticker.C:
if g.IsRunning(name) {
return true
}
case <-timeout:
return false
}
}
}
func start(c *cobra.Command, args []string) error {
args = g.RmDup(args)
if PreqOrderFlag {
args = g.PreqOrder(args)
}
if len(args) == 0 {
args = g.AllModulesInOrder
}
for _, moduleName := range args {
if err := checkStartReq(moduleName); err != nil {
return err
}
// Skip starting if the module is already running
if g.IsRunning(moduleName) {
fmt.Print("[", g.ModuleApps[moduleName], "] ", g.Pid(moduleName), "\n")
continue
}
if err := execModule(ConsoleOutputFlag, moduleName); err != nil {
return err
}
if isStarted(moduleName) {
fmt.Print("[", g.ModuleApps[moduleName], "] ", g.Pid(moduleName), "\n")
continue
}
return fmt.Errorf("[%s] failed to start", g.ModuleApps[moduleName])
}
return nil
}
================================================
FILE: cmd/stop.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"os"
"os/exec"
"strings"
"github.com/open-falcon/falcon-plus/g"
"github.com/spf13/cobra"
)
var Stop = &cobra.Command{
Use: "stop [Module ...]",
Short: "Stop Open-Falcon modules",
Long: `
Stop the specified Open-Falcon modules.
A module represents a single node in a cluster.
Modules:
` + "all " + strings.Join(g.AllModulesInOrder, " "),
RunE: stop,
}
func stop(c *cobra.Command, args []string) error {
args = g.RmDup(args)
if len(args) == 0 {
args = g.AllModulesInOrder
}
for _, moduleName := range args {
if !g.HasModule(moduleName) {
return fmt.Errorf("%s doesn't exist", moduleName)
}
if !g.IsRunning(moduleName) {
fmt.Print("[", g.ModuleApps[moduleName], "] down\n")
continue
}
cmd := exec.Command("kill", "-TERM", g.Pid(moduleName))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err == nil {
fmt.Print("[", g.ModuleApps[moduleName], "] down\n")
continue
}
return err
}
return nil
}
================================================
FILE: common/.gitignore
================================================
*.swp
*.swo
/var
.DS_Store
*.iml
*.idea
================================================
FILE: common/LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: common/NOTICE
================================================
Open-Falcon
Copyright (c) 2014-2015 Xiaomi, Inc. All Rights Reserved.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
You may not use this product except in compliance with the License.
This product may include a number of subcomponents with separate copyright notices
and license terms. Your use of these subcomponents is subject to the terms and
conditions of the subcomponent's license, as noted in the LICENSE file.
================================================
FILE: common/backend_pool/rpc_backends.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package backend_pool
import (
"fmt"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"sync"
"time"
connp "github.com/toolkits/conn_pool"
rpcpool "github.com/toolkits/conn_pool/rpc_conn_pool"
)
// ConnPools Manager
type SafeRpcConnPools struct {
sync.RWMutex
M map[string]*connp.ConnPool
MaxConns int
MaxIdle int
ConnTimeout int
CallTimeout int
}
func CreateSafeRpcConnPools(maxConns, maxIdle, connTimeout, callTimeout int, cluster []string) *SafeRpcConnPools {
cp := &SafeRpcConnPools{M: make(map[string]*connp.ConnPool), MaxConns: maxConns, MaxIdle: maxIdle,
ConnTimeout: connTimeout, CallTimeout: callTimeout}
ct := time.Duration(cp.ConnTimeout) * time.Millisecond
for _, address := range cluster {
if _, exist := cp.M[address]; exist {
continue
}
cp.M[address] = createOneRpcPool(address, address, ct, maxConns, maxIdle)
}
return cp
}
func CreateSafeJsonrpcConnPools(maxConns, maxIdle, connTimeout, callTimeout int, cluster []string) *SafeRpcConnPools {
cp := &SafeRpcConnPools{M: make(map[string]*connp.ConnPool), MaxConns: maxConns, MaxIdle: maxIdle,
ConnTimeout: connTimeout, CallTimeout: callTimeout}
ct := time.Duration(cp.ConnTimeout) * time.Millisecond
for _, address := range cluster {
if _, exist := cp.M[address]; exist {
continue
}
cp.M[address] = createOneJsonrpcPool(address, address, ct, maxConns, maxIdle)
}
return cp
}
// 同步发送, 完成发送或超时后 才能返回
func (this *SafeRpcConnPools) Call(addr, method string, args interface{}, resp interface{}) error {
connPool, exists := this.Get(addr)
if !exists {
return fmt.Errorf("%s has no connection pool", addr)
}
conn, err := connPool.Fetch()
if err != nil {
return fmt.Errorf("%s get connection fail: conn %v, err %v. proc: %s", addr, conn, err, connPool.Proc())
}
rpcClient := conn.(*rpcpool.RpcClient)
callTimeout := time.Duration(this.CallTimeout) * time.Millisecond
done := make(chan error, 1)
go func() {
done <- rpcClient.Call(method, args, resp)
}()
select {
case <-time.After(callTimeout):
connPool.ForceClose(conn)
return fmt.Errorf("%s, call timeout", addr)
case err = <-done:
if err != nil {
connPool.ForceClose(conn)
err = fmt.Errorf("%s, call failed, err %v. proc: %s", addr, err, connPool.Proc())
} else {
connPool.Release(conn)
}
return err
}
}
func (this *SafeRpcConnPools) Get(address string) (*connp.ConnPool, bool) {
this.RLock()
defer this.RUnlock()
p, exists := this.M[address]
return p, exists
}
func (this *SafeRpcConnPools) Destroy() {
this.Lock()
defer this.Unlock()
addresses := make([]string, 0, len(this.M))
for address := range this.M {
addresses = append(addresses, address)
}
for _, address := range addresses {
this.M[address].Destroy()
delete(this.M, address)
}
}
func (this *SafeRpcConnPools) Proc() []string {
procs := []string{}
for _, cp := range this.M {
procs = append(procs, cp.Proc())
}
return procs
}
func createOneRpcPool(name string, address string, connTimeout time.Duration, maxConns int, maxIdle int) *connp.ConnPool {
p := connp.NewConnPool(name, address, int32(maxConns), int32(maxIdle))
p.New = func(connName string) (connp.NConn, error) {
_, err := net.ResolveTCPAddr("tcp", p.Address)
if err != nil {
return nil, err
}
conn, err := net.DialTimeout("tcp", p.Address, connTimeout)
if err != nil {
return nil, err
}
return rpcpool.NewRpcClient(rpc.NewClient(conn), connName), nil
}
return p
}
func createOneJsonrpcPool(name string, address string, connTimeout time.Duration, maxConns int, maxIdle int) *connp.ConnPool {
p := connp.NewConnPool(name, address, int32(maxConns), int32(maxIdle))
p.New = func(connName string) (connp.NConn, error) {
_, err := net.ResolveTCPAddr("tcp", p.Address)
if err != nil {
return nil, err
}
conn, err := net.DialTimeout("tcp", p.Address, connTimeout)
if err != nil {
return nil, err
}
return rpcpool.NewRpcClientWithCodec(jsonrpc.NewClientCodec(conn), connName), nil
}
return p
}
================================================
FILE: common/backend_pool/tsdb_backends.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package backend_pool
import (
"fmt"
"net"
"time"
connp "github.com/toolkits/conn_pool"
)
// TSDB
type TsdbClient struct {
cli *struct{ net.Conn }
name string
}
func (t TsdbClient) Name() string {
return t.name
}
func (t TsdbClient) Closed() bool {
return t.cli.Conn == nil
}
func (t TsdbClient) Close() error {
if t.cli != nil {
err := t.cli.Close()
t.cli.Conn = nil
return err
}
return nil
}
func newTsdbConnPool(address string, maxConns int, maxIdle int, connTimeout int) *connp.ConnPool {
pool := connp.NewConnPool("tsdb", address, int32(maxConns), int32(maxIdle))
pool.New = func(name string) (connp.NConn, error) {
_, err := net.ResolveTCPAddr("tcp", address)
if err != nil {
return nil, err
}
conn, err := net.DialTimeout("tcp", address, time.Duration(connTimeout)*time.Millisecond)
if err != nil {
return nil, err
}
return TsdbClient{
cli: &struct{ net.Conn }{conn},
name: name,
}, nil
}
return pool
}
type TsdbConnPoolHelper struct {
p *connp.ConnPool
maxConns int
maxIdle int
connTimeout int
callTimeout int
address string
}
func NewTsdbConnPoolHelper(address string, maxConns, maxIdle, connTimeout, callTimeout int) *TsdbConnPoolHelper {
return &TsdbConnPoolHelper{
p: newTsdbConnPool(address, maxConns, maxIdle, connTimeout),
maxConns: maxConns,
maxIdle: maxIdle,
connTimeout: connTimeout,
callTimeout: callTimeout,
address: address,
}
}
func (t *TsdbConnPoolHelper) Send(data []byte) (err error) {
conn, err := t.p.Fetch()
if err != nil {
return fmt.Errorf("get connection fail: err %v. proc: %s", err, t.p.Proc())
}
cli := conn.(TsdbClient).cli
done := make(chan error, 1)
go func() {
_, err = cli.Write(data)
done <- err
}()
select {
case <-time.After(time.Duration(t.callTimeout) * time.Millisecond):
t.p.ForceClose(conn)
return fmt.Errorf("%s, call timeout", t.address)
case err = <-done:
if err != nil {
t.p.ForceClose(conn)
err = fmt.Errorf("%s, call failed, err %v. proc: %s", t.address, err, t.p.Proc())
} else {
t.p.Release(conn)
}
return err
}
}
func (t *TsdbConnPoolHelper) Destroy() {
if t.p != nil {
t.p.Destroy()
}
}
================================================
FILE: common/db/db.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package db
// graph.endpoint
type GraphEndpoint struct {
Id int64
Endpoint string
}
// graph.tag_endpoint
type GraphTagEndpoint struct {
Id int64
Tag string
EndpointId int64
}
// graph.endpoint_counter
type GraphEndpointCounter struct {
Id int64
EndpointId int64
Counter string
}
================================================
FILE: common/model/agent.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
)
type AgentReportRequest struct {
Hostname string
IP string
AgentVersion string
PluginVersion string
}
func (this *AgentReportRequest) String() string {
return fmt.Sprintf(
"",
this.Hostname,
this.IP,
this.AgentVersion,
this.PluginVersion,
)
}
type AgentUpdateInfo struct {
LastUpdate int64
ReportRequest *AgentReportRequest
}
type AgentHeartbeatRequest struct {
Hostname string
Checksum string
}
func (this *AgentHeartbeatRequest) String() string {
return fmt.Sprintf(
"",
this.Hostname,
this.Checksum,
)
}
type AgentPluginsResponse struct {
Plugins []string
Timestamp int64
}
func (this *AgentPluginsResponse) String() string {
return fmt.Sprintf(
"",
this.Plugins,
this.Timestamp,
)
}
// e.g. net.port.listen or proc.num
type BuiltinMetric struct {
Metric string
Tags string
}
func (this *BuiltinMetric) String() string {
return fmt.Sprintf(
"%s/%s",
this.Metric,
this.Tags,
)
}
type BuiltinMetricResponse struct {
Metrics []*BuiltinMetric
Checksum string
Timestamp int64
}
func (this *BuiltinMetricResponse) String() string {
return fmt.Sprintf(
"",
this.Metrics,
this.Checksum,
this.Timestamp,
)
}
type BuiltinMetricSlice []*BuiltinMetric
func (this BuiltinMetricSlice) Len() int {
return len(this)
}
func (this BuiltinMetricSlice) Swap(i, j int) {
this[i], this[j] = this[j], this[i]
}
func (this BuiltinMetricSlice) Less(i, j int) bool {
return this[i].String() < this[j].String()
}
================================================
FILE: common/model/event.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
"github.com/open-falcon/falcon-plus/common/utils"
)
// 机器监控和实例监控都会产生Event,共用这么一个struct
type Event struct {
Id string `json:"id"`
Strategy *Strategy `json:"strategy"`
Expression *Expression `json:"expression"`
Status string `json:"status"` // OK or PROBLEM
Endpoint string `json:"endpoint"`
LeftValue float64 `json:"leftValue"`
CurrentStep int `json:"currentStep"`
EventTime int64 `json:"eventTime"`
PushedTags map[string]string `json:"pushedTags"`
}
func (this *Event) FormattedTime() string {
return utils.UnixTsFormat(this.EventTime)
}
func (this *Event) String() string {
return fmt.Sprintf(
"",
this.Endpoint,
this.Status,
this.Strategy,
this.Expression,
utils.ReadableFloat(this.LeftValue),
this.CurrentStep,
this.PushedTags,
this.FormattedTime(),
)
}
func (this *Event) ExpressionId() int {
if this.Expression != nil {
return this.Expression.Id
}
return 0
}
func (this *Event) StrategyId() int {
if this.Strategy != nil {
return this.Strategy.Id
}
return 0
}
func (this *Event) TplId() int {
if this.Strategy != nil {
return this.Strategy.Tpl.Id
}
return 0
}
func (this *Event) Tpl() *Template {
if this.Strategy != nil {
return this.Strategy.Tpl
}
return nil
}
func (this *Event) ActionId() int {
if this.Expression != nil {
return this.Expression.ActionId
}
return this.Strategy.Tpl.ActionId
}
func (this *Event) Priority() int {
if this.Strategy != nil {
return this.Strategy.Priority
}
return this.Expression.Priority
}
func (this *Event) Note() string {
if this.Strategy != nil {
return this.Strategy.Note
}
return this.Expression.Note
}
func (this *Event) Metric() string {
if this.Strategy != nil {
return this.Strategy.Metric
}
return this.Expression.Metric
}
func (this *Event) RightValue() float64 {
if this.Strategy != nil {
return this.Strategy.RightValue
}
return this.Expression.RightValue
}
func (this *Event) Operator() string {
if this.Strategy != nil {
return this.Strategy.Operator
}
return this.Expression.Operator
}
func (this *Event) Func() string {
if this.Strategy != nil {
return this.Strategy.Func
}
return this.Expression.Func
}
func (this *Event) MaxStep() int {
if this.Strategy != nil {
return this.Strategy.MaxStep
}
return this.Expression.MaxStep
}
func (this *Event) Counter() string {
return fmt.Sprintf("%s/%s %s", this.Endpoint, this.Metric(), utils.SortedTags(this.PushedTags))
}
================================================
FILE: common/model/expression.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
"github.com/open-falcon/falcon-plus/common/utils"
)
type Expression struct {
Id int `json:"id"`
Metric string `json:"metric"`
Tags map[string]string `json:"tags"`
Func string `json:"func"` // e.g. max(#3) all(#3)
Operator string `json:"operator"` // e.g. < !=
RightValue float64 `json:"rightValue"` // critical value
MaxStep int `json:"maxStep"`
Priority int `json:"priority"`
Note string `json:"note"`
ActionId int `json:"actionId"`
}
func (this *Expression) String() string {
return fmt.Sprintf(
"",
this.Id,
this.Metric,
this.Tags,
this.Func,
this.Operator,
utils.ReadableFloat(this.RightValue),
this.MaxStep,
this.Priority,
this.Note,
this.ActionId,
)
}
type ExpressionResponse struct {
Expressions []*Expression `json:"expressions"`
}
================================================
FILE: common/model/graph.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
"math"
MUtils "github.com/open-falcon/falcon-plus/common/utils"
)
// DsType 即RRD中的Datasource的类型:GAUGE|COUNTER|DERIVE
type GraphItem struct {
Endpoint string `json:"endpoint"`
Metric string `json:"metric"`
Tags map[string]string `json:"tags"`
Value float64 `json:"value"`
Timestamp int64 `json:"timestamp"`
DsType string `json:"dstype"`
Step int `json:"step"`
Heartbeat int `json:"heartbeat"`
Min string `json:"min"`
Max string `json:"max"`
}
func (this *GraphItem) String() string {
return fmt.Sprintf(
"",
this.Endpoint,
this.Metric,
this.Tags,
this.Value,
this.Timestamp,
MUtils.UnixTsFormat(this.Timestamp),
this.DsType,
this.Step,
this.Heartbeat,
this.Min,
this.Max,
)
}
func (this *GraphItem) PrimaryKey() string {
return MUtils.PK(this.Endpoint, this.Metric, this.Tags)
}
func (t *GraphItem) Checksum() string {
return MUtils.Checksum(t.Endpoint, t.Metric, t.Tags)
}
func (this *GraphItem) UUID() string {
return MUtils.UUID(this.Endpoint, this.Metric, this.Tags, this.DsType, this.Step)
}
type GraphDeleteParam struct {
Endpoint string `json:"endpoint"`
Metric string `json:"metric"`
Step int `json:"step"`
DsType string `json:"dstype"`
Tags string `json:"tags"`
}
type GraphDeleteResp struct {
}
// ConsolFun 是RRD中的概念,比如:MIN|MAX|AVERAGE
type GraphQueryParam struct {
Start int64 `json:"start"`
End int64 `json:"end"`
ConsolFun string `json:"consolFuc"`
Endpoint string `json:"endpoint"`
Counter string `json:"counter"`
Step int `json:"step"`
}
type GraphQueryResponse struct {
Endpoint string `json:"endpoint"`
Counter string `json:"counter"`
DsType string `json:"dstype"`
Step int `json:"step"`
Values []*RRDData `json:"Values"` //大写为了兼容已经再用这个api的用户
}
// 页面上已经可以看到DsType和Step了,直接带进查询条件,Graph更易处理
type GraphAccurateQueryParam struct {
Checksum string `json:"checksum"`
Start int64 `json:"start"`
End int64 `json:"end"`
ConsolFun string `json:"consolFuc"`
DsType string `json:"dsType"`
Step int `json:"step"`
}
type GraphAccurateQueryResponse struct {
Values []*RRDData `json:"Values"`
}
type JsonFloat float64
func (v JsonFloat) MarshalJSON() ([]byte, error) {
f := float64(v)
if math.IsNaN(f) || math.IsInf(f, 0) {
return []byte("null"), nil
} else {
return []byte(fmt.Sprintf("%f", f)), nil
}
}
type RRDData struct {
Timestamp int64 `json:"timestamp"`
Value JsonFloat `json:"value"`
}
func NewRRDData(ts int64, val float64) *RRDData {
return &RRDData{Timestamp: ts, Value: JsonFloat(val)}
}
func (this *RRDData) String() string {
return fmt.Sprintf(
"",
this.Value,
this.Timestamp,
MUtils.UnixTsFormat(this.Timestamp),
)
}
type GraphInfoParam struct {
Endpoint string `json:"endpoint"`
Counter string `json:"counter"`
}
type GraphInfoResp struct {
ConsolFun string `json:"consolFun"`
Step int `json:"step"`
Filename string `json:"filename"`
}
type GraphFullyInfo struct {
Endpoint string `json:"endpoint"`
Counter string `json:"counter"`
ConsolFun string `json:"consolFun"`
Step int `json:"step"`
Filename string `json:"filename"`
Addr string `json:"addr"`
}
type GraphLastParam struct {
Endpoint string `json:"endpoint"`
Counter string `json:"counter"`
}
type GraphLastResp struct {
Endpoint string `json:"endpoint"`
Counter string `json:"counter"`
Value *RRDData `json:"value"`
}
================================================
FILE: common/model/host.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
)
type Host struct {
Id int
Name string
}
func (this *Host) String() string {
return fmt.Sprintf(
"",
this.Id,
this.Name,
)
}
================================================
FILE: common/model/influxdb.go
================================================
package model
type InfluxdbItem struct {
Measurement string `json:"metric"`
Tags map[string]string `json:"tags"`
Fileds map[string]interface{} `json:"fileds"`
Timestamp int64 `json:"timestamp"`
}
================================================
FILE: common/model/judge.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
"github.com/open-falcon/falcon-plus/common/utils"
)
type JudgeItem struct {
Endpoint string `json:"endpoint"`
Metric string `json:"metric"`
Value float64 `json:"value"`
Timestamp int64 `json:"timestamp"`
JudgeType string `json:"judgeType"`
Tags map[string]string `json:"tags"`
}
func (this *JudgeItem) String() string {
return fmt.Sprintf("",
this.Endpoint,
this.Metric,
this.Value,
this.Timestamp,
this.JudgeType,
this.Tags)
}
func (this *JudgeItem) PrimaryKey() string {
return utils.Md5(utils.PK(this.Endpoint, this.Metric, this.Tags))
}
type HistoryData struct {
Timestamp int64 `json:"timestamp"`
Value float64 `json:"value"`
}
================================================
FILE: common/model/metric.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
MUtils "github.com/open-falcon/falcon-plus/common/utils"
)
type MetricValue struct {
Endpoint string `json:"endpoint"`
Metric string `json:"metric"`
Value interface{} `json:"value"`
Step int64 `json:"step"`
Type string `json:"counterType"`
Tags string `json:"tags"`
Timestamp int64 `json:"timestamp"`
}
func (this *MetricValue) String() string {
return fmt.Sprintf(
"",
this.Endpoint,
this.Metric,
this.Type,
this.Tags,
this.Step,
this.Timestamp,
this.Value,
)
}
// Same As `MetricValue`
type JsonMetaData struct {
Metric string `json:"metric"`
Endpoint string `json:"endpoint"`
Timestamp int64 `json:"timestamp"`
Step int64 `json:"step"`
Value interface{} `json:"value"`
CounterType string `json:"counterType"`
Tags string `json:"tags"`
}
func (t *JsonMetaData) String() string {
return fmt.Sprintf("",
t.Endpoint, t.Metric, t.Tags, t.CounterType, t.Step, t.Value, t.Timestamp)
}
type MetaData struct {
Metric string `json:"metric"`
Endpoint string `json:"endpoint"`
Timestamp int64 `json:"timestamp"`
Step int64 `json:"step"`
Value float64 `json:"value"`
CounterType string `json:"counterType"`
Tags map[string]string `json:"tags"`
}
func (t *MetaData) String() string {
return fmt.Sprintf("",
t.Endpoint, t.Metric, t.Timestamp, t.Step, t.Value, t.Tags)
}
func (t *MetaData) PK() string {
return MUtils.PK(t.Endpoint, t.Metric, t.Tags)
}
================================================
FILE: common/model/nodata.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
"github.com/open-falcon/falcon-plus/common/utils"
ttime "github.com/toolkits/time"
)
type NodataItem struct {
Counter string `json:"counter"`
Ts int64 `json:"ts"`
FStatus string `json:"fstatus"`
FTs int64 `json:"fts"`
}
func (this *NodataItem) String() string {
return fmt.Sprintf("{NodataItem counter:%s ts:%s fecthStatus:%s fetchTs:%s}",
this.Counter, ttime.FormatTs(this.Ts), this.FStatus, ttime.FormatTs(this.FTs))
}
type NodataConfig struct {
Id int `json:"id"`
Name string `json:"name"`
ObjType string `json:"objType"`
Endpoint string `json:"endpoint"`
Metric string `json:"metric"`
Tags map[string]string `json:"tags"`
Type string `json:"type"`
Step int64 `json:"step"`
Mock float64 `json:"mock"`
}
func NewNodataConfig(id int, name string, objType string, endpoint string, metric string, tags map[string]string, dstype string, step int64, mock float64) *NodataConfig {
return &NodataConfig{id, name, objType, endpoint, metric, tags, dstype, step, mock}
}
func (this *NodataConfig) String() string {
return fmt.Sprintf("{NodataConfig id:%d, name:%s, objType:%s, endpoint:%s, metric:%s, tags:%s, type:%s, step:%d, mock:%f}",
this.Id, this.Name, this.ObjType, this.Endpoint, this.Metric, utils.SortedTags(this.Tags), this.Type, this.Step, this.Mock)
}
================================================
FILE: common/model/prometheus.go
================================================
package model
// MetricType Prometheus指标类型:GAUGE|COUNTER
type P8sItem struct {
Endpoint string `json:"endpoint"`
Metric string `json:"metric"`
Tags map[string]string `json:"tags"`
Value float64 `json:"value"`
Timestamp int64 `json:"timestamp"`
MetricType string `json:"metric_type"`
Step int `json:"step"`
}
================================================
FILE: common/model/rpc.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
)
// code == 0 => success
// code == 1 => bad request
type SimpleRpcResponse struct {
Code int `json:"code"`
}
func (this *SimpleRpcResponse) String() string {
return fmt.Sprintf("", this.Code)
}
type NullRpcRequest struct {
}
================================================
FILE: common/model/strategy.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
"github.com/open-falcon/falcon-plus/common/utils"
)
type Strategy struct {
Id int `json:"id"`
Metric string `json:"metric"`
Tags map[string]string `json:"tags"`
Func string `json:"func"` // e.g. max(#3) all(#3)
Operator string `json:"operator"` // e.g. < !=
RightValue float64 `json:"rightValue"` // critical value
MaxStep int `json:"maxStep"`
Priority int `json:"priority"`
Note string `json:"note"`
Tpl *Template `json:"tpl"`
}
func (this *Strategy) String() string {
return fmt.Sprintf(
"",
this.Id,
this.Metric,
this.Tags,
this.Func,
this.Operator,
utils.ReadableFloat(this.RightValue),
this.MaxStep,
this.Priority,
this.Note,
this.Tpl,
)
}
type HostStrategy struct {
Hostname string `json:"hostname"`
Strategies []Strategy `json:"strategies"`
}
type StrategiesResponse struct {
HostStrategies []*HostStrategy `json:"hostStrategies"`
}
================================================
FILE: common/model/template.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
)
type Template struct {
Id int `json:"id"`
Name string `json:"name"`
ParentId int `json:"parentId"`
ActionId int `json:"actionId"`
Creator string `json:"creator"`
}
func (this *Template) String() string {
return fmt.Sprintf(
"",
this.Id,
this.Name,
this.ParentId,
this.ActionId,
this.Creator,
)
}
================================================
FILE: common/model/transfer.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
)
type TransferResponse struct {
Message string
Total int
Invalid int
Latency int64
}
func (this *TransferResponse) String() string {
return fmt.Sprintf(
"",
this.Total,
this.Invalid,
this.Latency,
this.Message,
)
}
================================================
FILE: common/model/tsdb.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
"strings"
)
type TsdbItem struct {
Metric string `json:"metric"`
Tags map[string]string `json:"tags"`
Value float64 `json:"value"`
Timestamp int64 `json:"timestamp"`
}
func (this *TsdbItem) String() string {
return fmt.Sprintf(
"",
this.Metric,
this.Tags,
this.Value,
this.Timestamp,
)
}
func (this *TsdbItem) TsdbString() (s string) {
s = fmt.Sprintf("put %s %d %.3f ", this.Metric, this.Timestamp, this.Value)
for k, v := range this.Tags {
key := strings.ToLower(strings.Replace(k, " ", "_", -1))
value := strings.Replace(v, " ", "_", -1)
s += key + "=" + value + " "
}
return s
}
================================================
FILE: common/proc/proc.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package proc
import (
"sync"
"time"
)
const (
DefaultOtherMaxSize = 100 // 默认的 自定义统计字段的最大值
DefaultSCounterQpsPeriod = 1 // QPS计算周期, 默认值为1s
)
// 基本的计数器
type SCounterBase struct {
sync.RWMutex
Name string
Cnt int64
Time string
ts int64
// 自定义统计指标
Other map[string]interface{}
}
func NewSCounterBase(name string) *SCounterBase {
uts := time.Now().Unix()
return &SCounterBase{Name: name, Cnt: 0, Time: formatTs(uts), ts: uts,
Other: make(map[string]interface{})}
}
func (this *SCounterBase) Get() *SCounterBase {
this.RLock()
defer this.RUnlock()
return this
}
// to be abandoned
func (this *SCounterBase) Set(cnt int64) {
this.Lock()
defer this.Unlock()
this.Cnt = cnt
this.ts = time.Now().Unix()
this.Time = formatTs(this.ts)
}
func (this *SCounterBase) SetCnt(cnt int64) {
this.Lock()
defer this.Unlock()
this.Cnt = cnt
this.ts = time.Now().Unix()
this.Time = formatTs(this.ts)
}
func (this *SCounterBase) PutOther(key string, value interface{}) bool {
this.Lock()
defer this.Unlock()
ret := false
_, exist := this.Other[key]
if exist {
this.Other[key] = value
ret = true
} else {
if len(this.Other) < DefaultOtherMaxSize {
this.Other[key] = value
ret = true
}
}
return ret
}
func formatTs(ts int64) string {
return time.Unix(ts, 0).Format("2006-01-02 15:04:05")
}
// QPS统计,只支持 增加计数操作
type SCounterQps struct {
sync.RWMutex
Name string
Cnt int64
Qps int64
Time string
ts int64
// for qps
lastTs int64
lastCnt int64
// 自定义统计指标
Other map[string]interface{}
}
func NewSCounterQps(name string) *SCounterQps {
uts := time.Now().Unix()
return &SCounterQps{Name: name, Cnt: 0, Time: formatTs(uts), ts: uts,
Qps: 0, lastCnt: 0, lastTs: uts,
Other: make(map[string]interface{})}
}
func (this *SCounterQps) Get() *SCounterQps {
this.RLock()
defer this.RUnlock()
this.incrByDirty(0) // update qps
return this
}
func (this *SCounterQps) Incr() {
this.IncrBy(int64(1))
}
func (this *SCounterQps) IncrBy(incr int64) {
this.Lock()
defer this.Unlock()
this.incrByDirty(incr)
}
func (this *SCounterQps) PutOther(key string, value interface{}) bool {
this.Lock()
defer this.Unlock()
ret := false
_, exist := this.Other[key]
if exist {
this.Other[key] = value
ret = true
} else {
if len(this.Other) < DefaultOtherMaxSize {
this.Other[key] = value
ret = true
}
}
return ret
}
// 操作我的时候,请加写锁
func (this *SCounterQps) incrByDirty(incr int64) {
this.Cnt += incr
this.ts = time.Now().Unix()
this.Time = formatTs(this.ts)
// qps
if this.ts-this.lastTs > DefaultSCounterQpsPeriod {
this.Qps = int64((this.Cnt - this.lastCnt) / (this.ts - this.lastTs))
this.lastTs = this.ts
this.lastCnt = this.Cnt
}
}
================================================
FILE: common/sdk/.gitignore
================================================
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
*.swp
*.swo
*.log
.idea
.DS_Store
/sdk*
/gitversion
================================================
FILE: common/sdk/README.md
================================================
================================================
FILE: common/sdk/requests/auth_request.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package requests
import (
"encoding/json"
"errors"
"github.com/toolkits/net/httplib"
"time"
)
func CurlPlus(uri, method, token_name, token_sig string, headers, params map[string]string) (req *httplib.BeegoHttpRequest, err error) {
if method == "GET" {
req = httplib.Get(uri)
} else if method == "POST" {
req = httplib.Post(uri)
} else if method == "PUT" {
req = httplib.Put(uri)
} else if method == "DELETE" {
req = httplib.Delete(uri)
} else if method == "HEAD" {
req = httplib.Head(uri)
} else {
err = errors.New("invalid http method")
return
}
req = req.SetTimeout(1*time.Second, 5*time.Second)
token, _ := json.Marshal(map[string]string{
"name": token_name,
"sig": token_sig,
})
req.Header("Apitoken", string(token))
for hk, hv := range headers {
req.Header(hk, hv)
}
for pk, pv := range params {
req.Param(pk, pv)
}
return
}
================================================
FILE: common/sdk/requests/post.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package requests
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
)
func PostJsonBody(url string, v interface{}) (response []byte, err error) {
bs, err := json.Marshal(v)
if err != nil {
return response, err
}
bf := bytes.NewBuffer(bs)
resp, err := http.Post(url, "application/json", bf)
if err != nil {
return response, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}
================================================
FILE: common/sdk/sender/linkedlist.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sender
import (
"container/list"
"sync"
"github.com/open-falcon/falcon-plus/common/model"
)
type SafeLinkedList struct {
sync.RWMutex
L *list.List
}
func NewSafeLinkedList() *SafeLinkedList {
return &SafeLinkedList{L: list.New()}
}
func (this *SafeLinkedList) PopBack(limit int) []*model.JsonMetaData {
this.RLock()
defer this.RUnlock()
sz := this.L.Len()
if sz == 0 {
return []*model.JsonMetaData{}
}
if sz < limit {
limit = sz
}
ret := make([]*model.JsonMetaData, 0, limit)
for i := 0; i < limit; i++ {
e := this.L.Back()
ret = append(ret, e.Value.(*model.JsonMetaData))
this.L.Remove(e)
}
return ret
}
func (this *SafeLinkedList) PushFront(v interface{}) *list.Element {
this.Lock()
defer this.Unlock()
return this.L.PushFront(v)
}
func (this *SafeLinkedList) Front() *list.Element {
this.RLock()
defer this.RUnlock()
return this.L.Front()
}
func (this *SafeLinkedList) Len() int {
this.RLock()
defer this.RUnlock()
return this.L.Len()
}
================================================
FILE: common/sdk/sender/make.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sender
import (
"time"
"github.com/open-falcon/falcon-plus/common/model"
)
func MakeMetaData(endpoint, metric, tags string, val interface{}, counterType string, step_and_ts ...int64) *model.JsonMetaData {
md := model.JsonMetaData{
Endpoint: endpoint,
Metric: metric,
Tags: tags,
Value: val,
CounterType: counterType,
}
argc := len(step_and_ts)
if argc == 0 {
md.Step = 60
md.Timestamp = time.Now().Unix()
} else if argc == 1 {
md.Step = step_and_ts[0]
md.Timestamp = time.Now().Unix()
} else if argc == 2 {
md.Step = step_and_ts[0]
md.Timestamp = step_and_ts[1]
}
return &md
}
func MakeGaugeValue(endpoint, metric, tags string, val interface{}, step_and_ts ...int64) *model.JsonMetaData {
return MakeMetaData(endpoint, metric, tags, val, "GAUGE", step_and_ts...)
}
func MakeCounterValue(endpoint, metric, tags string, val interface{}, step_and_ts ...int64) *model.JsonMetaData {
return MakeMetaData(endpoint, metric, tags, val, "COUNTER", step_and_ts...)
}
func PushGauge(endpoint, metric, tags string, val interface{}, step_and_ts ...int64) {
md := MakeGaugeValue(endpoint, metric, tags, val, step_and_ts...)
MetaDataQueue.PushFront(md)
}
func PushCounter(endpoint, metric, tags string, val interface{}, step_and_ts ...int64) {
md := MakeCounterValue(endpoint, metric, tags, val, step_and_ts...)
MetaDataQueue.PushFront(md)
}
func Push(endpoint, metric, tags string, val interface{}, counterType string, step_and_ts ...int64) {
md := MakeMetaData(endpoint, metric, tags, val, counterType, step_and_ts...)
MetaDataQueue.PushFront(md)
}
================================================
FILE: common/sdk/sender/push.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sender
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"github.com/open-falcon/falcon-plus/common/model"
)
func PostPush(L []*model.JsonMetaData) error {
bs, err := json.Marshal(L)
if err != nil {
return err
}
bf := bytes.NewBuffer(bs)
resp, err := http.Post(PostPushUrl, "application/json", bf)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
content := string(body)
if resp.StatusCode != 200 {
return fmt.Errorf("status code %d != 200, response: %s", resp.StatusCode, content)
}
if Debug {
log.Println("[D] response:", content)
}
return nil
}
================================================
FILE: common/sdk/sender/sender.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sender
import (
"log"
"time"
)
const LIMIT = 200
var MetaDataQueue = NewSafeLinkedList()
var PostPushUrl string
var Debug bool
func StartSender() {
go startSender()
}
func startSender() {
for {
L := MetaDataQueue.PopBack(LIMIT)
if len(L) == 0 {
time.Sleep(time.Millisecond * 200)
continue
}
err := PostPush(L)
if err != nil {
log.Println("[E] push to transfer fail", err)
}
}
}
================================================
FILE: common/utils/counter.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"fmt"
)
func Counter(metric string, tags map[string]string) string {
if tags == nil || len(tags) == 0 {
return metric
}
return fmt.Sprintf("%s/%s", metric, SortedTags(tags))
}
================================================
FILE: common/utils/date.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"time"
)
func UnixTsFormat(ts int64) string {
return time.Unix(ts, 0).Format("2006-01-02 15:04:05")
}
================================================
FILE: common/utils/formatter.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"strconv"
"strings"
)
func ReadableFloat(raw float64) string {
val := strconv.FormatFloat(raw, 'f', 5, 64)
if strings.Contains(val, ".") {
val = strings.TrimRight(val, "0")
val = strings.TrimRight(val, ".")
}
return val
}
================================================
FILE: common/utils/func.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"bytes"
"math/rand"
"strconv"
"time"
)
func PK(endpoint, metric string, tags map[string]string) string {
ret := bufferPool.Get().(*bytes.Buffer)
ret.Reset()
defer bufferPool.Put(ret)
if tags == nil || len(tags) == 0 {
ret.WriteString(endpoint)
ret.WriteString("/")
ret.WriteString(metric)
return ret.String()
}
ret.WriteString(endpoint)
ret.WriteString("/")
ret.WriteString(metric)
ret.WriteString("/")
ret.WriteString(SortedTags(tags))
return ret.String()
}
func PK2(endpoint, counter string) string {
ret := bufferPool.Get().(*bytes.Buffer)
ret.Reset()
defer bufferPool.Put(ret)
ret.WriteString(endpoint)
ret.WriteString("/")
ret.WriteString(counter)
return ret.String()
}
func UUID(endpoint, metric string, tags map[string]string, dstype string, step int) string {
ret := bufferPool.Get().(*bytes.Buffer)
ret.Reset()
defer bufferPool.Put(ret)
if tags == nil || len(tags) == 0 {
ret.WriteString(endpoint)
ret.WriteString("/")
ret.WriteString(metric)
ret.WriteString("/")
ret.WriteString(dstype)
ret.WriteString("/")
ret.WriteString(strconv.Itoa(step))
return ret.String()
}
ret.WriteString(endpoint)
ret.WriteString("/")
ret.WriteString(metric)
ret.WriteString("/")
ret.WriteString(SortedTags(tags))
ret.WriteString("/")
ret.WriteString(dstype)
ret.WriteString("/")
ret.WriteString(strconv.Itoa(step))
return ret.String()
}
func Checksum(endpoint string, metric string, tags map[string]string) string {
pk := PK(endpoint, metric, tags)
return Md5(pk)
}
func ChecksumOfUUID(endpoint, metric string, tags map[string]string, dstype string, step int64) string {
return Md5(UUID(endpoint, metric, tags, dstype, int(step)))
}
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
func RandString(l int) string {
bytes := make([]byte, l)
for i := 0; i < l; i++ {
bytes[i] = byte(RandInt(65, 90))
}
return string(bytes)
}
func RandInt(min int, max int) int {
return min + rand.Intn(max-min)
}
================================================
FILE: common/utils/func_test.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"fmt"
"testing"
)
func origPK(endpoint, metric string, tags map[string]string) string {
if tags == nil || len(tags) == 0 {
return fmt.Sprintf("%s/%s", endpoint, metric)
}
return fmt.Sprintf("%s/%s/%s", endpoint, metric, SortedTags(tags))
}
func origPK2(endpoint, counter string) string {
return fmt.Sprintf("%s/%s", endpoint, counter)
}
func origUUID(endpoint, metric string, tags map[string]string, dstype string, step int) string {
if tags == nil || len(tags) == 0 {
return fmt.Sprintf("%s/%s/%s/%d", endpoint, metric, dstype, step)
}
return fmt.Sprintf("%s/%s/%s/%s/%d", endpoint, metric, SortedTags(tags), dstype, step)
}
var pkCase = []struct {
endpoint string
metric string
tags map[string]string
except string
}{
{"endpoint1", "metric1", nil, "endpoint1/metric1"},
{"endpoint1", "metric1", map[string]string{}, "endpoint1/metric1"},
{"endpoint1", "metric1", map[string]string{"k1": "v1", "k2": "v2"}, "endpoint1/metric1/k1=v1,k2=v2"},
{"endpoint1", "metric1", map[string]string{"k2": "v2", "k1": "v1"}, "endpoint1/metric1/k1=v1,k2=v2"},
}
var pk2Case = []struct {
endpoint string
counter string
except string
}{
{"endpoint1", "counter1", "endpoint1/counter1"},
}
var uuidCase = []struct {
endpoint string
metric string
tags map[string]string
dstype string
step int
except string
}{
{"endpoint1", "metric1", nil, "ds", 10, "endpoint1/metric1/ds/10"},
{"endpoint1", "metric1", map[string]string{}, "ds", 10, "endpoint1/metric1/ds/10"},
{"endpoint1", "metric1", map[string]string{"k1": "v1", "k2": "v2"}, "ds", 10, "endpoint1/metric1/k1=v1,k2=v2/ds/10"},
{"endpoint1", "metric1", map[string]string{"k2": "v2", "k1": "v1"}, "ds", 10, "endpoint1/metric1/k1=v1,k2=v2/ds/10"},
}
func Test_PK(t *testing.T) {
for _, pk := range pkCase {
if PK(pk.endpoint, pk.metric, pk.tags) != origPK(pk.endpoint, pk.metric, pk.tags) || PK(pk.endpoint, pk.metric, pk.tags) != pk.except {
t.Error("not except")
}
}
}
func Test_PK2(t *testing.T) {
for _, pk2 := range pk2Case {
if PK2(pk2.endpoint, pk2.counter) != origPK2(pk2.endpoint, pk2.counter) || PK2(pk2.endpoint, pk2.counter) != pk2.except {
t.Error("not except")
}
}
}
func Test_UUID(t *testing.T) {
for _, uuid := range uuidCase {
if UUID(uuid.endpoint, uuid.metric, uuid.tags, uuid.dstype, uuid.step) != origUUID(uuid.endpoint, uuid.metric, uuid.tags, uuid.dstype, uuid.step) ||
UUID(uuid.endpoint, uuid.metric, uuid.tags, uuid.dstype, uuid.step) != uuid.except {
t.Error("not except")
}
}
}
var (
testTags = map[string]string{"k1": "v1", "k2": "v2"}
)
func Benchmark_PK(b *testing.B) {
for i := 0; i < b.N; i++ {
PK("endpoint1", "metric1", testTags)
}
}
func Benchmark_PK_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origPK("endpoint1", "metric1", testTags)
}
}
func Benchmark_PK2(b *testing.B) {
for i := 0; i < b.N; i++ {
PK2("endpoint1", "counter1")
}
}
func Benchmark_PK2_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origPK2("endpoint1", "counter1")
}
}
func Benchmark_UUID(b *testing.B) {
for i := 0; i < b.N; i++ {
UUID("endpoint1", "metric1", testTags, "dt", 10)
}
}
func Benchmark_UUID_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origUUID("endpoint1", "metric1", testTags, "dt", 10)
}
}
================================================
FILE: common/utils/map.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"sort"
)
// TODO 以下的部分, 考虑放到公共组件库
func KeysOfMap(m map[string]string) []string {
keys := make(sort.StringSlice, len(m))
i := 0
for key := range m {
keys[i] = key
i++
}
keys.Sort()
return []string(keys)
}
================================================
FILE: common/utils/md5.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"crypto/md5"
"encoding/hex"
)
func Md5(raw string) string {
h := md5.Sum([]byte(raw))
return hex.EncodeToString(h[:])
}
================================================
FILE: common/utils/md5_test.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"crypto/md5"
"fmt"
"io"
"testing"
)
func origMd5(raw string) string {
h := md5.New()
io.WriteString(h, raw)
return fmt.Sprintf("%x", h.Sum(nil))
}
func Test_Md5(t *testing.T) {
if Md5("1234567890123") != origMd5("1234567890123") {
t.Error("not expect")
}
}
func Benchmark_Md5(b *testing.B) {
for i := 0; i < b.N; i++ {
Md5("1234567890123")
}
}
func Benchmark_Md5_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origMd5("1234567890123")
}
}
================================================
FILE: common/utils/objpool.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"bytes"
"sync"
)
var bufferPool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}
================================================
FILE: common/utils/statistics.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import "math"
func ComputeMean(values []float64) float64 {
var sum float64
for _, value := range values {
sum = sum + value
}
return (sum / float64(len(values)))
}
func ComputeStdDeviation(values []float64) float64 {
var (
mean float64
vp []float64
stdDiv, temp float64
)
vp = make([]float64, len(values))
/*Calculate mean of the data points*/
mean = ComputeMean(values)
/*Calculate standard deviation of individual data points*/
for i, v := range values {
temp = v - mean
vp[i] = (temp * temp)
}
/* Finally, Compute standard Deviation of data points
* by taking mean of individual std. Deviation.
*/
stdDiv = ComputeMean(vp)
return float64(math.Sqrt(float64(stdDiv)))
}
================================================
FILE: common/utils/tags.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"bytes"
"fmt"
"sort"
"strings"
)
func SortedTags(tags map[string]string) string {
if tags == nil {
return ""
}
size := len(tags)
if size == 0 {
return ""
}
ret := bufferPool.Get().(*bytes.Buffer)
ret.Reset()
defer bufferPool.Put(ret)
if size == 1 {
for k, v := range tags {
ret.WriteString(k)
ret.WriteString("=")
ret.WriteString(v)
}
return ret.String()
}
keys := make([]string, size)
i := 0
for k := range tags {
keys[i] = k
i++
}
sort.Strings(keys)
for j, key := range keys {
ret.WriteString(key)
ret.WriteString("=")
ret.WriteString(tags[key])
if j != size-1 {
ret.WriteString(",")
}
}
return ret.String()
}
func DictedTagstring(s string) map[string]string {
if s == "" {
return map[string]string{}
}
if strings.ContainsRune(s, ' ') {
s = strings.Replace(s, " ", "", -1)
}
tag_dict := make(map[string]string)
tags := strings.Split(s, ",")
for _, tag := range tags {
idx := strings.IndexRune(tag, '=')
if idx != -1 {
tag_dict[tag[:idx]] = tag[idx+1:]
}
}
return tag_dict
}
func SplitTagsString(s string) (err error, tags map[string]string) {
err = nil
tags = make(map[string]string)
s = strings.Replace(s, " ", "", -1)
if s == "" {
return
}
tagSlice := strings.Split(s, ",")
for _, tag := range tagSlice {
tag_pair := strings.SplitN(tag, "=", 2)
if len(tag_pair) == 2 {
tags[tag_pair[0]] = tag_pair[1]
} else {
err = fmt.Errorf("bad tag %s", tag)
return
}
}
return
}
================================================
FILE: common/utils/tags_test.go
================================================
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"fmt"
"sort"
"strings"
"testing"
)
var testCases4map2string = []struct {
tags map[string]string
expect string
}{
{map[string]string{"1": "1"}, "1=1"},
{map[string]string{"1": "1", "2": "2"}, "1=1,2=2"},
{map[string]string{"1": "1", "2": "2", "0": "0"}, "0=0,1=1,2=2"},
}
var testCases4string2map = []struct {
tags string
expect map[string]string
}{
{"1=1", map[string]string{"1": "1"}},
{"1=1,2=2", map[string]string{"1": "1", "2": "2"}},
{"0=0,1=1,2=2", map[string]string{"1": "1", "2": "2", "0": "0"}},
{"0,1=1,2=2", map[string]string{"1": "1", "2": "2"}},
{"0=,1=1,2=2", map[string]string{"0": "", "1": "1", "2": "2"}},
{"=0,1=1,2=2", map[string]string{"": "0", "1": "1", "2": "2"}},
{"0=0, 1=1, 2=2", map[string]string{"0": "0", "1": "1", "2": "2"}},
}
func origSortedTags(tags map[string]string) string {
if tags == nil {
return ""
}
size := len(tags)
if size == 0 {
return ""
}
if size == 1 {
for k, v := range tags {
return fmt.Sprintf("%s=%s", k, v)
}
}
keys := make([]string, size)
i := 0
for k := range tags {
keys[i] = k
i++
}
sort.Strings(keys)
ret := make([]string, size)
for j, key := range keys {
ret[j] = fmt.Sprintf("%s=%s", key, tags[key])
}
return strings.Join(ret, ",")
}
func origDictedTagstring(s string) map[string]string {
if s == "" {
return map[string]string{}
}
s = strings.Replace(s, " ", "", -1)
tag_dict := make(map[string]string)
tags := strings.Split(s, ",")
for _, tag := range tags {
tag_pair := strings.SplitN(tag, "=", 2)
if len(tag_pair) == 2 {
tag_dict[tag_pair[0]] = tag_pair[1]
}
}
return tag_dict
}
func Test_SortedTags(t *testing.T) {
for _, testCase := range testCases4map2string {
if r := SortedTags(testCase.tags); r != testCase.expect || SortedTags(testCase.tags) != origSortedTags(testCase.tags) {
t.Errorf("expect %v, got %v\n", testCase.expect, r)
}
}
}
func Test_DictedTagstring(t *testing.T) {
for _, testCase := range testCases4string2map {
r := DictedTagstring(testCase.tags)
origR := origDictedTagstring(testCase.tags)
if len(r) != len(testCase.expect) || len(r) != len(origR) {
t.FailNow()
}
for k, v := range r {
if expectV, exist := testCase.expect[k]; !exist || v != expectV || v != origR[k] {
t.Errorf("expect %v, got %v\n", testCase.expect, r)
}
}
}
}
func Benchmark_SortedTags_1pair(b *testing.B) {
for i := 0; i < b.N; i++ {
SortedTags(map[string]string{"1": "1"})
}
}
func Benchmark_SortedTags_1pair_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origSortedTags(map[string]string{"1": "1"})
}
}
func Benchmark_SortedTags_2pairs(b *testing.B) {
for i := 0; i < b.N; i++ {
SortedTags(map[string]string{"1": "1", "2": "2"})
}
}
func Benchmark_SortedTags_2pairs_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origSortedTags(map[string]string{"1": "1", "2": "2"})
}
}
func Benchmark_SortedTags_3pairs(b *testing.B) {
for i := 0; i < b.N; i++ {
SortedTags(map[string]string{"1": "1", "2": "2", "3": "3"})
}
}
func Benchmark_SortedTags_3pairs_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origSortedTags(map[string]string{"1": "1", "2": "2", "3": "3"})
}
}
func Benchmark_SortedTags_4pairs(b *testing.B) {
for i := 0; i < b.N; i++ {
SortedTags(map[string]string{"1": "1", "2": "2", "3": "3", "4": "4"})
}
}
func Benchmark_SortedTags_4pairs_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origSortedTags(map[string]string{"1": "1", "2": "2", "3": "3", "4": "4"})
}
}
func Benchmark_SortedTags_5pairs(b *testing.B) {
for i := 0; i < b.N; i++ {
SortedTags(map[string]string{"1": "1", "2": "2", "3": "3", "4": "4", "5": "5"})
}
}
func Benchmark_SortedTags_5pairs_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origSortedTags(map[string]string{"1": "1", "2": "2", "3": "3", "4": "4", "5": "5"})
}
}
func Benchmark_SortedTags_6pairs(b *testing.B) {
for i := 0; i < b.N; i++ {
SortedTags(map[string]string{"1": "1", "2": "2", "3": "3", "4": "4", "5": "5", "0": "0"})
}
}
func Benchmark_SortedTags_6pairs_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origSortedTags(map[string]string{"1": "1", "2": "2", "3": "3", "4": "4", "5": "5", "0": "0"})
}
}
func Benchmark_DictedTagstring_1pair(b *testing.B) {
for i := 0; i < b.N; i++ {
DictedTagstring("1=1")
}
}
func Benchmark_DictedTagstring_1pair_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origDictedTagstring("1=1")
}
}
func Benchmark_DictedTagstring_2pairs(b *testing.B) {
for i := 0; i < b.N; i++ {
DictedTagstring("1=1,2=2")
}
}
func Benchmark_DictedTagstring_2pairs_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origDictedTagstring("1=1,2=2")
}
}
func Benchmark_DictedTagstring_3pairs(b *testing.B) {
for i := 0; i < b.N; i++ {
DictedTagstring("1=1,2=2,3=3")
}
}
func Benchmark_DictedTagstring_3pairs_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origDictedTagstring("1=1,2=2,3=3")
}
}
func Benchmark_DictedTagstring_4pairs(b *testing.B) {
for i := 0; i < b.N; i++ {
DictedTagstring("1=1,2=2,3=3,4=4")
}
}
func Benchmark_DictedTagstring_4pairs_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origDictedTagstring("1=1,2=2,3=3,4=4")
}
}
func Benchmark_DictedTagstring_5pairs(b *testing.B) {
for i := 0; i < b.N; i++ {
DictedTagstring("1=1,2=2,3=3,4=4,5=5")
}
}
func Benchmark_DictedTagstring_5pairs_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origDictedTagstring("1=1,2=2,3=3,4=4,5=5")
}
}
func Benchmark_DictedTagstring_6pairs(b *testing.B) {
for i := 0; i < b.N; i++ {
DictedTagstring("1=1,2=2,3=3,4=4,5=5,6=6")
}
}
func Benchmark_DictedTagstring_6pairs_orig(b *testing.B) {
for i := 0; i < b.N; i++ {
origDictedTagstring("1=1,2=2,3=3,4=4,5=5,6=6")
}
}
================================================
FILE: config/agent.json
================================================
{
"debug": true,
"hostname": "%%AGENT_HOSTNAME%%",
"ip": "",
"plugin": {
"enabled": false,
"dir": "./plugin",
"git": "https://github.com/open-falcon/plugin.git",
"logs": "./logs"
},
"heartbeat": {
"enabled": true,
"addr": "%%HBS_RPC%%",
"interval": 60,
"timeout": 1000
},
"transfer": {
"enabled": true,
"addrs": [
"%%TRANSFER_RPC%%"
],
"interval": 60,
"timeout": 1000
},
"http": {
"enabled": true,
"listen": ":1988",
"backdoor": false
},
"collector": {
"ifacePrefix": ["eth", "em"],
"mountPoint": []
},
"default_tags": {
},
"ignore": {
"cpu.busy": true,
"df.bytes.free": true,
"df.bytes.total": true,
"df.bytes.used": true,
"df.bytes.used.percent": true,
"df.inodes.total": true,
"df.inodes.free": true,
"df.inodes.used": true,
"df.inodes.used.percent": true,
"mem.memtotal": true,
"mem.memused": true,
"mem.memused.percent": true,
"mem.memfree": true,
"mem.swaptotal": true,
"mem.swapused": true,
"mem.swapfree": true
}
}
================================================
FILE: config/aggregator.json
================================================
{
"debug": true,
"http": {
"enabled": true,
"listen": "%%AGGREGATOR_HTTP%%"
},
"database": {
"addr": "%%MYSQL%%/falcon_portal?loc=Local&parseTime=true",
"idle": 10,
"ids": [1, -1],
"interval": 55
},
"api": {
"connect_timeout": 500,
"request_timeout": 2000,
"plus_api": "http://127.0.0.1:8080",
"plus_api_token": "%%PLUS_API_DEFAULT_TOKEN%%",
"push_api": "http://127.0.0.1:1988/v1/push"
}
}
================================================
FILE: config/alarm.json
================================================
{
"log_level": "debug",
"http": {
"enabled": true,
"listen": "0.0.0.0:9912"
},
"redis": {
"addr": "%%REDIS%%",
"maxIdle": 5,
"highQueues": [
"event:p0",
"event:p1",
"event:p2"
],
"lowQueues": [
"event:p3",
"event:p4",
"event:p5",
"event:p6"
],
"userIMQueue": "/queue/user/im",
"userSmsQueue": "/queue/user/sms",
"userMailQueue": "/queue/user/mail"
},
"api": {
"im": "http://127.0.0.1:10086/wechat",
"sms": "http://127.0.0.1:10086/sms",
"mail": "http://127.0.0.1:10086/mail",
"dashboard": "http://127.0.0.1:8081",
"plus_api":"http://127.0.0.1:8080",
"plus_api_token": "%%PLUS_API_DEFAULT_TOKEN%%"
},
"falcon_portal": {
"addr": "%%MYSQL%%/alarms?charset=utf8&loc=Local",
"idle": 10,
"max": 100
},
"worker": {
"im": 10,
"sms": 10,
"mail": 50
},
"housekeeper": {
"event_retention_days": 7,
"event_delete_batch": 100
}
}
================================================
FILE: config/api.json
================================================
{
"log_level": "debug",
"db": {
"falcon_portal": "%%MYSQL%%/falcon_portal?charset=utf8&parseTime=True&loc=Local",
"graph": "%%MYSQL%%/graph?charset=utf8&parseTime=True&loc=Local",
"uic": "%%MYSQL%%/uic?charset=utf8&parseTime=True&loc=Local",
"dashboard": "%%MYSQL%%/dashboard?charset=utf8&parseTime=True&loc=Local",
"alarms": "%%MYSQL%%/alarms?charset=utf8&parseTime=True&loc=Local",
"db_bug": true
},
"graphs": {
"cluster": {
"graph-00": "%%GRAPH_RPC%%"
},
"max_conns": 100,
"max_idle": 100,
"conn_timeout": 1000,
"call_timeout": 5000,
"numberOfReplicas": 500
},
"metric_list_file": "./api/data/metric",
"web_port": "%%PLUS_API_HTTP%%",
"access_control": true,
"signup_disable": false,
"salt": "",
"skip_auth": false,
"default_token": "%%PLUS_API_DEFAULT_TOKEN%%",
"gen_doc": false,
"gen_doc_path": "doc/module.html"
}
================================================
FILE: config/confgen.sh
================================================
#!/bin/bash
confs=(
'%%AGENT_HTTP%%=0.0.0.0:1988'
'%%AGGREGATOR_HTTP%%=0.0.0.0:6055'
'%%GRAPH_HTTP%%=0.0.0.0:6071'
'%%GRAPH_RPC%%=0.0.0.0:6070'
'%%HBS_HTTP%%=0.0.0.0:6031'
'%%HBS_RPC%%=0.0.0.0:6030'
'%%JUDGE_HTTP%%=0.0.0.0:6081'
'%%JUDGE_RPC%%=0.0.0.0:6080'
'%%NODATA_HTTP%%=0.0.0.0:6090'
'%%TRANSFER_HTTP%%=0.0.0.0:6060'
'%%TRANSFER_RPC%%=0.0.0.0:8433'
'%%REDIS%%=127.0.0.1:6379'
'%%MYSQL%%=root:@tcp(127.0.0.1:3306)'
'%%PLUS_API_DEFAULT_TOKEN%%=default-token-used-in-server-side'
'%%PLUS_API_HTTP%%=0.0.0.0:8080'
'%%AGENT_HOSTNAME%%='
)
configurer() {
for i in "${confs[@]}"
do
search="${i%%=*}"
replace="${i##*=}"
uname=`uname`
if [ "$uname" == "Darwin" ] ; then
# Note the "" and -e after -i, needed in OS X
find ./out/*/config/*.json -type f -exec sed -i .tpl -e "s/${search}/${replace}/g" {} \;
else
find ./out/*/config/*.json -type f -exec sed -i "s/${search}/${replace}/g" {} \;
fi
done
}
configurer
================================================
FILE: config/falcon2p8s.json
================================================
{
"log_level": "debug",
"concurrent": 100,
"http": {
"listen": "0.0.0.0:9090"
},
"rpc": {
"listen": "0.0.0.0:8080"
}
}
================================================
FILE: config/gateway.json
================================================
{
"debug": true,
"minStep": 30,
"http": {
"enabled": true,
"listen": "0.0.0.0:16060"
},
"rpc": {
"enabled": true,
"listen": "0.0.0.0:18433"
},
"socket": {
"enabled": true,
"listen": "0.0.0.0:14444",
"timeout": 3600
},
"judge": {
"enabled": false,
"batch": 200,
"connTimeout": 1000,
"callTimeout": 5000,
"maxConns": 32,
"maxIdle": 32,
"replicas": 500,
"cluster": {
"judge-00" : "%%JUDGE_RPC%%"
}
},
"graph": {
"enabled": false,
"batch": 200,
"connTimeout": 1000,
"callTimeout": 5000,
"maxConns": 32,
"maxIdle": 32,
"replicas": 500,
"cluster": {
"graph-00" : "%%GRAPH_RPC%%"
}
},
"tsdb": {
"enabled": false,
"batch": 200,
"connTimeout": 1000,
"callTimeout": 5000,
"maxConns": 32,
"maxIdle": 32,
"retry": 3,
"address": "127.0.0.1:8088"
},
"transfer": {
"enabled": true,
"batch": 200,
"connTimeout": 1000,
"callTimeout": 5000,
"maxConns": 32,
"maxIdle": 32,
"retry": 3,
"cluster": {
"t1": "%%TRANSFER_RPC%%"
}
},
"influxdb": {
"enabled": false,
"batch": 200,
"retry": 3,
"maxConns": 32,
"username": "admin",
"password": "123456",
"precision": "s",
"db": "foo",
"address": "http://127.0.0.1:8086",
"timeout": 5000
}
}
================================================
FILE: config/graph.json
================================================
{
"debug": false,
"http": {
"enabled": true,
"listen": "%%GRAPH_HTTP%%"
},
"rpc": {
"enabled": true,
"listen": "%%GRAPH_RPC%%"
},
"rrd": {
"storage": "./data/6070"
},
"db": {
"dsn": "%%MYSQL%%/graph?loc=Local&parseTime=true",
"maxIdle": 4
},
"callTimeout": 5000,
"ioWorkerNum": 64,
"migrate": {
"enabled": false,
"concurrency": 2,
"replicas": 500,
"cluster": {
"graph-00" : "127.0.0.1:6070"
}
}
}
================================================
FILE: config/hbs.json
================================================
{
"debug": true,
"database": "%%MYSQL%%/falcon_portal?loc=Local&parseTime=true",
"hosts": "",
"maxConns": 20,
"maxIdle": 15,
"listen": ":6030",
"trustable": [""],
"http": {
"enabled": true,
"listen": "%%HBS_HTTP%%"
}
}
================================================
FILE: config/judge.json
================================================
{
"debug": true,
"debugHost": "nil",
"remain": 11,
"http": {
"enabled": true,
"listen": "%%JUDGE_HTTP%%"
},
"rpc": {
"enabled": true,
"listen": "%%JUDGE_RPC%%"
},
"hbs": {
"servers": ["%%HBS_RPC%%"],
"timeout": 300,
"interval": 60
},
"alarm": {
"enabled": true,
"minInterval": 300,
"queuePattern": "event:p%v",
"redis": {
"dsn": "%%REDIS%%",
"maxIdle": 5,
"connTimeout": 5000,
"readTimeout": 5000,
"writeTimeout": 5000
}
}
}
================================================
FILE: config/nodata.json
================================================
{
"debug": true,
"http": {
"enabled": true,
"listen": "%%NODATA_HTTP%%"
},
"plus_api":{
"connectTimeout": 500,
"requestTimeout": 2000,
"addr": "http://127.0.0.1:8080",
"token": "default-token-used-in-server-side"
},
"config": {
"enabled": true,
"dsn": "%%MYSQL%%/falcon_portal?loc=Local&parseTime=true&wait_timeout=604800",
"maxIdle": 4
},
"collector":{
"enabled": true,
"batch": 200,
"concurrent": 10
},
"sender":{
"enabled": true,
"connectTimeout": 500,
"requestTimeout": 2000,
"transferAddr": "%%TRANSFER_HTTP%%",
"batch": 500
}
}
================================================
FILE: config/transfer.json
================================================
{
"debug": true,
"minStep": 30,
"http": {
"enabled": true,
"listen": "%%TRANSFER_HTTP%%"
},
"rpc": {
"enabled": true,
"listen": "%%TRANSFER_RPC%%"
},
"socket": {
"enabled": true,
"listen": "0.0.0.0:4444",
"timeout": 3600
},
"judge": {
"enabled": true,
"batch": 200,
"connTimeout": 1000,
"callTimeout": 5000,
"maxConns": 32,
"maxIdle": 32,
"replicas": 500,
"cluster": {
"judge-00" : "%%JUDGE_RPC%%"
}
},
"graph": {
"enabled": true,
"batch": 200,
"connTimeout": 1000,
"callTimeout": 5000,
"maxConns": 32,
"maxIdle": 32,
"replicas": 500,
"cluster": {
"graph-00" : "%%GRAPH_RPC%%"
}
},
"tsdb": {
"enabled": false,
"batch": 200,
"connTimeout": 1000,
"callTimeout": 5000,
"maxConns": 32,
"maxIdle": 32,
"retry": 3,
"address": "127.0.0.1:8088"
},
"transfer": {
"enabled": false,
"batch": 200,
"connTimeout": 1000,
"callTimeout": 5000,
"maxConns": 32,
"maxIdle": 32,
"retry": 3,
"cluster": {
"t1": "127.0.0.1:8433"
}
},
"influxdb": {
"enabled": false,
"batch": 200,
"retry": 3,
"maxConns": 32,
"username": "admin",
"password": "123456",
"precision": "s",
"db": "foo",
"address": "http://127.0.0.1:8086",
"timeout": 5000
},
"p8s_relay": {
"enabled": false,
"batch": 200,
"connTimeout": 1000,
"callTimeout": 5000,
"maxConns": 32,
"maxIdle": 32,
"replicas": 500,
"notSyncMetrics": [
"gpu.",
"snmp."
],
"cluster": {
"p8s-relay-00" : "192.168.1.1:8080",
"p8s-relay-01" : "192.168.1.2:8080"
}
}
}
================================================
FILE: docker/README.md
================================================
## Running open-falcon container
`the latest version in docker hub is v0.3`
##### 1. Start mysql and init the mysql table before the first running
```
## start mysql in container
docker run -itd \
--name falcon-mysql \
-v /home/work/mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=test123456 \
-p 3306:3306 \
mysql:5.7
## init mysql table before the first running
cd /tmp && \
git clone --depth=1 https://github.com/open-falcon/falcon-plus.git && \
cd /tmp/falcon-plus/ && \
for x in `ls ./scripts/mysql/db_schema/*.sql`; do
echo init mysql table $x ...;
docker exec -i falcon-mysql mysql -uroot -ptest123456 < $x;
done
rm -rf /tmp/falcon-plus/
```
##### 2. Start redis in container
```
docker run --name falcon-redis -p6379:6379 -d redis:4-alpine3.8
```
##### 3. Start falcon-plus modules in one container
```
## pull images from hub.docker.com/openfalcon
docker pull openfalcon/falcon-plus:v0.3
## run falcon-plus container
docker run -itd --name falcon-plus \
--link=falcon-mysql:db.falcon \
--link=falcon-redis:redis.falcon \
-p 8433:8433 \
-p 8080:8080 \
-e MYSQL_PORT=root:test123456@tcp\(db.falcon:3306\) \
-e REDIS_PORT=redis.falcon:6379 \
-v /home/work/open-falcon/data:/open-falcon/data \
-v /home/work/open-falcon/logs:/open-falcon/logs \
openfalcon/falcon-plus:v0.3
## start falcon backend modules, such as graph,api,etc.
docker exec falcon-plus sh ctrl.sh start \
graph hbs judge transfer nodata aggregator agent gateway api alarm
## or you can just start/stop/restart specific module as:
docker exec falcon-plus sh ctrl.sh start/stop/restart xxx
## check status of backend modules
docker exec falcon-plus ./open-falcon check
## or you can check logs at /home/work/open-falcon/logs/ in your host
ls -l /home/work/open-falcon/logs/
```
##### 4. Start falcon-dashboard in container
```
docker run -itd --name falcon-dashboard \
-p 8081:8081 \
--link=falcon-mysql:db.falcon \
--link=falcon-plus:api.falcon \
-e API_ADDR=http://api.falcon:8080/api/v1 \
-e PORTAL_DB_HOST=db.falcon \
-e PORTAL_DB_PORT=3306 \
-e PORTAL_DB_USER=root \
-e PORTAL_DB_PASS=test123456 \
-e PORTAL_DB_NAME=falcon_portal \
-e ALARM_DB_HOST=db.falcon \
-e ALARM_DB_PORT=3306 \
-e ALARM_DB_USER=root \
-e ALARM_DB_PASS=test123456 \
-e ALARM_DB_NAME=alarms \
-w /open-falcon/dashboard openfalcon/falcon-dashboard:v0.2.1 \
'./control startfg'
```
##### 5. Start falcon-agent in container
```
sudo docker run -d --restart always --name falcon-agent \
-e NUX_ROOTFS=/rootfs \
-v /:/rootfs:ro \
openfalcon/falcon-plus:v0.3 \
./agent/bin/falcon-agent -c /open-falcon/agent/config/cfg.json
```
----
## Building open-falcon images from source code
##### Building falcon-plus
```
cd /tmp && \
git clone https://github.com/open-falcon/falcon-plus.git && \
cd /tmp/falcon-plus/ && \
docker build -t falcon-plus:v0.3 .
```
##### Building falcon-dashboard
```
cd /tmp && \
git clone https://github.com/open-falcon/dashboard.git && \
cd /tmp/dashboard/ && \
docker build -t falcon-dashboard:v0.2.1 .
```
================================================
FILE: docker/confgen4docker.sh
================================================
#!/bin/bash
confs=(
'%%AGENT_HTTP%%=0.0.0.0:1988'
'%%AGGREGATOR_HTTP%%=0.0.0.0:6055'
'%%GRAPH_HTTP%%=0.0.0.0:6071'
'%%GRAPH_RPC%%=0.0.0.0:6070'
'%%HBS_HTTP%%=0.0.0.0:6031'
'%%HBS_RPC%%=0.0.0.0:6030'
'%%JUDGE_HTTP%%=0.0.0.0:6081'
'%%JUDGE_RPC%%=0.0.0.0:6080'
'%%NODATA_HTTP%%=0.0.0.0:6090'
'%%TRANSFER_HTTP%%=0.0.0.0:6060'
'%%TRANSFER_RPC%%=0.0.0.0:8433'
'%%PLUS_API_DEFAULT_TOKEN%%=default-token-used-in-server-side'
'%%PLUS_API_HTTP%%=0.0.0.0:8080'
'%%AGENT_HOSTNAME%%='
)
configurer() {
for i in "${confs[@]}"
do
search="${i%%=*}"
replace="${i##*=}"
uname=`uname`
if [ "$uname" == "Darwin" ] ; then
# Note the "" and -e after -i, needed in OS X
find ./out/*/config/*.json -type f -exec sed -i .tpl -e "s/${search}/${replace}/g" {} \;
else
find ./out/*/config/*.json -type f -exec sed -i "s/${search}/${replace}/g" {} \;
fi
done
}
configurer
================================================
FILE: docker/ctrl.sh
================================================
#!/bin/sh
DOCKER_DIR=/open-falcon
of_bin=$DOCKER_DIR/open-falcon
DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')
# Search $1 and replace with $2 or $3(defualt)
replace() {
replacement=$2
if [ -z "$replacement" ]; then
replacement=$3
fi
find $DOCKER_DIR/*/config/*.json -type f -exec sed -i "s/$1/$replacement/g" {} \;
}
replace "%%MYSQL%%" "$MYSQL_PORT" "$DOCKER_HOST_IP:3306"
replace "%%REDIS%%" "$REDIS_PORT" "$DOCKER_HOST_IP:6379"
replace "%%AGGREGATOR_HTTP%%" "$AGGREGATOR_HTTP" "0.0.0.0:6055"
replace "%%GRAPH_HTTP%%" "$GRAPH_HTTP" "0.0.0.0:6071"
replace "%%GRAPH_RPC%%" "$GRAPH_RPC" "0.0.0.0:6070"
replace "%%HBS_HTTP%%" "$HBS_HTTP" "0.0.0.0:6031"
replace "%%HBS_RPC%%" "$HBS_RPC" "0.0.0.0:6030"
replace "%%JUDGE_HTTP%%" "$JUDGE_HTTP" "0.0.0.0:6081"
replace "%%JUDGE_RPC%%" "$JUDGE_RPC" "0.0.0.0:6080"
replace "%%NODATA_HTTP%%" "$NODATA_HTTP" "0.0.0.0:6090"
replace "%%TRANSFER_HTTP%%" "$TRANSFER_HTTP" "0.0.0.0:6060"
replace "%%TRANSFER_RPC%%" "$TRANSFER_RPC" "0.0.0.0:8433"
replace "%%PLUS_API_HTTP%%" "$PLUS_API_HTTP" "0.0.0.0:8080"
replace "%%AGENT_HOSTNAME%%" "$AGENT_HOSTNAME" ""
#use absolute path of metric_list_file in docker
TAB=$'\t'; sed -i "s|.*metric_list_file.*|${TAB}\"metric_list_file\": \"$DOCKER_DIR/api/data/metric\",|g" $DOCKER_DIR/api/config/*.json;
action=$1
module_name=$2
case $action in
run)
$DOCKER_DIR/"$module_name"/bin/falcon-"$module_name" -c /open-falcon/"$module_name"/config/cfg.json
;;
*)
supervisorctl $*
;;
esac
================================================
FILE: docker/k8s-cluster/Dockerfile.tpl
================================================
FROM alpine:3.7
LABEL maintainer tabsp@qq.com
USER root
ENV FALCON_DIR=/open-falcon
# agent
RUN apk add --no-cache ca-certificates git curl
# alarm
ADD https://github.com/golang/go/raw/master/lib/time/zoneinfo.zip /usr/local/go/lib/time/zoneinfo.zip
COPY build/%%MODULE_NAME%% ${FALCON_DIR}/%%MODULE_NAME%%
WORKDIR ${FALCON_DIR}
CMD ["/open-falcon/%%MODULE_NAME%%/bin/falcon-%%MODULE_NAME%%", "-c", "/open-falcon/%%MODULE_NAME%%/config/cfg.json"]
================================================
FILE: docker/k8s-cluster/README.md
================================================
## 分布式部署 open-falcon 到 k8s 集群
### 构建
克隆源码:
```shell
git clone https://github.com/open-falcon/falcon-plus.git && cd falcon-plus
```
编译源码并构建 Docker 镜像
```shell
./docker/k8s-cluster/build.sh
```
### 部署
注意点:
1. graph 为有状态组件,部署方式为每个节点一个 Deployment,同时 replica 设置为 1
2. 所有配置文件使用挂载目录的方式持久化,可以改为 ConfigMap 管理配置
3. 镜像可以使用构建脚本自己构建后推送到自己的私仓使用(推荐),或者直接使用我构建好的,仓库地址在 docker/k8s-cluster/build.sh 查看或修改
================================================
FILE: docker/k8s-cluster/build.sh
================================================
#!/bin/bash
MODULES=(
'agent'
'aggregator'
'alarm'
'api'
'gateway'
'graph'
'hbs'
'judge'
'nodata'
'transfer'
)
DOCKER_REGISTRY=registry.cn-hangzhou.aliyuncs.com/open-falcon
VERSION=v0.3
clean() {
echo "clean..."
if [ -d "build" ]; then
rm -rf build/
fi
mkdir build
}
build() {
echo "build source..."
if [ `uname -m` == "aarch64" ]; then
BASE_IMAGE=jimmytinsley/makegcc-golang
else
BASE_IMAGE=openfalcon/makegcc-golang:1.10-alpine
fi
docker run -it --rm \
--name build \
-v "$(pwd)":"/go/src/github.com/open-falcon/falcon-plus" \
-w "/go/src/github.com/open-falcon/falcon-plus" \
$BASE_IMAGE \
docker/k8s-cluster/init.sh
}
buildDockerImages() {
echo "build docker images..."
for i in "${MODULES[@]}"; do
echo "build $i"
awk -v module="$i" '{ gsub(/%%MODULE_NAME%%/, module); print $0 }' docker/k8s-cluster/Dockerfile.tpl > docker/k8s-cluster/Dockerfile
docker build -f docker/k8s-cluster/Dockerfile -t $DOCKER_REGISTRY/$i:$VERSION .
rm docker/k8s-cluster/Dockerfile
done
}
clean
build
buildDockerImages
================================================
FILE: docker/k8s-cluster/init.sh
================================================
#!/bin/sh
apk add --no-cache ca-certificates git bash \
&& make all \
&& make pack4docker \
&& tar -zxf open-falcon-v*.tar.gz -C build \
&& rm open-falcon-v*.tar.gz
================================================
FILE: docker/k8s-cluster/modules/falcon-agent.yaml
================================================
apiVersion: v1
kind: Service
metadata:
namespace: open-falcon
name: falcon-agent
labels:
app: open-falcon
spec:
type: ClusterIP
ports:
- name: http
port: 1988
selector:
name: falcon-agent
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: open-falcon
name: falcon-agent
labels:
app: open-falcon
spec:
replicas: 1
template:
metadata:
labels:
name: falcon-agent
spec:
containers:
- name: falcon-agent
image: registry.cn-hangzhou.aliyuncs.com/open-falcon/agent:v0.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 1988
name: http
protocol: TCP
volumeMounts:
- mountPath: /open-falcon/agent/config
name: falcon-agent-config
- mountPath: /etc/localtime
name: tz-config
volumes:
- flexVolume:
driver: alicloud/nas
options:
path: /open-falcon/falcon-agent/config
server: xxx.cn-hangzhou.nas.aliyuncs.com
vers: "4.0"
name: falcon-agent-config
- hostPath:
path: /etc/localtime
type: ''
name: tz-config
================================================
FILE: docker/k8s-cluster/modules/falcon-aggregator.yaml
================================================
apiVersion: v1
kind: Service
metadata:
namespace: open-falcon
name: falcon-aggregator
labels:
app: open-falcon
spec:
type: ClusterIP
ports:
- name: http
port: 6055
selector:
name: falcon-aggregator
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: open-falcon
name: falcon-aggregator
labels:
app: open-falcon
spec:
replicas: 1
template:
metadata:
labels:
name: falcon-aggregator
spec:
containers:
- name: falcon-aggregator
image: registry.cn-hangzhou.aliyuncs.com/open-falcon/aggregator:v0.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6055
name: http
protocol: TCP
volumeMounts:
- mountPath: /open-falcon/aggregator/config
name: falcon-aggregator-config
- mountPath: /etc/localtime
name: tz-config
volumes:
- flexVolume:
driver: alicloud/nas
options:
path: /open-falcon/falcon-aggregator/config
server: xxx.cn-hangzhou.nas.aliyuncs.com
vers: "4.0"
name: falcon-aggregator-config
- hostPath:
path: /etc/localtime
type: ''
name: tz-config
================================================
FILE: docker/k8s-cluster/modules/falcon-alarm.yaml
================================================
apiVersion: v1
kind: Service
metadata:
namespace: open-falcon
name: falcon-alarm
labels:
app: open-falcon
spec:
type: ClusterIP
ports:
- name: http
port: 9912
selector:
name: falcon-alarm
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: open-falcon
name: falcon-alarm
labels:
app: open-falcon
spec:
replicas: 1
template:
metadata:
labels:
name: falcon-alarm
spec:
containers:
- name: falcon-alarm
image: registry.cn-hangzhou.aliyuncs.com/open-falcon/alarm:v0.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9912
name: http
protocol: TCP
volumeMounts:
- mountPath: /open-falcon/alarm/config
name: falcon-alarm-config
- mountPath: /etc/localtime
name: tz-config
volumes:
- flexVolume:
driver: alicloud/nas
options:
path: /open-falcon/falcon-alarm/config
server: xxx.cn-hangzhou.nas.aliyuncs.com
vers: "4.0"
name: falcon-alarm-config
- hostPath:
path: /etc/localtime
type: ''
name: tz-config
================================================
FILE: docker/k8s-cluster/modules/falcon-api.yaml
================================================
apiVersion: v1
kind: Service
metadata:
namespace: open-falcon
name: falcon-api
labels:
app: open-falcon
spec:
type: ClusterIP
ports:
- name: http
port: 8080
selector:
name: falcon-api
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: open-falcon
name: falcon-api
labels:
app: open-falcon
spec:
replicas: 1
template:
metadata:
labels:
name: falcon-api
spec:
containers:
- name: falcon-api
image: registry.cn-hangzhou.aliyuncs.com/open-falcon/api:v0.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: http
protocol: TCP
volumeMounts:
- mountPath: /open-falcon/api/config
name: falcon-api-config
- mountPath: /etc/localtime
name: tz-config
volumes:
- flexVolume:
driver: alicloud/nas
options:
path: /open-falcon/falcon-api/config
server: xxx.cn-hangzhou.nas.aliyuncs.com
vers: "4.0"
name: falcon-api-config
- hostPath:
path: /etc/localtime
type: ''
name: tz-config
================================================
FILE: docker/k8s-cluster/modules/falcon-dashboard.yaml
================================================
apiVersion: v1
kind: Service
metadata:
namespace: open-falcon
name: falcon-dashboard
labels:
app: open-falcon
spec:
type: ClusterIP
ports:
- name: http
port: 8081
selector:
name: falcon-dashboard
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: open-falcon
name: falcon-dashboard
labels:
app: open-falcon
spec:
replicas: 1
template:
metadata:
labels:
name: falcon-dashboard
spec:
containers:
- name: falcon-dashboard
image: openfalcon/falcon-dashboard:v0.2.1
command: ["sh","-c","cd /open-falcon/dashboard && ./control startfg"]
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8081
env:
- name: API_ADDR
value: http://falcon-api:8080/api/v1
- name: PORTAL_DB_HOST
value: 127.0.0.1
- name: PORTAL_DB_PORT
value: "3306"
- name: PORTAL_DB_USER
value: root
- name: PORTAL_DB_PASS
value: xxx
- name: PORTAL_DB_NAME
value: falcon_portal
- name: ALARM_DB_HOST
value: 127.0.0.1
- name: ALARM_DB_PORT
value: "3306"
- name: ALARM_DB_USER
value: root
- name: ALARM_DB_PASS
value: root
- name: ALARM_DB_NAME
value: alarms
volumeMounts:
- mountPath: /etc/localtime
name: tz-config
volumes:
- hostPath:
path: /etc/localtime
type: ''
name: tz-config
================================================
FILE: docker/k8s-cluster/modules/falcon-graph-01.yaml
================================================
apiVersion: v1
kind: Service
metadata:
namespace: open-falcon
name: falcon-graph-01
labels:
app: open-falcon
spec:
type: ClusterIP
ports:
- name: rpc
port: 6070
- name: http
port: 6071
selector:
name: falcon-graph-01
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: open-falcon
name: falcon-graph-01
labels:
app: open-falcon
spec:
replicas: 1
template:
metadata:
labels:
name: falcon-graph-01
spec:
containers:
- name: falcon-graph-01
image: registry.cn-hangzhou.aliyuncs.com/open-falcon/graph:v0.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6070
name: rpc
protocol: TCP
- containerPort: 6071
name: http
protocol: TCP
volumeMounts:
- mountPath: /open-falcon/graph/config
name: falcon-graph-config
- mountPath: /open-falcon/graph/data
name: falcon-graph-data
- mountPath: /etc/localtime
name: tz-config
volumes:
- flexVolume:
driver: alicloud/nas
options:
path: /open-falcon/falcon-graph/01/config
server: xxx.cn-hangzhou.nas.aliyuncs.com
vers: "4.0"
name: falcon-graph-config
- flexVolume:
driver: alicloud/nas
options:
path: /open-falcon/falcon-graph/01/data
server: xxx.cn-hangzhou.nas.aliyuncs.com
vers: "4.0"
name: falcon-graph-data
- hostPath:
path: /etc/localtime
type: ''
name: tz-config
================================================
FILE: docker/k8s-cluster/modules/falcon-hbs.yaml
================================================
apiVersion: v1
kind: Service
metadata:
namespace: open-falcon
name: falcon-hbs
labels:
app: open-falcon
spec:
type: ClusterIP
ports:
- name: rpc
port: 6030
- name: http
port: 6031
selector:
name: falcon-hbs
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: open-falcon
name: falcon-hbs
labels:
app: open-falcon
spec:
replicas: 1
template:
metadata:
labels:
name: falcon-hbs
spec:
containers:
- name: falcon-hbs
image: registry.cn-hangzhou.aliyuncs.com/open-falcon/hbs:v0.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6030
name: rpc
protocol: TCP
- containerPort: 6031
name: http
protocol: TCP
volumeMounts:
- mountPath: /open-falcon/hbs/config
name: falcon-hbs-config
- mountPath: /etc/localtime
name: tz-config
volumes:
- flexVolume:
driver: alicloud/nas
options:
path: /open-falcon/falcon-hbs/config
server: xxx.cn-hangzhou.nas.aliyuncs.com
vers: "4.0"
name: falcon-hbs-config
- hostPath:
path: /etc/localtime
type: ''
name: tz-config
================================================
FILE: docker/k8s-cluster/modules/falcon-judge.yaml
================================================
apiVersion: v1
kind: Service
metadata:
namespace: open-falcon
name: falcon-judge
labels:
app: open-falcon
spec:
type: ClusterIP
ports:
- name: rpc
port: 6080
- name: http
port: 6081
selector:
name: falcon-judge
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: open-falcon
name: falcon-judge
labels:
app: open-falcon
spec:
replicas: 1
template:
metadata:
labels:
name: falcon-judge
spec:
containers:
- name: falcon-judge
image: registry.cn-hangzhou.aliyuncs.com/open-falcon/judge:v0.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6080
name: rpc
protocol: TCP
- containerPort: 6081
name: http
protocol: TCP
volumeMounts:
- mountPath: /open-falcon/judge/config
name: falcon-judge-config
- mountPath: /etc/localtime
name: tz-config
volumes:
- flexVolume:
driver: alicloud/nas
options:
path: /open-falcon/falcon-judge/config
server: xxx.cn-hangzhou.nas.aliyuncs.com
vers: "4.0"
name: falcon-judge-config
- hostPath:
path: /etc/localtime
type: ''
name: tz-config
================================================
FILE: docker/k8s-cluster/modules/falcon-nodata.yaml
================================================
apiVersion: v1
kind: Service
metadata:
namespace: open-falcon
name: falcon-nodata
labels:
app: open-falcon
spec:
type: ClusterIP
ports:
- name: http
port: 6090
selector:
name: falcon-nodata
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: open-falcon
name: falcon-nodata
labels:
app: open-falcon
spec:
replicas: 1
template:
metadata:
labels:
name: falcon-nodata
spec:
containers:
- name: falcon-nodata
image: registry.cn-hangzhou.aliyuncs.com/open-falcon/nodata:v0.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6090
name: http
protocol: TCP
volumeMounts:
- mountPath: /open-falcon/nodata/config
name: falcon-nodata-config
- mountPath: /etc/localtime
name: tz-config
volumes:
- flexVolume:
driver: alicloud/nas
options:
path: /open-falcon/falcon-nodata/config
server: xxx.cn-hangzhou.nas.aliyuncs.com
vers: "4.0"
name: falcon-nodata-config
- hostPath:
path: /etc/localtime
type: ''
name: tz-config
================================================
FILE: docker/k8s-cluster/modules/falcon-transfer.yaml
================================================
apiVersion: v1
kind: Service
metadata:
namespace: open-falcon
name: falcon-transfer
labels:
app: open-falcon
spec:
type: ClusterIP
ports:
- name: http
port: 6060
- name: rpc
port: 8433
selector:
name: falcon-transfer
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: open-falcon
name: falcon-transfer
labels:
app: open-falcon
spec:
replicas: 1
template:
metadata:
labels:
name: falcon-transfer
spec:
containers:
- name: falcon-transfer
image: registry.cn-hangzhou.aliyuncs.com/open-falcon/transfer:v0.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6060
name: http
protocol: TCP
- containerPort: 8433
name: rpc
protocol: TCP
volumeMounts:
- mountPath: /open-falcon/transfer/config
name: falcon-transfer-config
- mountPath: /etc/localtime
name: tz-config
volumes:
- flexVolume:
driver: alicloud/nas
options:
path: /open-falcon/falcon-transfer/config
server: xxx.cn-hangzhou.nas.aliyuncs.com
vers: "4.0"
name: falcon-transfer-config
- hostPath:
path: /etc/localtime
type: ''
name: tz-config
================================================
FILE: docker/k8s-example/README.md
================================================
## Running open-falcon in kubernetes
work on kubernetes 1.14 , the `kubectl version` like:
```
Client Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.0", GitCommit:"641856db18352033a0d96dbc99153fa3b27298e5", GitTreeState:"clean", BuildDate:"2019-03-25T15:53:57Z", GoVersion:"go1.12.1", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.0", GitCommit:"641856db18352033a0d96dbc99153fa3b27298e5", GitTreeState:"clean", BuildDate:"2019-03-25T15:45:25Z", GoVersion:"go1.12.1", Compiler:"gc", Platform:"linux/amd64"}
```
##### 1. Start mysql in k8s and init the mysql table before the first running
if mysql is already in k8s you can break this step
```
kubectl apply -f mysql.yaml
```
init mysql table before the first running
```
sh init_mysql_data.sh
```
##### 2. Start redis in k8s
if redis is already in k8s you can also break this step
```
kubectl apply -f redis.yaml
```
##### 3. Start falcon-plus modules in one pod
```
kubectl apply -f openfalcon-plus.yaml
```
##### 4. Start falcon-dashboard in k8s
```
kubectl apply -f openfalcon-dashboard.yaml
```
##### 5. browse the dashboard view
```
[tyhall51@192-168-10-21 k8s-example]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 105d
mysql NodePort 10.110.20.201 3306:30535/TCP 25m
open-falcon NodePort 10.97.12.125 8433:31952/TCP,8080:31957/TCP 53s
open-falcon-dashboard NodePort 10.96.119.231 8081:30191/TCP 3s
redis ClusterIP 10.98.212.126 6379/TCP 32m
```
get **open-falcon-dashboard** service localhost port **30191** , then can visit `http://192.168.10.21:30191` in webrowser 。
[mailto](mailto:studyoo@foxmail.com)
================================================
FILE: docker/k8s-example/init_mysql_data.sh
================================================
#!/bin/sh
mysql_pod=$(kubectl get pods | grep mysql | awk '{print $1}')
cd /tmp && \
git clone --depth=1 https://github.com/open-falcon/falcon-plus && \
cd /tmp/falcon-plus/ && \
for x in `ls ./scripts/mysql/db_schema/*.sql`; do
echo init mysql table $x ...;
kubectl exec -it $mysql_pod -- mysql -uroot -p123456 < $x;
done
rm -rf /tmp/falcon-plus/
================================================
FILE: docker/k8s-example/mysql.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: mysql
labels:
app: db
spec:
type: NodePort
ports:
- port: 3306
targetPort: mysqlport
selector:
app: db
name: mysql
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
template:
metadata:
labels:
app: db
name: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
imagePullPolicy: IfNotPresent
env:
- name: TZ
value: "Asia/Shanghai"
- name: MYSQL_ROOT_PASSWORD
value: "123456"
ports:
- containerPort: 3306
name: mysqlport
volumeMounts:
- name: mysqldata
subPath: mysql_data
mountPath: /var/lib/mysql
volumes:
- name: mysqldata
emptyDir: {}
================================================
FILE: docker/k8s-example/openfalcon-dashboard.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: open-falcon-dashboard
labels:
app: monitor
spec:
type: NodePort
ports:
- name: web
port: 8081
selector:
name: open-falcon-dashboard
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: open-falcon-dashboard
labels:
app: monitor
spec:
replicas: 1
template:
metadata:
labels:
name: open-falcon-dashboard
spec:
containers:
- name: open-falcon-dashboard
image: openfalcon/falcon-dashboard:v0.2.1
command: ["sh","-c","cd /open-falcon/dashboard && ./control startfg"]
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8081
env:
- name: API_ADDR
value: http://open-falcon:8080/api/v1
- name: PORTAL_DB_HOST
value: mysql
- name: PORTAL_DB_PORT
value: "3306"
- name: PORTAL_DB_USER
value: root
- name: PORTAL_DB_PASS
value: 1qazxsw2
- name: PORTAL_DB_NAME
value: falcon_portal
- name: ALARM_DB_HOST
value: mysql
- name: ALARM_DB_PORT
value: "3306"
- name: ALARM_DB_USER
value: root
- name: ALARM_DB_PASS
value: 1qazxsw2
- name: ALARM_DB_NAME
value: alarms
================================================
FILE: docker/k8s-example/openfalcon-plus.yaml
================================================
apiVersion: v1
kind: ConfigMap
metadata:
name: openfalcon-configmap
data:
entrypoint.sh: |-
#!/bin/bash
/bin/sh -c 'sleep 10 && sh ctrl.sh start graph hbs judge transfer nodata aggregator gateway api alarm' & /usr/bin/supervisord -c /etc/supervisord.conf
agent.json: |-
{
"debug": true,
"hostname": "",
"ip": "",
"plugin": {
"enabled": false,
"dir": "./plugin",
"git": "https://github.com/open-falcon/plugin.git",
"logs": "./logs"
},
"heartbeat": {
"enabled": true,
"addr": "open-falcon:6030",
"interval": 60,
"timeout": 1000
},
"transfer": {
"enabled": true,
"addrs": [
"open-falcon:8433"
],
"interval": 60,
"timeout": 1000
},
"http": {
"enabled": true,
"listen": ":1988",
"backdoor": false
},
"collector": {
"ifacePrefix": ["eth", "em"],
"mountPoint": []
},
"default_tags": {
},
"ignore": {
"sys.disk.rw": true,
"df.bytes.free": true,
"df.bytes.total": true,
"df.bytes.used": true,
"df.inodes.total": true,
"df.inodes.free": true,
"df.inodes.used": true,
"mem.memtotal": true,
"mem.memused": true,
"mem.memfree": true,
"mem.swaptotal": true,
"mem.swapused": true,
"mem.swapfree": true,
"df.statistics.total": true,
"df.statistics.used": true
}
}
---
apiVersion: v1
kind: Service
metadata:
name: open-falcon
labels:
app: monitor
spec:
type: NodePort
ports:
- name: tcp
port: 8433
- name: web
port: 8080
selector:
name: open-falcon
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: open-falcon
labels:
app: monitor
spec:
replicas: 1
template:
metadata:
labels:
name: open-falcon
spec:
containers:
- name: open-falcon
image: openfalcon/falcon-plus:v0.3
workingDir: /open-falcon
command:
- /bin/entrypoint.sh
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8433
- containerPort: 8080
env:
- name: MYSQL_PORT
value: root:123456@tcp(mysql:3306)
- name: REDIS_PORT
value: redis:6379
volumeMounts:
- name: open-falcon-data
mountPath: /open-falcon/data
- name: configmap-volume
mountPath: /bin/entrypoint.sh
readOnly: true
subPath: entrypoint.sh
volumes:
- name: open-falcon-data
emptyDir: {}
- name: configmap-volume
configMap:
defaultMode: 0700
name: openfalcon-configmap
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: falcon-plus
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
k8s-app: falcon-agent
kubernetes.io/cluster-service: 'true'
version: v1
name: falcon-agent
spec:
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: falcon-agent
kubernetes.io/cluster-service: 'true'
version: v1
template:
metadata:
creationTimestamp: null
labels:
k8s-app: falcon-agent
kubernetes.io/cluster-service: 'true'
version: v1
spec:
containers:
- args:
- '-c'
- /open-falcon/config/agent.json
command:
- ./agent/bin/falcon-agent
env:
- name: GIN_MODE
value: release
- name: NUX_ROOTFS
value: /rootfs
- name: FALCON_ENDPOINT
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
image: 'openfalcon/falcon-plus:v0.3'
workingDir: /open-falcon
imagePullPolicy: IfNotPresent
name: falcon-agent
resources:
limits:
cpu: 200m
memory: 200Mi
requests:
cpu: 200m
memory: 200Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /rootfs
name: rootfs
readOnly: true
- mountPath: /open-falcon/config
name: configmap-volume
readOnly: true
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: falcon-plus
serviceAccountName: falcon-plus
terminationGracePeriodSeconds: 30
volumes:
- hostPath:
path: /
type: ''
name: rootfs
- name: configmap-volume
configMap:
defaultMode: 0700
name: openfalcon-configmap
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
================================================
FILE: docker/k8s-example/redis.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: redis
labels:
app: db
spec:
ports:
- port: 6379
selector:
app: db
name: redis
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis
spec:
replicas: 1
template:
metadata:
labels:
app: db
name: redis
spec:
containers:
- image: redis:alpine
name: redis
livenessProbe:
tcpSocket:
port: 6379
ports:
- containerPort: 6379
name: redis
================================================
FILE: docker/mysql-init/Dockerfile
================================================
from alpine:3.5
env MYSQL_HOST=mysql \
MYSQL_USER=root \
MYSQL_PASSWORD=test123456
run apk add --no-cache mysql-client git
copy init_mysql_data.sh /
cmd ["/init_mysql_data.sh"]
================================================
FILE: docker/mysql-init/init_mysql_data.sh
================================================
#!/bin/sh
Host=${MYSQL_HOST}
User=${MYSQL_USER}
Password=${MYSQL_PASSWORD}
cd /tmp && \
git clone --depth=1 https://github.com/open-falcon/falcon-plus && \
cd /tmp/falcon-plus/ && \
for x in `ls ./scripts/mysql/db_schema/*.sql`; do
echo init mysql table $x ...;
mysql -h${Host} -u${User} -p${Password} < $x;
done
rm -rf /tmp/falcon-plus/
================================================
FILE: docker/supervisord.conf
================================================
[supervisord]
childlogdir = /open-falcon/logs/
logfile = /open-falcon/logs/supervisord.log
pidfile = /var/run/supervisord.pid
nodaemon = true
directory = /open-falcon
[unix_http_server]
file = /var/run/supervisor.sock
chmod = 0777
chown= nobody:nogroup
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl = unix:///var/run/supervisor.sock
[program:graph]
user = root
directory = /open-falcon/%(program_name)s
command = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json
stdout_logfile = /open-falcon/logs/%(program_name)s.log
stderr_logfile = /open-falcon/logs/%(program_name)s.err
autostart=false
[program:hbs]
user = root
directory = /open-falcon/%(program_name)s
command = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json
stdout_logfile = /open-falcon/logs/%(program_name)s.log
stderr_logfile = /open-falcon/logs/%(program_name)s.err
autostart=false
[program:judge]
user = root
directory = /open-falcon/%(program_name)s
command = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json
stdout_logfile = /open-falcon/logs/%(program_name)s.log
stderr_logfile = /open-falcon/logs/%(program_name)s.err
autostart=false
[program:transfer]
user = root
directory = /open-falcon/%(program_name)s
command = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json
stdout_logfile = /open-falcon/logs/%(program_name)s.log
stderr_logfile = /open-falcon/logs/%(program_name)s.err
autostart=false
[program:nodata]
user = root
directory = /open-falcon/%(program_name)s
command = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json
stdout_logfile = /open-falcon/logs/%(program_name)s.log
stderr_logfile = /open-falcon/logs/%(program_name)s.err
autostart=false
[program:aggregator]
user = root
directory = /open-falcon/%(program_name)s
command = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json
stdout_logfile = /open-falcon/logs/%(program_name)s.log
stderr_logfile = /open-falcon/logs/%(program_name)s.err
autostart=false
[program:agent]
user = root
directory = /open-falcon/%(program_name)s
command = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json
stdout_logfile = /open-falcon/logs/%(program_name)s.log
stderr_logfile = /open-falcon/logs/%(program_name)s.err
autostart=false
[program:gateway]
user = root
directory = /open-falcon/%(program_name)s
command = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json
stdout_logfile = /open-falcon/logs/%(program_name)s.log
stderr_logfile = /open-falcon/logs/%(program_name)s.err
autostart=false
[program:api]
user = root
directory = /open-falcon/%(program_name)s
command = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json
stdout_logfile = /open-falcon/logs/%(program_name)s.log
stderr_logfile = /open-falcon/logs/%(program_name)s.err
autostart=false
[program:alarm]
user = root
directory = /open-falcon/%(program_name)s
command = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json
stdout_logfile = /open-falcon/logs/%(program_name)s.log
stderr_logfile = /open-falcon/logs/%(program_name)s.err
autostart=false
================================================
FILE: docker-compose.yml
================================================
version: '3.5'
services:
mysql:
container_name: falcon-mysql
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- ./scripts/mysql/db_schema:/docker-entrypoint-initdb.d/
- mysql-data:/var/lib/mysql
redis:
container_name: falcon-redis
image: redis:4-alpine3.8
hbs: &falcon
container_name: falcon-hbs
build:
context: ./
args:
MODULE: hbs
dockerfile: Dockerfile.module
image: openfalcon/falcon-hbs:dev
environment:
MYSQL_PORT: root:root@tcp\(falcon-mysql:3306\)
REDIS_PORT: falcon-redis:6379
AGGREGATOR_HTTP: falcon-aggregator:6055
GRAPH_HTTP: falcon-graph:6071
GRAPH_RPC: falcon-graph:6070
HBS_HTTP: falcon-hbs:6031
HBS_RPC: falcon-hbs:6030
JUDGE_HTTP: falcon-judge:6081
JUDGE_RPC: falcon-judge:6080
NODATA_HTTP: falcon-nodata:6090
TRANSFER_HTTP: falcon-transfer:6060
TRANSFER_RPC: falcon-transfer:8433
PLUS_API_HTTP: falcon-api:8080
AGENT_HOSTNAME: docker-agent
depends_on:
- mysql
- redis
command: "sh ctrl.sh run hbs"
agent:
<<: *falcon
build:
context: ./
args:
MODULE: agent
dockerfile: Dockerfile.module
image: openfalcon/falcon-agent:dev
container_name: falcon-agent
depends_on:
- hbs
- transfer
command: "sh ctrl.sh run agent"
aggregator:
<<: *falcon
build:
context: ./
args:
MODULE: aggregator
dockerfile: Dockerfile.module
image: openfalcon/falcon-aggregator:dev
container_name: falcon-aggregator
command: "sh ctrl.sh run aggregator"
nodata:
<<: *falcon
build:
context: ./
args:
MODULE: nodata
dockerfile: Dockerfile.module
image: openfalcon/falcon-nodata:dev
container_name: falcon-nodata
command: "sh ctrl.sh run nodata"
api:
<<: *falcon
build:
context: ./
args:
MODULE: api
dockerfile: Dockerfile.module
image: openfalcon/falcon-api:dev
container_name: falcon-api
command: "sh ctrl.sh run api"
ports:
- 8080:8080
alarm:
<<: *falcon
build:
context: ./
args:
MODULE: alarm
dockerfile: Dockerfile.module
image: openfalcon/falcon-alarm:dev
container_name: falcon-alarm
command: "sh ctrl.sh run alarm"
transfer:
<<: *falcon
build:
context: ./
args:
MODULE: transfer
dockerfile: Dockerfile.module
image: openfalcon/falcon-transfer:dev
container_name: falcon-transfer
depends_on:
- graph
command: "sh ctrl.sh run transfer"
judge:
<<: *falcon
build:
context: ./
args:
MODULE: judge
dockerfile: Dockerfile.module
image: openfalcon/falcon-judge:dev
container_name: falcon-judge
command: "sh ctrl.sh run judge"
graph:
<<: *falcon
build:
context: ./
args:
MODULE: graph
dockerfile: Dockerfile.module
image: openfalcon/falcon-graph:dev
container_name: falcon-graph
volumes:
- graph-data:/open-falcon/data
command: "sh ctrl.sh run graph"
dashboard:
container_name: falcon-dashboard
image: openfalcon/falcon-dashboard:v0.2.1
entrypoint: ./control startfg
environment:
API_ADDR: http://falcon-api:8080/api/v1
PORTAL_DB_HOST: mysql
PORTAL_DB_PORT: 3306
PORTAL_DB_USER: root
PORTAL_DB_PASS: root
PORTAL_DB_NAME: falcon_portal
ALARM_DB_HOST: mysql
ALARM_DB_PORT: 3306
ALARM_DB_USER: root
ALARM_DB_PASS: root
ALARM_DB_NAME: alarms
working_dir: /open-falcon/dashboard
ports:
- 8081:8081
volumes:
mysql-data:
graph-data:
================================================
FILE: docker_test.sh
================================================
#!/bin/bash
export DB_USER=root
export DB_PASSWORD=test123456
export DB_HOST=127.0.0.1
export DB_PORT=13306
export REDIS_HOST=127.0.0.1
export REDIS_PORT=16379
export API_PORT=18080
export API_HOST=127.0.0.1
docker rm -f falcon-mysql falcon-redis falcon-plus &> /dev/null
if [[ `uname -m` == "aarch64" ]]; then
docker run --name falcon-mysql -e MYSQL_ROOT_PASSWORD=$DB_PASSWORD -p $DB_PORT:3306 -d mariadb:10.3
else
docker run --name falcon-mysql -e MYSQL_ROOT_PASSWORD=$DB_PASSWORD -p $DB_PORT:3306 -d mysql:5.7
fi
docker run --name falcon-redis -p $REDIS_PORT:6379 -d redis:4-alpine3.8
echo "waiting mysql start..."
sleep 15
for x in `ls ./scripts/mysql/db_schema/*.sql`; do
echo "- - -" $x ...
mysql -h $DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD < $x
done
commit_id=`git rev-parse --short HEAD`
image_tag="falcon-plus:$commit_id"
#build docker image from source code
if [[ `uname -m` == "aarch64" ]]; then
docker build -t $image_tag -f Dockerfile_arm64 .
else
docker build -t $image_tag .
fi
## run falcon-plus container
docker run -itd --name falcon-plus \
--link=falcon-mysql:db.falcon \
--link=falcon-redis:redis.falcon \
-p 18433:8433 \
-p 18080:8080 \
-e MYSQL_PORT=$DB_USER:$DB_PASSWORD@tcp\(db.falcon:3306\) \
-e REDIS_PORT=redis.falcon:6379 \
$image_tag
sleep 15
## start falcon backend modules, such as graph,api,etc.
docker exec falcon-plus sh ctrl.sh start \
graph hbs judge transfer nodata aggregator agent gateway api alarm
echo "sleep 15s waiting for falcon-plus process ready..."
sleep 15
make test
================================================
FILE: docs/LICENSE.md
================================================
The MIT License (MIT)
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: docs/Makefile
================================================
SRC = $(wildcard lib/*/*.js)
HTML = $(wildcard lib/*/*.html)
TEMPLATES = $(HTML:.html=.js)
LESS = $(wildcard lib/*/*.less)
CSS = $(LESS:.less=.css)
build: components $(SRC) $(TEMPLATES) $(CSS)
@component build --verbose --out . --name assets
components: component.json
@component install
%.js: %.html
@component convert $<
%.css: %.less
@lessc $< $@
clean:
rm -fr build components $(TEMPLATES)
.PHONY: clean
================================================
FILE: docs/README.md
================================================
## The "What ?" and the "Why ?"
**Carte** is a simple Jekyll based documentation website for APIs. It is designed as a boilerplate to build your own documentation and is heavily inspired from [Swagger](http://swagger.wordnik.com/) and [I/O docs](http://www.mashery.com/product/io-docs). Fork it, add specifications for your APIs calls and customize the theme. Go ahead, see if we care.
We built **Carte** because the existing options (Swagger and the likes) were trying to do too much and did not match our needs:
1. Most of our API calls are sending JSON objects, as opposed to a series of parameters,
1. Being able to query the real API is nice, but running anything but `GET` calls can get tricky ("What do you mean I deleted my stuff? I was just trying out the API calls!"),
1. Overall, setting up a separate server for what really requires a good static documentation seemed overkill.
The real value of **Carte** is its structure for describing APIs, not its underlying technical stack (or lack-thereof). In a nutshell; **we built a static template for your API documentation, feel free to re-use it**.
## Install
It' Jekyll god dammit:
1. Clone this repository on your local,
1. [Install Jekyll](https://github.com/mojombo/jekyll/wiki/install),
1. Go at the root of the repository and run ```jekyll serve --watch```,
1. Go to http://localhost:4000,
1. [Great success! High five!](http://www.youtube.com/watch?v=wWWyJwHQ-4E)
## How to...
### Adding a new API call
You can add a new API call by simply adding a new post in the `_posts` folder. Jekyll by default forces you to specify a date in the file path: it makes us sad pandas too, but you'll have to stick to this format. You can use dates to control the order in which API calls are displayed in the interface.
Each API call can define a few values in its YAML header:
Variable | Mandatory | Default | Description
--- | --- | --- | ---
``title`` | Y | - | A short description of what that calls does.
``path`` | N | - | The URL for the API call, including potential parameters.
``type`` | N | - | Set it to `PUT`, `GET`, `POST`, `DELETE` or nothing (for parts of your documentation that do not relate to an actual API call).
A typical header:
```
---
path: '/stuff/:id'
title: 'Delete a thing'
type: 'DELETE'
layout: nil
---
```
We then describe the request and response (or whatever else you wish to talk about) in the body of our post. Check the placeholders present in the `_posts` folder to get an idea of what it can look like.
### Grouping calls
Adding a category to your YAML header will allows you to group methods in the navigation. It is particularly helpful as you start having a lot of methods and need to organize them. For example:
```
---
category: Stuff
path: '/stuff/:id'
title: 'Delete a thing'
type: 'DELETE'
layout: nil
---
```
### Edit the design
The default UI is mostly described through the `css/style.css` file and a couple short jQuery scripts in the `/_layouts/default.html` layout. Hack it to oblivion.
================================================
FILE: docs/_config.yml
================================================
---
exclude: ['README.markdown']
permalink: ':title'
safe: false
title: 'Falcon+ API'
project_name: 'Falcon+'
================================================
FILE: docs/_includes/nav.html
================================================
{{ site.title }}
{% for post in site.posts %}
{% if post.category == null %}