├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── enhancement.md
│ └── question.yml
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── n9e.yml
├── .gitignore
├── .goreleaser.yaml
├── LICENSE
├── Makefile
├── README.md
├── README_en.md
├── alert
├── aconf
│ └── conf.go
├── alert.go
├── astats
│ └── stats.go
├── common
│ └── key.go
├── dispatch
│ ├── consume.go
│ ├── dispatch.go
│ ├── log.go
│ ├── notify_channel.go
│ └── notify_target.go
├── eval
│ ├── alert_rule.go
│ ├── eval.go
│ └── eval_test.go
├── mute
│ └── mute.go
├── naming
│ ├── hashring.go
│ ├── heartbeat.go
│ └── leader.go
├── pipeline
│ ├── pipeline.go
│ └── processor
│ │ ├── callback
│ │ └── callback.go
│ │ ├── common
│ │ └── common.go
│ │ ├── eventdrop
│ │ └── event_drop.go
│ │ ├── eventupdate
│ │ └── event_update.go
│ │ └── relabel
│ │ └── relabel.go
├── process
│ ├── alert_cur_event.go
│ └── process.go
├── queue
│ └── queue.go
├── record
│ ├── prom_rule.go
│ ├── sample.go
│ └── scheduler.go
├── router
│ ├── router.go
│ └── router_event.go
└── sender
│ ├── callback.go
│ ├── dingtalk.go
│ ├── email.go
│ ├── feishu.go
│ ├── feishucard.go
│ ├── ibex.go
│ ├── lark.go
│ ├── larkcard.go
│ ├── mm.go
│ ├── notify_record_queue.go
│ ├── plugin.go
│ ├── plugin_cmd_unix.go
│ ├── plugin_cmd_windows.go
│ ├── sender.go
│ ├── telegram.go
│ ├── webhook.go
│ ├── webhook_event_queue.go
│ ├── webhook_event_queue_test.go
│ ├── webhook_queue.go
│ └── wecom.go
├── center
├── cconf
│ ├── conf.go
│ ├── event_example.go
│ ├── metric.go
│ ├── ops.go
│ ├── plugin.go
│ ├── rsa
│ │ └── rsa_conf.go
│ └── sql_tpl.go
├── center.go
├── cstats
│ └── stats.go
├── integration
│ └── init.go
├── metas
│ └── metas.go
├── router
│ ├── router.go
│ ├── router_alert_aggr_view.go
│ ├── router_alert_cur_event.go
│ ├── router_alert_his_event.go
│ ├── router_alert_rule.go
│ ├── router_alert_subscribe.go
│ ├── router_board.go
│ ├── router_builtin.go
│ ├── router_builtin_componet.go
│ ├── router_builtin_metric_filter.go
│ ├── router_builtin_metrics.go
│ ├── router_builtin_payload.go
│ ├── router_busi_group.go
│ ├── router_captcha.go
│ ├── router_chart_share.go
│ ├── router_config.go
│ ├── router_configs.go
│ ├── router_crypto.go
│ ├── router_dash_annotation.go
│ ├── router_dashboard.go
│ ├── router_datasource.go
│ ├── router_datasource_db.go
│ ├── router_embedded.go
│ ├── router_es.go
│ ├── router_es_index_pattern.go
│ ├── router_event_pipeline.go
│ ├── router_funcs.go
│ ├── router_heartbeat.go
│ ├── router_login.go
│ ├── router_message_template.go
│ ├── router_metric_desc.go
│ ├── router_metric_view.go
│ ├── router_mute.go
│ ├── router_mw.go
│ ├── router_notification_record.go
│ ├── router_notify_channel.go
│ ├── router_notify_channel_test.go
│ ├── router_notify_config.go
│ ├── router_notify_rule.go
│ ├── router_notify_tpl.go
│ ├── router_proxy.go
│ ├── router_query.go
│ ├── router_recording_rule.go
│ ├── router_role.go
│ ├── router_role_operation.go
│ ├── router_self.go
│ ├── router_server.go
│ ├── router_source_token.go
│ ├── router_target.go
│ ├── router_task.go
│ ├── router_task_tpl.go
│ ├── router_tdengine.go
│ ├── router_user.go
│ ├── router_user_group.go
│ └── router_user_variable_config.go
└── sso
│ ├── init.go
│ └── sync.go
├── cli
├── cli.go
└── upgrade
│ ├── config.go
│ ├── readme.md
│ ├── upgrade.go
│ └── upgrade.sql
├── cmd
├── alert
│ └── main.go
├── center
│ └── main.go
├── cli
│ └── main.go
├── edge
│ ├── edge.go
│ └── main.go
└── pushgw
│ └── main.go
├── conf
├── conf.go
└── crypto.go
├── cron
└── clean_notify_record.go
├── datasource
├── ck
│ └── clickhouse.go
├── commons
│ └── eslike
│ │ └── eslike.go
├── datasource.go
├── es
│ └── es.go
├── prom
│ └── prom.go
└── tdengine
│ └── tdengine.go
├── doc
├── README.bak.md
├── active-contributors.md
├── committers.md
├── community-governance.md
├── contributors.md
├── end-users.md
├── img
│ ├── Nightingale_L_V.png
│ ├── alert-events.png
│ ├── arch-product.png
│ ├── arch-system.png
│ ├── arch.png
│ ├── ccf-logo.png
│ ├── ccf-n9e.png
│ ├── dingtalk.png
│ ├── install-vm.png
│ ├── intro.gif
│ ├── mysql-alerts.png
│ ├── n9e-arch-latest.png
│ ├── n9e-node-dashboard.png
│ ├── n9e-screenshot-gif-v6.gif
│ ├── n9e-vx-new.png
│ ├── nightingale_logo_h.png
│ ├── nightingale_logo_v.png
│ ├── readme
│ │ ├── 20240221152601.png
│ │ ├── 20240222102119.png
│ │ ├── 20240513103305.png
│ │ ├── 20240513103530.png
│ │ ├── 20240513103628.png
│ │ ├── 20240513103825.png
│ │ ├── 2025-05-23_18-43-37.png
│ │ ├── 2025-05-23_18-46-06.png
│ │ ├── 2025-05-23_18-49-02.png
│ │ ├── 2025-05-30_08-49-28.png
│ │ ├── logos.png
│ │ └── n9e-switch-i18n.png
│ ├── redis-dash.png
│ ├── vm-cluster-arch.png
│ ├── wecom.png
│ └── wx.jpg
├── pmc.md
└── server-dash.json
├── docker
├── .dockerignore
├── Dockerfile.goreleaser
├── Dockerfile.goreleaser.arm64
├── build.sh
├── compose-bridge
│ ├── docker-compose.yaml
│ ├── etc-categraf
│ │ ├── config.toml
│ │ ├── input.cpu
│ │ │ └── cpu.toml
│ │ ├── input.disk
│ │ │ └── disk.toml
│ │ ├── input.diskio
│ │ │ └── diskio.toml
│ │ ├── input.kernel
│ │ │ └── kernel.toml
│ │ ├── input.mem
│ │ │ └── mem.toml
│ │ ├── input.mysql
│ │ │ └── mysql.toml
│ │ ├── input.net
│ │ │ └── net.toml
│ │ ├── input.netstat
│ │ │ └── netstat.toml
│ │ ├── input.processes
│ │ │ └── processes.toml
│ │ ├── input.prometheus
│ │ │ └── prometheus.toml
│ │ ├── input.redis
│ │ │ └── redis.toml
│ │ └── input.system
│ │ │ └── system.toml
│ ├── etc-mysql
│ │ └── my.cnf
│ └── etc-nightingale
│ │ ├── config.toml
│ │ ├── metrics.yaml
│ │ └── script
│ │ ├── notify.bak.py
│ │ ├── notify.py
│ │ ├── notify_feishu.py
│ │ └── rule_converter.py
├── compose-host-network-metric-log
│ ├── docker-compose.yaml
│ ├── etc-categraf
│ │ ├── config.toml
│ │ ├── input.cpu
│ │ │ └── cpu.toml
│ │ ├── input.disk
│ │ │ └── disk.toml
│ │ ├── input.diskio
│ │ │ └── diskio.toml
│ │ ├── input.kernel
│ │ │ └── kernel.toml
│ │ ├── input.mem
│ │ │ └── mem.toml
│ │ ├── input.net
│ │ │ └── net.toml
│ │ ├── input.netstat
│ │ │ └── netstat.toml
│ │ ├── input.processes
│ │ │ └── processes.toml
│ │ ├── input.system
│ │ │ └── system.toml
│ │ └── logs.toml
│ ├── etc-logstash
│ │ └── logstash.yaml
│ ├── etc-mysql
│ │ └── my.cnf
│ ├── etc-nightingale
│ │ ├── config.toml
│ │ ├── metrics.yaml
│ │ └── script
│ │ │ ├── notify.bak.py
│ │ │ ├── notify.py
│ │ │ ├── notify_feishu.py
│ │ │ └── rule_converter.py
│ └── etc-prometheus
│ │ └── prometheus.yml
├── compose-host-network
│ ├── docker-compose.yaml
│ ├── etc-categraf
│ │ ├── config.toml
│ │ ├── input.cpu
│ │ │ └── cpu.toml
│ │ ├── input.disk
│ │ │ └── disk.toml
│ │ ├── input.diskio
│ │ │ └── diskio.toml
│ │ ├── input.kernel
│ │ │ └── kernel.toml
│ │ ├── input.mem
│ │ │ └── mem.toml
│ │ ├── input.net
│ │ │ └── net.toml
│ │ ├── input.netstat
│ │ │ └── netstat.toml
│ │ ├── input.processes
│ │ │ └── processes.toml
│ │ └── input.system
│ │ │ └── system.toml
│ ├── etc-mysql
│ │ └── my.cnf
│ ├── etc-nightingale
│ │ ├── config.toml
│ │ ├── metrics.yaml
│ │ └── script
│ │ │ ├── notify.bak.py
│ │ │ ├── notify.py
│ │ │ ├── notify_feishu.py
│ │ │ └── rule_converter.py
│ └── etc-prometheus
│ │ └── prometheus.yml
├── compose-postgres
│ ├── categraf
│ │ └── conf
│ │ │ ├── config.toml
│ │ │ ├── input.cpu
│ │ │ └── cpu.toml
│ │ │ ├── input.disk
│ │ │ └── disk.toml
│ │ │ ├── input.diskio
│ │ │ └── diskio.toml
│ │ │ ├── input.docker
│ │ │ └── docker.toml
│ │ │ ├── input.kernel
│ │ │ └── kernel.toml
│ │ │ ├── input.mem
│ │ │ └── mem.toml
│ │ │ ├── input.net
│ │ │ └── net.toml
│ │ │ ├── input.netstat
│ │ │ └── netstat.toml
│ │ │ ├── input.processes
│ │ │ └── processes.toml
│ │ │ ├── input.system
│ │ │ └── system.toml
│ │ │ └── prometheus.toml
│ ├── docker-compose.yaml
│ ├── initsql_for_postgres
│ │ ├── a-n9e-for-Postgres.sql
│ │ └── b-ibex-for-Postgres.sql
│ ├── n9eetc_pg
│ │ ├── config.toml
│ │ └── metrics.yaml
│ └── prometc_vm
│ │ ├── prometheus.yml
│ │ └── targets.json
├── initsql
│ ├── a-n9e.sql
│ └── c-init.sql
├── migratesql
│ └── migrate.sql
└── sqlite.sql
├── dscache
├── cache.go
└── sync.go
├── dskit
├── clickhouse
│ ├── clickhouse.go
│ ├── clickhouse_test.go
│ └── timeseries.go
├── sqlbase
│ ├── base.go
│ ├── timeseries.go
│ └── timeseries_test.go
├── tdengine
│ └── tdengine.go
└── types
│ ├── timeseries.go
│ └── types.go
├── dumper
├── dumper.go
└── sync.go
├── etc
├── config.toml
├── edge
│ └── edge.toml
├── metrics.yaml
└── script
│ ├── notify.bak.py
│ ├── notify.py
│ ├── notify_feishu.py
│ └── rule_converter.py
├── fe.sh
├── front
└── statik
│ └── statik.go
├── go.mod
├── go.sum
├── integrations
├── AMD_ROCm_SMI
│ ├── collect
│ │ └── amd_rocm_smi
│ │ │ └── rocm.toml
│ ├── icon
│ │ └── rocm_smi.png
│ └── markdown
│ │ └── README.md
├── AliYun
│ ├── collect
│ │ └── aliyun
│ │ │ └── cloud.toml
│ ├── dashboards
│ │ ├── arms-api.json
│ │ ├── arms-application.json
│ │ ├── arms-db.json
│ │ ├── arms-jvm-service.json
│ │ ├── arms-machine.json
│ │ ├── arms_jvm.json
│ │ ├── cdn.json
│ │ ├── ecs.json
│ │ ├── mongodb.json
│ │ ├── mse.json
│ │ ├── mysql.json
│ │ ├── nat.json
│ │ ├── oss.json
│ │ ├── polardb_mysql.json
│ │ ├── rds.json
│ │ ├── rds_new.json
│ │ ├── redis.json
│ │ ├── redis_cluster.json
│ │ ├── redis_new.json
│ │ ├── redis_standard.json
│ │ ├── slb.json
│ │ ├── slb_new.json
│ │ └── waf.json
│ ├── icon
│ │ └── aliyun.png
│ └── markdown
│ │ ├── README.md
│ │ ├── ecs.png
│ │ ├── rds.png
│ │ ├── redis.png
│ │ ├── slb.png
│ │ └── waf.png
├── AppDynamics
│ ├── collect
│ │ └── appdynamics
│ │ │ └── app.toml
│ ├── icon
│ │ └── appdynamics.png
│ └── markdown
│ │ └── README.md
├── AutoMQ
│ ├── alerts
│ │ └── 常用告警规则.json
│ ├── collect
│ │ └── prometheus
│ │ │ └── 采集OTEL-COLLECTOR的样例.toml
│ ├── dashboards
│ │ ├── broker_metrics.json
│ │ ├── cluster_overview.json
│ │ ├── detailed_metrics.json
│ │ ├── group_metrics.json
│ │ └── topic_metrics.json
│ ├── icon
│ │ └── automq.png
│ ├── markdown
│ │ └── overview.md
│ └── metrics
│ │ └── exporter.json
├── Bind
│ ├── collect
│ │ └── bind
│ │ │ └── bind.toml
│ ├── icon
│ │ └── bind.png
│ └── markdown
│ │ └── README.md
├── Canal
│ ├── dashboards
│ │ └── canal_by_categraf.json
│ ├── icon
│ │ └── canal.png
│ └── markdown
│ │ └── README.md
├── Ceph
│ ├── alerts
│ │ └── ceph_by_categraf.json
│ ├── dashboards
│ │ └── ceph_by_categraf.json
│ ├── icon
│ │ └── ceph.png
│ └── markdown
│ │ ├── README.md
│ │ ├── alerts.png
│ │ ├── ceph-alerts.png
│ │ ├── ceph-dash.png
│ │ └── ceph.png
├── ClickHouse
│ ├── alerts
│ │ ├── clickhouse_by_categraf.json
│ │ └── clickhouse_by_exporter.json
│ ├── collect
│ │ └── clickhouse
│ │ │ └── clickhouse.toml
│ ├── dashboards
│ │ ├── clickhouse_by_categraf.json
│ │ └── clickhouse_by_exporter.json
│ ├── icon
│ │ └── clickhouse.png
│ ├── markdown
│ │ └── README.md
│ └── metrics
│ │ ├── clickhouse_by_categraf.json
│ │ └── clickhouse_by_exporter.json
├── CloudWatch
│ ├── collect
│ │ └── cloudwatch
│ │ │ └── cloud.toml
│ ├── dashboards
│ │ └── dashboard-by-aws-rds.json
│ ├── icon
│ │ └── cloudwatch.png
│ └── markdown
│ │ └── README.md
├── Consul
│ ├── collect
│ │ └── consul
│ │ │ └── consul.toml
│ ├── icon
│ │ └── consul.png
│ └── markdown
│ │ └── README.md
├── Dns_Query
│ ├── collect
│ │ └── dns_query
│ │ │ └── dns_query.toml
│ ├── icon
│ │ └── dns.png
│ └── markdown
│ │ └── README.md
├── Docker
│ ├── collect
│ │ └── docker
│ │ │ └── docker.toml
│ ├── icon
│ │ └── docker.png
│ └── markdown
│ │ └── README.md
├── Doris
│ ├── alerts
│ │ └── doris_by_categraf.json
│ ├── collect
│ │ └── prometheus
│ │ │ └── collect_doris_examples.toml
│ ├── dashboards
│ │ └── Doris_Overview.json
│ ├── icon
│ │ └── doris.svg
│ └── markdown
│ │ └── README.md
├── Elasticsearch
│ ├── alerts
│ │ ├── elasticsearch_by_categraf.json
│ │ └── elasticsearch_by_exporter.json
│ ├── collect
│ │ └── elasticsearch
│ │ │ └── elasticsearch.toml
│ ├── dashboards
│ │ ├── elasticsearch_by_categraf.json
│ │ ├── elasticsearch_by_categraf_a.json
│ │ ├── elasticsearch_by_categraf_b.json
│ │ └── elasticsearch_by_exporter.json
│ ├── icon
│ │ └── elasticsearch.png
│ ├── markdown
│ │ ├── README.md
│ │ └── es-dashboard.jpeg
│ └── metrics
│ │ └── categraf-base.json
├── Exec
│ ├── collect
│ │ └── exec
│ │ │ └── exec.toml
│ ├── icon
│ │ └── exec.png
│ └── markdown
│ │ └── README.md
├── Filecount
│ ├── collect
│ │ └── filecount
│ │ │ └── filecount.toml
│ ├── icon
│ │ └── filecount.png
│ └── markdown
│ │ └── README.md
├── Gitlab
│ ├── alerts
│ │ └── gitlab_by_categraf.json
│ ├── dashboards
│ │ ├── MachinePerformance.json
│ │ ├── NGINXVTS.json
│ │ ├── Overview.json
│ │ ├── PostgreSQL.json
│ │ └── Redis.json
│ ├── icon
│ │ └── gitlab.png
│ └── markdown
│ │ └── README.md
├── GoogleCloud
│ ├── collect
│ │ └── googlecloud
│ │ │ └── gcp.toml
│ ├── icon
│ │ └── gcp.png
│ └── markdown
│ │ └── README.md
├── HAProxy
│ ├── collect
│ │ └── haproxy
│ │ │ └── haproxy.toml
│ ├── dashboards
│ │ └── dashboard.json
│ ├── icon
│ │ └── haproxy.png
│ └── markdown
│ │ └── README.md
├── HTTP_Response
│ ├── alerts
│ │ └── http_response_by_categraf.json
│ ├── collect
│ │ └── http_response
│ │ │ └── http_response.toml
│ ├── dashboards
│ │ └── http_response_by_categraf.json
│ ├── icon
│ │ └── http_response.png
│ ├── markdown
│ │ └── http.md
│ └── metrics
│ │ └── categraf.json
├── IPMI
│ ├── alerts
│ │ └── alerts.json
│ ├── collect
│ │ └── ipmi
│ │ │ └── conf.toml
│ ├── dashboards
│ │ ├── IPMI.json
│ │ ├── IPMI_by_categraf.json
│ │ └── IPMI_by_prometheus.json
│ ├── icon
│ │ └── ipmi.png
│ └── markdown
│ │ └── README.md
├── IPVS
│ ├── collect
│ │ └── ipvs
│ │ │ └── ipvs.toml
│ ├── icon
│ │ └── ipvs.png
│ └── markdown
│ │ └── README.md
├── JMX
│ ├── dashboards
│ │ └── jmx_by_exporter.json
│ └── icon
│ │ └── jmx.png
├── Jenkins
│ ├── collect
│ │ └── jenkins
│ │ │ └── jenkins.toml
│ ├── icon
│ │ └── jenkins.png
│ └── markdown
│ │ └── README.md
├── Jolokia_Agent
│ ├── collect
│ │ └── jolokia_agent
│ │ │ ├── activemq.toml
│ │ │ ├── bitbucket.toml
│ │ │ ├── cassandra.toml
│ │ │ ├── hadoop-hdfs.toml
│ │ │ ├── java.toml
│ │ │ ├── jboss.toml
│ │ │ ├── kafka-connect.toml
│ │ │ ├── kafka.toml
│ │ │ ├── tomcat.toml
│ │ │ ├── weblogic.toml
│ │ │ └── zookeeper.toml
│ ├── icon
│ │ └── jolokia.png
│ └── markdown
│ │ └── README.md
├── Kafka
│ ├── alerts
│ │ ├── kafka_by_categraf.json
│ │ └── kafka_by_exporter.json
│ ├── collect
│ │ └── kafka
│ │ │ └── kafka.toml
│ ├── dashboards
│ │ ├── kafka_by_categraf.json
│ │ └── kafka_by_exporter.json
│ ├── icon
│ │ └── kafka.png
│ ├── markdown
│ │ ├── README.md
│ │ ├── alerts-kafka.png
│ │ ├── alerts..png
│ │ ├── dash-kafka.png
│ │ └── dashboards.png
│ └── metrics
│ │ └── categraf-base.json
├── Kubernetes
│ ├── alerts
│ │ ├── apiserver.json
│ │ ├── kube-controller-plane.json
│ │ ├── kubelet.json
│ │ ├── node-exporter.json
│ │ ├── prometheus-operator.json
│ │ └── prometheus.json
│ ├── dashboards
│ │ ├── APIServer.json
│ │ ├── ControllerManager.json
│ │ ├── DeploymentContainer.json
│ │ ├── KubeStateMetrics.json
│ │ ├── KubeletMetrics.json
│ │ ├── Pod.json
│ │ ├── Scheduler.json
│ │ └── StatefulsetContainer.json
│ ├── icon
│ │ └── kubernetes.png
│ ├── markdown
│ │ └── README.md
│ ├── metrics
│ │ ├── k8s-node.json
│ │ └── k8s-pod.json
│ └── record-rules
│ │ ├── kube-controller-plane.json
│ │ └── node-exporer.json
├── Ldap
│ ├── collect
│ │ └── ldap
│ │ │ └── ldap.toml
│ ├── icon
│ │ └── ldap.png
│ └── markdown
│ │ └── README.md
├── Linux
│ ├── alerts
│ │ ├── CommonAlertingRules-Categraf.json
│ │ ├── linux_by_categraf.json
│ │ ├── linux_by_exporter.json
│ │ ├── linux_by_telegraf.json
│ │ └── 常用中文告警规则-采集器Categraf.json
│ ├── collect
│ │ ├── arp_packet
│ │ │ └── arp_packet.toml
│ │ ├── kernel_vmstat
│ │ │ └── kernel_vmstat.toml
│ │ ├── netstat
│ │ │ └── netstat.toml
│ │ ├── ntp
│ │ │ └── ntp.toml
│ │ └── processes
│ │ │ └── processes.toml
│ ├── dashboards
│ │ ├── categraf-detail.json
│ │ ├── categraf-overview.json
│ │ ├── categraf-processes.json
│ │ └── exporter-detail.json
│ ├── icon
│ │ └── linux.png
│ ├── markdown
│ │ └── README.md
│ └── metrics
│ │ ├── categraf-base.json
│ │ └── exporter-base.json
├── Logstash
│ ├── collect
│ │ └── logstash
│ │ │ └── logstash.toml
│ ├── dashboards
│ │ └── logstash-dash.json
│ ├── icon
│ │ └── logstash.png
│ └── markdown
│ │ └── README.md
├── MinIO
│ ├── alerts
│ │ └── minio_by_categraf.json
│ ├── dashboards
│ │ └── minio_by_categraf.json
│ ├── icon
│ │ └── minio.png
│ └── markdown
│ │ ├── README.md
│ │ ├── alerts-minio.png
│ │ ├── alerts.png
│ │ ├── dash-minio.png
│ │ └── minio.png
├── MongoDB
│ ├── alerts
│ │ └── mongo_by_exporter.json
│ ├── collect
│ │ └── mongodb
│ │ │ └── mongodb.toml
│ ├── dashboards
│ │ └── mongo_by_exporter.json
│ ├── icon
│ │ └── mongodb.png
│ └── markdown
│ │ └── README.md
├── Mtail
│ ├── collect
│ │ └── mtail
│ │ │ └── mtail.toml
│ ├── icon
│ │ └── mtail.png
│ └── markdown
│ │ ├── README.md
│ │ ├── timestamp.png
│ │ └── timezone.png
├── MySQL
│ ├── alerts
│ │ ├── mysql_by_categraf.json
│ │ └── mysql_by_exporter.json
│ ├── collect
│ │ └── mysql
│ │ │ └── mysql.toml
│ ├── dashboards
│ │ ├── MySQL-by-address.json
│ │ ├── MySQL仪表盘-远端.json
│ │ ├── MySQL仪表盘.json
│ │ ├── mysql_by_categraf.json
│ │ ├── mysql_by_categraf_ident.json
│ │ ├── mysql_by_categraf_instance.json
│ │ └── mysql_by_exporter.json
│ ├── icon
│ │ └── mysql.png
│ ├── markdown
│ │ ├── README.md
│ │ └── mysql.md
│ └── metrics
│ │ └── categraf-base.json
├── N9E
│ ├── dashboards
│ │ ├── n9e_server.json
│ │ ├── n9e_v6.json
│ │ └── n9e_v8.json
│ ├── icon
│ │ └── nightingale.png
│ └── markdown
│ │ └── README.md
├── NFSClient
│ ├── collect
│ │ └── nfsclient
│ │ │ └── nfsclient.toml
│ ├── icon
│ │ └── nfsclient.png
│ └── markdown
│ │ └── README.md
├── NSQ
│ ├── collect
│ │ └── nsq
│ │ │ └── nsq.toml
│ ├── icon
│ │ └── nsq.png
│ └── markdown
│ │ └── README.md
├── NVIDIA
│ ├── collect
│ │ └── nvidia_smi
│ │ │ └── nvidia_smi.toml
│ ├── dashboards
│ │ └── nvidia-gpu-metrics-by-categraf.json
│ ├── icon
│ │ └── nvidia.png
│ └── markdown
│ │ └── README.md
├── Net_Response
│ ├── alerts
│ │ └── net_response_by_categraf.json
│ ├── collect
│ │ └── net_response
│ │ │ └── net_response.toml
│ ├── dashboards
│ │ ├── dashboard-by-ziv.json
│ │ └── net_response_by_categraf.json
│ ├── icon
│ │ └── net_response.png
│ ├── markdown
│ │ └── README.md
│ └── metrics
│ │ └── categraf.json
├── Netstat_Filter
│ ├── collect
│ │ └── netstat_filter
│ │ │ └── netstat_filter.toml
│ ├── icon
│ │ └── netstat_filter.png
│ └── markdown
│ │ └── README.md
├── Nginx
│ ├── collect
│ │ ├── nginx
│ │ │ └── nginx.toml
│ │ └── nginx_upstream_check
│ │ │ └── nginx_upstream_check.toml
│ ├── dashboards
│ │ ├── nginx_stub_status.json
│ │ ├── nginx_upstream_check.json
│ │ └── nginx_vts.json
│ ├── icon
│ │ └── nginx.png
│ ├── markdown
│ │ └── README.md
│ └── metrics
│ │ └── categraf.json
├── Oracle
│ ├── alerts
│ │ └── oracle_alert.json
│ ├── collect
│ │ └── oracle
│ │ │ └── oracle.toml
│ ├── dashboards
│ │ └── oracle_by_categraf.json
│ ├── icon
│ │ └── oracle.png
│ └── markdown
│ │ └── README.md
├── PHP
│ ├── collect
│ │ └── phpfpm
│ │ │ └── phpfpm.toml
│ ├── icon
│ │ └── phpfpm.png
│ └── markdown
│ │ └── README.md
├── Ping
│ ├── alerts
│ │ └── ping_by_categraf.json
│ ├── collect
│ │ └── ping
│ │ │ └── ping.toml
│ ├── dashboards
│ │ ├── ping_by_categraf_a.json
│ │ └── ping_by_categraf_b.json
│ ├── icon
│ │ └── ping.png
│ ├── markdown
│ │ └── README.md
│ └── metrics
│ │ └── categraf.json
├── PostgreSQL
│ ├── alerts
│ │ └── postgresql_by_categraf.json
│ ├── collect
│ │ └── postgresql
│ │ │ └── postgresql.toml
│ ├── dashboards
│ │ └── postgresql_by_categraf.json
│ ├── icon
│ │ └── postgresql.png
│ └── markdown
│ │ ├── README.md
│ │ ├── alerts-pg.png
│ │ ├── alerts.png
│ │ ├── dash-pg.png
│ │ └── postgresql.png
├── Procstat
│ ├── alerts
│ │ └── categraf-procstat.json
│ ├── collect
│ │ └── procstat
│ │ │ └── procstat.toml
│ ├── dashboards
│ │ └── categraf-procstat.json
│ ├── icon
│ │ └── process.png
│ ├── markdown
│ │ └── readme.md
│ └── metrics
│ │ └── categraf.json
├── Prometheus
│ ├── collect
│ │ └── prometheus
│ │ │ └── prometheus.toml
│ ├── icon
│ │ └── prometheus.png
│ └── markdown
│ │ └── README.md
├── RabbitMQ
│ ├── alerts
│ │ └── alerts.json
│ ├── collect
│ │ └── rabbitmq
│ │ │ └── rabbitmq.toml
│ ├── dashboards
│ │ ├── rabbitmq_CN_v3.8_gt.json
│ │ ├── rabbitmq_by_categraf.json
│ │ ├── rabbitmq_v3.8_gt.json
│ │ └── rabbitmq_v3.8_lt.json
│ ├── icon
│ │ └── rabbitmq.png
│ └── markdown
│ │ ├── README.md
│ │ └── rabbitmq.png
├── Redis
│ ├── alerts
│ │ ├── redis_by_categraf.json
│ │ └── redis_by_exporter.json
│ ├── collect
│ │ ├── redis
│ │ │ └── redis.toml
│ │ └── redis_sentinel
│ │ │ └── redis_sentinel.toml
│ ├── dashboards
│ │ ├── FilterByAddress.json
│ │ ├── redis_by_categraf.json
│ │ └── redis_by_exporter.json
│ ├── icon
│ │ └── redis.png
│ └── markdown
│ │ └── README.md
├── SMART
│ ├── collect
│ │ └── smart
│ │ │ └── smart.toml
│ ├── dashboards
│ │ └── smart.json
│ ├── icon
│ │ └── smart.png
│ └── markdown
│ │ └── README.md
├── SNMP
│ ├── collect
│ │ └── snmp
│ │ │ ├── Cisco.toml
│ │ │ ├── snmp.toml
│ │ │ └── snmp.toml.example
│ ├── dashboards
│ │ ├── dashboards.json
│ │ ├── switch branch.json
│ │ └── switch main.json
│ ├── icon
│ │ └── snmp.png
│ └── markdown
│ │ └── README.md
├── SQLServer
│ ├── collect
│ │ └── sqlserver
│ │ │ └── sqlserver.toml
│ ├── dashboards
│ │ └── sqlserver.json
│ ├── icon
│ │ └── sqlserver.png
│ └── markdown
│ │ └── README.md
├── SpringBoot
│ ├── alerts
│ │ └── alerts.json
│ ├── dashboards
│ │ ├── JVM(Actuator)withapplicationname.json
│ │ └── JVM.json
│ ├── icon
│ │ └── springboot.png
│ └── markdown
│ │ ├── README.md
│ │ ├── actuator.jpeg
│ │ └── actuator_2.0.png
├── Switch_Legacy
│ ├── collect
│ │ └── switch_legacy
│ │ │ └── switch_legacy.toml
│ ├── dashboards
│ │ └── dashboard.json
│ ├── icon
│ │ └── switch_legacy.png
│ └── markdown
│ │ └── README.md
├── Systemd
│ ├── collect
│ │ └── systemd
│ │ │ └── systemd.toml
│ ├── icon
│ │ └── systemd.png
│ └── markdown
│ │ └── README.md
├── TDEngine
│ ├── dashboards
│ │ └── tasokeeper3.x.json
│ ├── icon
│ │ └── tdengine.png
│ └── markdown
│ │ └── README.md
├── TiDB
│ ├── alerts
│ │ └── tidb-alerts.json
│ ├── dashboards
│ │ └── tidb-dashboard.json
│ └── icon
│ │ └── tidb.png
├── Tomcat
│ ├── collect
│ │ └── tomcat
│ │ │ └── tomcat.toml
│ ├── dashboards
│ │ └── tomcat_by_categraf.json
│ ├── icon
│ │ └── tomcat.png
│ └── markdown
│ │ └── README.md
├── VictoriaMetrics
│ ├── alerts
│ │ └── alerts.json
│ ├── dashboards
│ │ ├── victoriametrics-cluster.json
│ │ └── victoriametrics-single.json
│ ├── icon
│ │ └── VictoriaMetrics.png
│ └── markdown
│ │ ├── README.md
│ │ ├── alerts-vm.png
│ │ ├── alerts.png
│ │ ├── dash-vm.png
│ │ └── dashboard.png
├── Whois
│ ├── collect
│ │ └── whois
│ │ │ └── whois.toml
│ ├── icon
│ │ └── whois.png
│ └── markdown
│ │ └── README.md
├── Windows
│ ├── alerts
│ │ ├── windows_by_categraf.json
│ │ └── windows_by_exporter.json
│ ├── dashboards
│ │ ├── windows_by_categraf.json
│ │ └── windows_by_exporter.json
│ ├── icon
│ │ └── windows.png
│ └── markdown
│ │ ├── README.md
│ │ └── windows.png
├── XSKYApi
│ ├── collect
│ │ └── xskyapi
│ │ │ └── xskyapi.toml
│ ├── icon
│ │ └── xsky.png
│ └── markdown
│ │ └── README.md
├── ZooKeeper
│ ├── alerts
│ │ └── zookeeper_by_exporter.json
│ ├── collect
│ │ └── zookeeper
│ │ │ └── zookeeper.toml
│ ├── dashboards
│ │ └── zookeeper_by_exporter.json
│ ├── icon
│ │ └── zookeeper.png
│ └── markdown
│ │ └── README.md
├── cAdvisor
│ ├── collect
│ │ └── cadvisor
│ │ │ └── cadvisor.toml
│ ├── dashboards
│ │ └── dashboard.json
│ ├── icon
│ │ └── cadvisor.png
│ ├── markdown
│ │ └── README.md
│ └── metrics
│ │ └── exporter-base.json
└── vSphere
│ ├── alerts
│ └── alerts.json
│ ├── collect
│ └── vsphere
│ │ └── vsphere.toml
│ ├── dashboards
│ ├── vmware_by_vsphere-monitor.json
│ └── vsphere.json
│ ├── icon
│ └── vsphere.png
│ └── markdown
│ └── README.md
├── memsto
├── alert_mute_cache.go
├── alert_rule_cache.go
├── alert_subscribe_cache.go
├── busi_group_cache.go
├── config_cache.go
├── config_cval_cache.go
├── datasource_cache.go
├── drop_ident.go
├── es_index_pattern.go
├── event_processor_cache.go
├── host_alert_rule_targets.go
├── memsto.go
├── message_template_cache.go
├── notify_channel_cache.go
├── notify_config.go
├── notify_rule_cache.go
├── recording_rule_cache.go
├── stat.go
├── target_cache.go
├── task_tpl_cache.go
├── user_cache.go
├── user_group_cache.go
└── user_token_cache.go
├── models
├── alert_aggr_view.go
├── alert_cur_event.go
├── alert_his_event.go
├── alert_mute.go
├── alert_rule.go
├── alert_subscribe.go
├── alerting_engine.go
├── anomaly_point.go
├── board.go
├── board_busi.go
├── board_payload.go
├── builtin_cate.go
├── builtin_component.go
├── builtin_metrics.go
├── builtin_metrics_filter.go
├── builtin_payload.go
├── busi_group.go
├── busi_group_member.go
├── chart.go
├── chart_group.go
├── chart_share.go
├── common.go
├── configs.go
├── dash_annotation.go
├── dashboard.go
├── datasource.go
├── embedded_product.go
├── es_index_pattern.go
├── event_pipeline.go
├── event_processor.go
├── host_meta.go
├── message_tpl.go
├── metric_view.go
├── migrate
│ ├── migrate.go
│ ├── migrate_es_index_pattern.go
│ └── migrate_test.go
├── notification_record.go
├── notify_channel.go
├── notify_channel_test.go
├── notify_config.go
├── notify_rule.go
├── notify_tpl.go
├── prom_alert_rule.go
├── prom_alert_rule_test.go
├── recording_rule.go
├── role.go
├── role_operation.go
├── source_token.go
├── sso_config.go
├── target.go
├── target_busi_group.go
├── task_record.go
├── task_tpl.go
├── ts.go
├── user.go
├── user_group.go
├── user_group_member.go
└── user_token.go
├── pkg
├── aop
│ ├── log.go
│ └── rec.go
├── cas
│ └── cas.go
├── cfg
│ ├── cfg.go
│ └── scan.go
├── choice
│ └── choice.go
├── ctx
│ └── ctx.go
├── fasttime
│ └── fasttime.go
├── flashduty
│ ├── post.go
│ ├── sync_user.go
│ └── sync_user_group.go
├── hash
│ ├── hash.go
│ ├── hash_fnv.go
│ └── hash_md5.go
├── httpx
│ └── httpx.go
├── i18nx
│ ├── i18n.go
│ └── var.go
├── ibex
│ └── ibex.go
├── ldapx
│ ├── ldapx.go
│ └── user_sync.go
├── logx
│ └── logx.go
├── macros
│ └── macros.go
├── oauth2x
│ └── oauth2x.go
├── oidcx
│ └── oidc.go
├── ormx
│ ├── database_init.go
│ ├── database_init_test.go
│ ├── ormx.go
│ └── types.go
├── osx
│ └── osx.go
├── parser
│ ├── calc.go
│ └── calc_test.go
├── poster
│ ├── post.go
│ └── post_test.go
├── prom
│ ├── client_option.go
│ ├── conv.go
│ ├── conv_test.go
│ ├── reader.go
│ └── writer.go
├── promql
│ ├── parser.go
│ ├── perser_test.go
│ └── promql.go
├── secu
│ ├── aes.go
│ └── rsa.go
├── slice
│ └── contains.go
├── strx
│ └── verify.go
├── tlsx
│ ├── common.go
│ └── config.go
├── tplx
│ ├── conv.go
│ ├── fns.go
│ ├── tpl_test.go
│ └── tplx.go
├── unit
│ ├── unit_convert.go
│ └── unit_convert_test.go
└── version
│ └── version.go
├── prom
├── client.go
├── option.go
└── reader.go
├── pushgw
├── idents
│ └── idents.go
├── kafka
│ └── producer.go
├── pconf
│ └── conf.go
├── pstat
│ └── pstat.go
├── pushgw.go
├── router
│ ├── fns.go
│ ├── router.go
│ ├── router_datadog.go
│ ├── router_datadog_easyjson.go
│ ├── router_heartbeat.go
│ ├── router_openfalcon.go
│ ├── router_openfalcon_easyjson.go
│ ├── router_opentsdb.go
│ ├── router_opentsdb_easyjson.go
│ ├── router_proxy_remotewrite.go
│ ├── router_remotewrite.go
│ ├── router_target.go
│ └── vars.go
└── writer
│ ├── json
│ └── json-iterator.go
│ ├── kafka_writer.go
│ ├── queue.go
│ ├── relabel.go
│ ├── relabel_test.go
│ └── writer.go
└── storage
├── redis.go
├── redis_test.go
└── storage.go
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.css linguist-language=go
2 | *.less linguist-language=go
3 | *.js linguist-language=go
4 | *.tsx linguist-language=go
5 | *.html linguist-language=go
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Nightingale docs
4 | url: https://n9e.github.io/
5 | about: You may want to read through the document before asking questions.
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/enhancement.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Enhancement Request
3 | about: Suggest an enhancement to the nightingale project
4 | labels: kind/feature
5 |
6 | ---
7 |
8 |
9 | **What would you like to be added**:
10 |
11 | **Why is this needed**:
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report & Usage Question
2 | description: Reporting a bug or asking a question about how to use Nightingale
3 | labels: []
4 |
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | The more detailed the form is filled in, the easier the problem will be solved.
10 | 提供的信息越详细,问题解决的可能性就越大。另外, 提问之前请先搜索历史 issue (包括 close 的), 以免重复提问。
11 | - type: textarea
12 | id: question
13 | attributes:
14 | label: Question and Steps to reproduce
15 | description: Describe your question and steps to reproduce the bug. 描述问题以及复现步骤
16 | validations:
17 | required: true
18 | - type: textarea
19 | id: logs
20 | attributes:
21 | label: Relevant logs and configurations
22 | description: Relevant logs and configurations. 报错日志([查看方法](https://flashcat.cloud/docs/content/flashcat-monitor/nightingale-v6/faq/how-to-check-logs/))以及各个相关组件的配置信息
23 | render: text
24 | validations:
25 | required: true
26 | - type: textarea
27 | id: system-info
28 | attributes:
29 | label: Version
30 | description: Include nightingale version, operating system, and other relevant details. 请告知夜莺的版本、操作系统的版本、CPU架构等信息
31 | validations:
32 | required: true
33 |
34 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **What type of PR is this?**
2 |
3 | **What this PR does / why we need it**:
4 |
7 |
8 | **Which issue(s) this PR fixes**:
9 |
12 | Fixes #
13 |
14 | **Special notes for your reviewer**:
--------------------------------------------------------------------------------
/.github/workflows/n9e.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*'
7 | env:
8 | GO_VERSION: 1.23
9 |
10 | jobs:
11 | goreleaser:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout Source Code
15 | uses: actions/checkout@v3
16 | with:
17 | fetch-depth: 0
18 | - name: Setup Go Environment
19 | uses: actions/setup-go@v3
20 | with:
21 | go-version: ${{ env.GO_VERSION }}
22 | - uses: docker/login-action@v2
23 | with:
24 | username: ${{ secrets.DOCKERHUB_USERNAME }}
25 | password: ${{ secrets.DOCKERHUB_TOKEN }}
26 | - name: Run GoReleaser
27 | uses: goreleaser/goreleaser-action@v3
28 | with:
29 | distribution: goreleaser
30 | version: '~> v1'
31 | args: release --rm-dist
32 | env:
33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.exe
2 | *.exe~
3 | *.dll
4 | *.dylib
5 | *.test
6 | *.out
7 | *.prof
8 | *.log
9 | *.o
10 | *.a
11 | *.so
12 | *.db
13 | *.sw[po]
14 | *.tar.gz
15 | *.[568vq]
16 | [568vq].out
17 |
18 | *.cgo1.go
19 | *.cgo2.c
20 | _cgo_defun.c
21 | _cgo_gotypes.go
22 | _cgo_export.*
23 | _testmain.go
24 | _obj
25 | _test
26 |
27 | /log*
28 | /bin
29 | /out
30 | /build
31 | /dist
32 | /etc/*.local.yml
33 | /etc/*.local.conf
34 | /etc/rsa/*
35 | /etc/plugins/*.local.yml
36 | /etc/script/rules.yaml
37 | /etc/script/alert-rules.json
38 | /etc/script/record-rules.json
39 | /data*
40 | /tarball
41 | /run
42 | /vendor
43 | /tmp
44 | /pub
45 | /n9e
46 | /docker/pub
47 | /docker/n9e
48 | /docker/compose-bridge/mysqldata
49 | /docker/compose-host-network/mysqldata
50 | /docker/compose-host-network-metric-log/mysqldata
51 | /docker/compose-host-network-metric-log/n9e-logs
52 | /docker/compose-postgres/pgdata
53 | /etc.local*
54 | /front/statik/statik.go
55 | /docker/compose-bridge/etc-nightingale/rsa/
56 |
57 | .alerts
58 | .idea
59 | .index
60 | .vscode
61 | .DS_Store
62 | .cache-loader
63 | .payload
64 | queries.active
65 |
66 | /n9e-*
67 | n9e.sql
68 |
69 | !/datasource
70 |
71 | .env.json
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: prebuild build
2 |
3 | ROOT:=$(shell pwd -P)
4 | GIT_COMMIT:=$(shell git --work-tree ${ROOT} rev-parse 'HEAD^{commit}')
5 | _GIT_VERSION:=$(shell git --work-tree ${ROOT} describe --tags --abbrev=14 "${GIT_COMMIT}^{commit}" 2>/dev/null)
6 | TAG=$(shell echo "${_GIT_VERSION}" | awk -F"-" '{print $$1}')
7 | RELEASE_VERSION:="$(TAG)-$(GIT_COMMIT)"
8 |
9 | all: prebuild build
10 |
11 | prebuild:
12 | echo "begin download and embed the front-end file..."
13 | sh fe.sh
14 | echo "front-end file download and embedding completed."
15 |
16 | build:
17 | go build -ldflags "-w -s -X github.com/ccfos/nightingale/v6/pkg/version.Version=$(RELEASE_VERSION)" -o n9e ./cmd/center/main.go
18 |
19 | build-edge:
20 | go build -ldflags "-w -s -X github.com/ccfos/nightingale/v6/pkg/version.Version=$(RELEASE_VERSION)" -o n9e-edge ./cmd/edge/
21 |
22 | build-alert:
23 | go build -ldflags "-w -s -X github.com/ccfos/nightingale/v6/pkg/version.Version=$(RELEASE_VERSION)" -o n9e-alert ./cmd/alert/main.go
24 |
25 | build-pushgw:
26 | go build -ldflags "-w -s -X github.com/ccfos/nightingale/v6/pkg/version.Version=$(RELEASE_VERSION)" -o n9e-pushgw ./cmd/pushgw/main.go
27 |
28 | build-cli:
29 | go build -ldflags "-w -s -X github.com/ccfos/nightingale/v6/pkg/version.Version=$(RELEASE_VERSION)" -o n9e-cli ./cmd/cli/main.go
30 |
31 | run:
32 | nohup ./n9e > n9e.log 2>&1 &
33 |
34 | run-alert:
35 | nohup ./n9e-alert > n9e-alert.log 2>&1 &
36 |
37 | run-pushgw:
38 | nohup ./n9e-pushgw > n9e-pushgw.log 2>&1 &
39 |
40 | release:
41 | goreleaser --skip-validate --skip-publish --snapshot
--------------------------------------------------------------------------------
/alert/aconf/conf.go:
--------------------------------------------------------------------------------
1 | package aconf
2 |
3 | import (
4 | "path"
5 | )
6 |
7 | type Alert struct {
8 | Disable bool
9 | EngineDelay int64
10 | Heartbeat HeartbeatConfig
11 | Alerting Alerting
12 | }
13 |
14 | type SMTPConfig struct {
15 | Host string
16 | Port int
17 | User string
18 | Pass string
19 | From string
20 | InsecureSkipVerify bool
21 | Batch int
22 | }
23 |
24 | type HeartbeatConfig struct {
25 | IP string
26 | Interval int64
27 | Endpoint string
28 | EngineName string
29 | }
30 |
31 | type Alerting struct {
32 | Timeout int64
33 | TemplatesDir string
34 | NotifyConcurrency int
35 | WebhookBatchSend bool
36 | }
37 |
38 | type CallPlugin struct {
39 | Enable bool
40 | PluginPath string
41 | Caller string
42 | }
43 |
44 | type RedisPub struct {
45 | Enable bool
46 | ChannelPrefix string
47 | ChannelKey string
48 | }
49 |
50 | func (a *Alert) PreCheck(configDir string) {
51 | if a.Alerting.TemplatesDir == "" {
52 | a.Alerting.TemplatesDir = path.Join(configDir, "template")
53 | }
54 |
55 | if a.Alerting.NotifyConcurrency == 0 {
56 | a.Alerting.NotifyConcurrency = 10
57 | }
58 |
59 | if a.Heartbeat.Interval == 0 {
60 | a.Heartbeat.Interval = 1000
61 | }
62 |
63 | if a.EngineDelay == 0 {
64 | a.EngineDelay = 30
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/alert/common/key.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/ccfos/nightingale/v6/models"
8 | )
9 |
10 | func RuleKey(datasourceId, id int64) string {
11 | return fmt.Sprintf("alert-%d-%d", datasourceId, id)
12 | }
13 |
14 | func MatchTags(eventTagsMap map[string]string, itags []models.TagFilter) bool {
15 | for _, filter := range itags {
16 | value, has := eventTagsMap[filter.Key]
17 | if !has {
18 | return false
19 | }
20 | if !matchTag(value, filter) {
21 | return false
22 | }
23 | }
24 | return true
25 | }
26 | func MatchGroupsName(groupName string, groupFilter []models.TagFilter) bool {
27 | for _, filter := range groupFilter {
28 | if !matchTag(groupName, filter) {
29 | return false
30 | }
31 | }
32 | return true
33 | }
34 |
35 | func matchTag(value string, filter models.TagFilter) bool {
36 | switch filter.Func {
37 | case "==":
38 | return strings.TrimSpace(filter.Value) == strings.TrimSpace(value)
39 | case "!=":
40 | return strings.TrimSpace(filter.Value) != strings.TrimSpace(value)
41 | case "in":
42 | _, has := filter.Vset[value]
43 | return has
44 | case "not in":
45 | _, has := filter.Vset[value]
46 | return !has
47 | case "=~":
48 | return filter.Regexp.MatchString(value)
49 | case "!~":
50 | return !filter.Regexp.MatchString(value)
51 | }
52 | // unexpect func
53 | return false
54 | }
55 |
--------------------------------------------------------------------------------
/alert/dispatch/log.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | import (
4 | "github.com/ccfos/nightingale/v6/models"
5 |
6 | "github.com/toolkits/pkg/logger"
7 | )
8 |
9 | func LogEvent(event *models.AlertCurEvent, location string, err ...error) {
10 | status := "triggered"
11 | if event.IsRecovered {
12 | status = "recovered"
13 | }
14 |
15 | message := ""
16 | if len(err) > 0 && err[0] != nil {
17 | message = "error_message: " + err[0].Error()
18 | }
19 |
20 | logger.Infof(
21 | "event(%s %s) %s: rule_id=%d sub_id:%d notify_rule_ids:%v cluster:%s %v%s@%d %s",
22 | event.Hash,
23 | status,
24 | location,
25 | event.RuleId,
26 | event.SubRuleId,
27 | event.NotifyRuleIds,
28 | event.Cluster,
29 | event.TagsJSON,
30 | event.TriggerValue,
31 | event.TriggerTime,
32 | message,
33 | )
34 | }
35 |
--------------------------------------------------------------------------------
/alert/dispatch/notify_channel.go:
--------------------------------------------------------------------------------
1 | package dispatch
2 |
3 | // NotifyChannels channelKey -> bool
4 | type NotifyChannels map[string]bool
5 |
6 | func NewNotifyChannels(channels []string) NotifyChannels {
7 | nc := make(NotifyChannels)
8 | for _, ch := range channels {
9 | nc[ch] = true
10 | }
11 | return nc
12 | }
13 |
14 | func (nc NotifyChannels) OrMerge(other NotifyChannels) {
15 | nc.merge(other, func(a, b bool) bool { return a || b })
16 | }
17 |
18 | func (nc NotifyChannels) AndMerge(other NotifyChannels) {
19 | nc.merge(other, func(a, b bool) bool { return a && b })
20 | }
21 |
22 | func (nc NotifyChannels) merge(other NotifyChannels, f func(bool, bool) bool) {
23 | if other == nil {
24 | return
25 | }
26 | for k, v := range other {
27 | if curV, has := nc[k]; has {
28 | nc[k] = f(curV, v)
29 | } else {
30 | nc[k] = v
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/alert/naming/leader.go:
--------------------------------------------------------------------------------
1 | package naming
2 |
3 | import (
4 | "sort"
5 |
6 | "github.com/toolkits/pkg/logger"
7 | )
8 |
9 | func (n *Naming) IamLeader() bool {
10 | if !n.ctx.IsCenter {
11 | return false
12 | }
13 |
14 | servers, err := n.ActiveServersByEngineName()
15 | if err != nil {
16 | logger.Errorf("failed to get active servers: %v", err)
17 | return false
18 | }
19 |
20 | if len(servers) == 0 {
21 | logger.Errorf("active servers empty")
22 | return false
23 | }
24 |
25 | sort.Strings(servers)
26 |
27 | return n.heartbeatConfig.Endpoint == servers[0]
28 | }
29 |
--------------------------------------------------------------------------------
/alert/pipeline/pipeline.go:
--------------------------------------------------------------------------------
1 | package pipeline
2 |
3 | import (
4 | _ "github.com/ccfos/nightingale/v6/alert/pipeline/processor/callback"
5 | _ "github.com/ccfos/nightingale/v6/alert/pipeline/processor/eventdrop"
6 | _ "github.com/ccfos/nightingale/v6/alert/pipeline/processor/eventupdate"
7 | _ "github.com/ccfos/nightingale/v6/alert/pipeline/processor/relabel"
8 | )
9 |
10 | func Init() {
11 | }
12 |
--------------------------------------------------------------------------------
/alert/pipeline/processor/common/common.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import (
4 | "encoding/json"
5 | )
6 |
7 | // InitProcessor 是一个通用的初始化处理器的方法
8 | // 使用泛型简化处理器初始化逻辑
9 | // T 必须是 models.Processor 接口的实现
10 | func InitProcessor[T any](settings interface{}) (T, error) {
11 | var zero T
12 | b, err := json.Marshal(settings)
13 | if err != nil {
14 | return zero, err
15 | }
16 |
17 | var result T
18 | err = json.Unmarshal(b, &result)
19 | if err != nil {
20 | return zero, err
21 | }
22 |
23 | return result, nil
24 | }
25 |
--------------------------------------------------------------------------------
/alert/queue/queue.go:
--------------------------------------------------------------------------------
1 | package queue
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/ccfos/nightingale/v6/alert/astats"
7 | "github.com/toolkits/pkg/container/list"
8 | )
9 |
10 | var EventQueue = list.NewSafeListLimited(10000000)
11 |
12 | func ReportQueueSize(stats *astats.Stats) {
13 | for {
14 | time.Sleep(time.Second)
15 |
16 | stats.GaugeAlertQueueSize.Set(float64(EventQueue.Len()))
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/alert/sender/plugin_cmd_unix.go:
--------------------------------------------------------------------------------
1 | //go:build !windows
2 | // +build !windows
3 |
4 | package sender
5 |
6 | import (
7 | "os/exec"
8 | "syscall"
9 | )
10 |
11 | func startCmd(c *exec.Cmd) error {
12 | c.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
13 | return c.Start()
14 | }
15 |
--------------------------------------------------------------------------------
/alert/sender/plugin_cmd_windows.go:
--------------------------------------------------------------------------------
1 | package sender
2 |
3 | import "os/exec"
4 |
5 | func startCmd(c *exec.Cmd) error {
6 | return c.Start()
7 | }
8 |
--------------------------------------------------------------------------------
/center/cconf/conf.go:
--------------------------------------------------------------------------------
1 | package cconf
2 |
3 | import "time"
4 |
5 | type Center struct {
6 | Plugins []Plugin
7 | MetricsYamlFile string
8 | OpsYamlFile string
9 | BuiltinIntegrationsDir string
10 | I18NHeaderKey string
11 | MetricDesc MetricDescType
12 | AnonymousAccess AnonymousAccess
13 | UseFileAssets bool
14 | FlashDuty FlashDuty
15 | EventHistoryGroupView bool
16 | CleanNotifyRecordDay int
17 | MigrateBusiGroupLabel bool
18 | }
19 |
20 | type Plugin struct {
21 | Id int64 `json:"id"`
22 | Category string `json:"category"`
23 | Type string `json:"plugin_type"`
24 | TypeName string `json:"plugin_type_name"`
25 | }
26 |
27 | type FlashDuty struct {
28 | Api string
29 | Headers map[string]string
30 | Timeout time.Duration
31 | }
32 |
33 | type AnonymousAccess struct {
34 | PromQuerier bool
35 | AlertDetail bool
36 | }
37 |
38 | func (c *Center) PreCheck() {
39 | if len(c.Plugins) == 0 {
40 | c.Plugins = Plugins
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/center/cconf/event_example.go:
--------------------------------------------------------------------------------
1 | package cconf
2 |
3 | const EVENT_EXAMPLE = `
4 | {
5 | "id": 1000000,
6 | "cate": "prometheus",
7 | "datasource_id": 1,
8 | "group_id": 1,
9 | "group_name": "Default Busi Group",
10 | "hash": "2cb966f9ba1cdc7af94c3796e855955a",
11 | "rule_id": 23,
12 | "rule_name": "测试告警",
13 | "rule_note": "测试告警",
14 | "rule_prod": "metric",
15 | "rule_config": {
16 | "queries": [
17 | {
18 | "key": "all_hosts",
19 | "op": "==",
20 | "values": []
21 | }
22 | ],
23 | "triggers": [
24 | {
25 | "duration": 3,
26 | "percent": 10,
27 | "severity": 3,
28 | "type": "pct_target_miss"
29 | }
30 | ]
31 | },
32 | "prom_for_duration": 60,
33 | "prom_eval_interval": 30,
34 | "callbacks": ["https://n9e.github.io"],
35 | "notify_recovered": 1,
36 | "notify_channels": ["dingtalk"],
37 | "notify_groups": [],
38 | "notify_groups_obj": null,
39 | "target_ident": "host01",
40 | "target_note": "机器备注",
41 | "trigger_time": 1677229517,
42 | "trigger_value": "2273533952",
43 | "tags": [
44 | "__name__=disk_free",
45 | "dc=qcloud-dev",
46 | "device=vda1",
47 | "fstype=ext4",
48 | "ident=tt-fc-dev00.nj"
49 | ],
50 | "is_recovered": false,
51 | "notify_users_obj": null,
52 | "last_eval_time": 1677229517,
53 | "last_sent_time": 1677229517,
54 | "notify_cur_number": 1,
55 | "first_trigger_time": 1677229517,
56 | "annotations": {
57 | "summary": "测试告警"
58 | }
59 | }
60 | `
61 |
--------------------------------------------------------------------------------
/center/cconf/metric.go:
--------------------------------------------------------------------------------
1 | package cconf
2 |
3 | import (
4 | "path"
5 |
6 | "github.com/toolkits/pkg/file"
7 | )
8 |
9 | // metricDesc , As load map happens before read map, there is no necessary to use concurrent map for metric desc store
10 | type MetricDescType struct {
11 | CommonDesc map[string]string `yaml:",inline" json:"common"`
12 | Zh map[string]string `yaml:"zh" json:"zh"`
13 | En map[string]string `yaml:"en" json:"en"`
14 | }
15 |
16 | var MetricDesc MetricDescType
17 |
18 | // GetMetricDesc , if metric is not registered, empty string will be returned
19 | func GetMetricDesc(lang, metric string) string {
20 | var m map[string]string
21 |
22 | switch lang {
23 | case "en":
24 | m = MetricDesc.En
25 | default:
26 | m = MetricDesc.Zh
27 | }
28 |
29 | if m != nil {
30 | if desc, ok := m[metric]; ok {
31 | return desc
32 | }
33 | }
34 |
35 | if MetricDesc.CommonDesc != nil {
36 | if desc, ok := MetricDesc.CommonDesc[metric]; ok {
37 | return desc
38 | }
39 | }
40 |
41 | return ""
42 | }
43 | func LoadMetricsYaml(configDir, metricsYamlFile string) error {
44 | fp := metricsYamlFile
45 | if fp == "" {
46 | fp = path.Join(configDir, "metrics.yaml")
47 | }
48 | if !file.IsExist(fp) {
49 | return nil
50 | }
51 | return file.ReadYaml(fp, &MetricDesc)
52 | }
53 |
--------------------------------------------------------------------------------
/center/cconf/plugin.go:
--------------------------------------------------------------------------------
1 | package cconf
2 |
3 | var Plugins = []Plugin{
4 | {
5 | Id: 1,
6 | Category: "timeseries",
7 | Type: "prometheus",
8 | TypeName: "Prometheus Like",
9 | },
10 | {
11 | Id: 2,
12 | Category: "logging",
13 | Type: "elasticsearch",
14 | TypeName: "Elasticsearch",
15 | },
16 | {
17 | Id: 3,
18 | Category: "loki",
19 | Type: "loki",
20 | TypeName: "Loki",
21 | },
22 | {
23 | Id: 4,
24 | Category: "timeseries",
25 | Type: "tdengine",
26 | TypeName: "TDengine",
27 | },
28 | {
29 | Id: 5,
30 | Category: "logging",
31 | Type: "ck",
32 | TypeName: "ClickHouse",
33 | },
34 | }
35 |
--------------------------------------------------------------------------------
/center/cstats/stats.go:
--------------------------------------------------------------------------------
1 | package cstats
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/prometheus/client_golang/prometheus"
7 | )
8 |
9 | const (
10 | namespace = "n9e"
11 | subsystem = "center"
12 | )
13 |
14 | var (
15 | uptime = prometheus.NewCounter(
16 | prometheus.CounterOpts{
17 | Namespace: namespace,
18 | Subsystem: subsystem,
19 | Name: "uptime",
20 | Help: "HTTP service uptime.",
21 | },
22 | )
23 |
24 | RequestDuration = prometheus.NewHistogramVec(
25 | prometheus.HistogramOpts{
26 | Namespace: namespace,
27 | Subsystem: subsystem,
28 | Buckets: prometheus.DefBuckets,
29 | Name: "http_request_duration_seconds",
30 | Help: "HTTP request latencies in seconds.",
31 | }, []string{"code", "path", "method"},
32 | )
33 |
34 | RedisOperationLatency = prometheus.NewHistogramVec(
35 | prometheus.HistogramOpts{
36 | Namespace: namespace,
37 | Subsystem: subsystem,
38 | Name: "redis_operation_latency_seconds",
39 | Help: "Histogram of latencies for Redis operations",
40 | Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5},
41 | },
42 | []string{"operation", "status"},
43 | )
44 | )
45 |
46 | func init() {
47 | // Register the summary and the histogram with Prometheus's default registry.
48 | prometheus.MustRegister(
49 | uptime,
50 | RequestDuration,
51 | RedisOperationLatency,
52 | )
53 |
54 | go recordUptime()
55 | }
56 |
57 | // recordUptime increases service uptime per second.
58 | func recordUptime() {
59 | for range time.Tick(time.Second) {
60 | uptime.Inc()
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/center/router/router_chart_share.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/ccfos/nightingale/v6/models"
7 | "github.com/ccfos/nightingale/v6/pkg/strx"
8 |
9 | "github.com/gin-gonic/gin"
10 | "github.com/toolkits/pkg/ginx"
11 | )
12 |
13 | func (rt *Router) chartShareGets(c *gin.Context) {
14 | ids := ginx.QueryStr(c, "ids", "")
15 | lst, err := models.ChartShareGetsByIds(rt.Ctx, strx.IdsInt64ForAPI(ids, ","))
16 | ginx.NewRender(c).Data(lst, err)
17 | }
18 |
19 | type chartShareForm struct {
20 | DatasourceId int64 `json:"datasource_id"`
21 | Configs string `json:"configs"`
22 | }
23 |
24 | func (rt *Router) chartShareAdd(c *gin.Context) {
25 | username := c.MustGet("username").(string)
26 |
27 | var forms []chartShareForm
28 | ginx.BindJSON(c, &forms)
29 |
30 | ids := []int64{}
31 | now := time.Now().Unix()
32 |
33 | for _, f := range forms {
34 | chart := models.ChartShare{
35 | DatasourceId: f.DatasourceId,
36 | Configs: f.Configs,
37 | CreateBy: username,
38 | CreateAt: now,
39 | }
40 | ginx.Dangerous(chart.Add(rt.Ctx))
41 | ids = append(ids, chart.Id)
42 | }
43 |
44 | ginx.NewRender(c).Data(ids, nil)
45 | }
46 |
--------------------------------------------------------------------------------
/center/router/router_crypto.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/ccfos/nightingale/v6/pkg/secu"
5 |
6 | "github.com/gin-gonic/gin"
7 | "github.com/toolkits/pkg/ginx"
8 | )
9 |
10 | type confPropCrypto struct {
11 | Data string `json:"data" binding:"required"`
12 | Key string `json:"key" binding:"required"`
13 | }
14 |
15 | func (rt *Router) confPropEncrypt(c *gin.Context) {
16 | var f confPropCrypto
17 | ginx.BindJSON(c, &f)
18 |
19 | k := len(f.Key)
20 | switch k {
21 | default:
22 | c.String(400, "The key length should be 16, 24 or 32")
23 | return
24 | case 16, 24, 32:
25 | break
26 | }
27 |
28 | s, err := secu.DealWithEncrypt(f.Data, f.Key)
29 | if err != nil {
30 | c.String(500, err.Error())
31 | }
32 |
33 | c.JSON(200, gin.H{
34 | "src": f.Data,
35 | "key": f.Key,
36 | "encrypt": s,
37 | })
38 | }
39 |
40 | func (rt *Router) confPropDecrypt(c *gin.Context) {
41 | var f confPropCrypto
42 | ginx.BindJSON(c, &f)
43 |
44 | k := len(f.Key)
45 | switch k {
46 | default:
47 | c.String(400, "The key length should be 16, 24 or 32")
48 | return
49 | case 16, 24, 32:
50 | break
51 | }
52 |
53 | s, err := secu.DealWithDecrypt(f.Data, f.Key)
54 | if err != nil {
55 | c.String(500, err.Error())
56 | }
57 |
58 | c.JSON(200, gin.H{
59 | "src": f.Data,
60 | "key": f.Key,
61 | "decrypt": s,
62 | })
63 | }
64 |
--------------------------------------------------------------------------------
/center/router/router_dashboard.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | type ChartPure struct {
4 | Configs string `json:"configs"`
5 | Weight int `json:"weight"`
6 | }
7 |
8 | type ChartGroupPure struct {
9 | Name string `json:"name"`
10 | Weight int `json:"weight"`
11 | Charts []ChartPure `json:"charts"`
12 | }
13 |
14 | type DashboardPure struct {
15 | Name string `json:"name"`
16 | Tags string `json:"tags"`
17 | Configs string `json:"configs"`
18 | ChartGroups []ChartGroupPure `json:"chart_groups"`
19 | }
20 |
--------------------------------------------------------------------------------
/center/router/router_notify_channel_test.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func TestGetFlashDutyChannels(t *testing.T) {
9 | // 构造测试数据
10 | integrationUrl := "https://api.flashcat.cloud/event/push/alert/n9e?integration_key=xxx"
11 | jsonData := []byte(`{}`)
12 |
13 | // 调用被测试的函数
14 | channels, err := getFlashDutyChannels(integrationUrl, jsonData)
15 |
16 | fmt.Println(channels, err)
17 | }
18 |
--------------------------------------------------------------------------------
/center/router/router_server.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/ccfos/nightingale/v6/models"
7 |
8 | "github.com/gin-gonic/gin"
9 | "github.com/toolkits/pkg/ginx"
10 | )
11 |
12 | func (rt *Router) serversGet(c *gin.Context) {
13 | list, err := models.AlertingEngineGets(rt.Ctx, "")
14 | ginx.NewRender(c).Data(list, err)
15 | }
16 |
17 | func (rt *Router) serverClustersGet(c *gin.Context) {
18 | list, err := models.AlertingEngineGetsClusters(rt.Ctx, "")
19 | ginx.NewRender(c).Data(list, err)
20 | }
21 |
22 | func (rt *Router) serverHeartbeat(c *gin.Context) {
23 | var req models.HeartbeatInfo
24 | ginx.BindJSON(c, &req)
25 | err := models.AlertingEngineHeartbeatWithCluster(rt.Ctx, req.Instance, req.EngineCluster, req.DatasourceId)
26 | ginx.NewRender(c).Message(err)
27 | }
28 |
29 | func (rt *Router) serversActive(c *gin.Context) {
30 | datasourceId := ginx.QueryInt64(c, "dsid", 0)
31 | engineName := ginx.QueryStr(c, "engine_name", "")
32 | if engineName != "" {
33 | servers, err := models.AlertingEngineGetsInstances(rt.Ctx, "engine_cluster = ? and clock > ?", engineName, time.Now().Unix()-30)
34 | ginx.NewRender(c).Data(servers, err)
35 | return
36 | }
37 |
38 | if datasourceId == 0 {
39 | ginx.NewRender(c).Message("dsid is required")
40 | return
41 | }
42 | servers, err := models.AlertingEngineGetsInstances(rt.Ctx, "datasource_id = ? and clock > ?", datasourceId, time.Now().Unix()-30)
43 | ginx.NewRender(c).Data(servers, err)
44 | }
45 |
--------------------------------------------------------------------------------
/center/router/router_source_token.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "net/http"
5 | "time"
6 |
7 | "github.com/ccfos/nightingale/v6/models"
8 | "github.com/google/uuid"
9 |
10 | "github.com/gin-gonic/gin"
11 | "github.com/toolkits/pkg/ginx"
12 | )
13 |
14 | // sourceTokenAdd 生成新的源令牌
15 | func (rt *Router) sourceTokenAdd(c *gin.Context) {
16 | var f models.SourceToken
17 | ginx.BindJSON(c, &f)
18 |
19 | if f.ExpireAt > 0 && f.ExpireAt <= time.Now().Unix() {
20 | ginx.Bomb(http.StatusBadRequest, "expire time must be in the future")
21 | }
22 |
23 | token := uuid.New().String()
24 |
25 | username := c.MustGet("username").(string)
26 |
27 | f.Token = token
28 | f.CreateBy = username
29 | f.CreateAt = time.Now().Unix()
30 |
31 | err := f.Add(rt.Ctx)
32 | ginx.Dangerous(err)
33 |
34 | go models.CleanupExpiredTokens(rt.Ctx)
35 | ginx.NewRender(c).Data(token, nil)
36 | }
37 |
--------------------------------------------------------------------------------
/center/sso/sync.go:
--------------------------------------------------------------------------------
1 | package sso
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ccfos/nightingale/v6/pkg/ctx"
7 | "github.com/toolkits/pkg/logger"
8 | )
9 |
10 | func (s *SsoClient) SyncSsoUsers(ctx *ctx.Context) {
11 | if err := s.LDAP.SyncAddAndDelUsers(ctx); err != nil {
12 | fmt.Println("failed to sync the addition and deletion of ldap users:", err)
13 | }
14 |
15 | if err := s.LDAP.SyncDelUsers(ctx); err != nil {
16 | fmt.Println("failed to sync deletion of ldap users:", err)
17 | }
18 |
19 | go s.loopSyncSsoUsers(ctx)
20 | }
21 |
22 | func (s *SsoClient) loopSyncSsoUsers(ctx *ctx.Context) {
23 | for {
24 | select {
25 | case <-s.LDAP.Ticker.C:
26 | lc := s.LDAP.Copy()
27 |
28 | if err := lc.SyncAddAndDelUsers(ctx); err != nil {
29 | logger.Warningf("failed to sync the addition and deletion of ldap users: %v", err)
30 | }
31 |
32 | if err := lc.SyncDelUsers(ctx); err != nil {
33 | logger.Warningf("failed to sync deletion of ldap users: %v", err)
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/cli/cli.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "github.com/ccfos/nightingale/v6/cli/upgrade"
5 | )
6 |
7 | func Upgrade(configFile string) error {
8 | return upgrade.Upgrade(configFile)
9 | }
10 |
--------------------------------------------------------------------------------
/cli/upgrade/config.go:
--------------------------------------------------------------------------------
1 | package upgrade
2 |
3 | import (
4 | "bytes"
5 | "path"
6 |
7 | "github.com/ccfos/nightingale/v6/pkg/cfg"
8 | "github.com/ccfos/nightingale/v6/pkg/ormx"
9 | "github.com/ccfos/nightingale/v6/pkg/tlsx"
10 | "github.com/koding/multiconfig"
11 | )
12 |
13 | type Config struct {
14 | DB ormx.DBConfig
15 | Clusters []ClusterOptions
16 | }
17 |
18 | type ClusterOptions struct {
19 | Name string
20 | Prom string
21 |
22 | BasicAuthUser string
23 | BasicAuthPass string
24 |
25 | Headers []string
26 |
27 | Timeout int64
28 | DialTimeout int64
29 |
30 | UseTLS bool
31 | tlsx.ClientConfig
32 |
33 | MaxIdleConnsPerHost int
34 | }
35 |
36 | func Parse(fpath string, configPtr *Config) error {
37 | var (
38 | tBuf []byte
39 | )
40 | loaders := []multiconfig.Loader{
41 | &multiconfig.TagLoader{},
42 | &multiconfig.EnvironmentLoader{},
43 | }
44 | s := cfg.NewFileScanner()
45 |
46 | s.Read(path.Join(fpath))
47 | tBuf = append(tBuf, s.Data()...)
48 | tBuf = append(tBuf, []byte("\n")...)
49 |
50 | if s.Err() != nil {
51 | return s.Err()
52 | }
53 |
54 | if len(tBuf) != 0 {
55 | loaders = append(loaders, &multiconfig.TOMLLoader{Reader: bytes.NewReader(tBuf)})
56 | }
57 |
58 | m := multiconfig.DefaultLoader{
59 | Loader: multiconfig.MultiLoader(loaders...),
60 | Validator: multiconfig.MultiValidator(&multiconfig.RequiredValidator{}),
61 | }
62 | return m.Load(configPtr)
63 | }
64 |
--------------------------------------------------------------------------------
/cli/upgrade/readme.md:
--------------------------------------------------------------------------------
1 | # v5 升级 v6 手册
2 | 0. 操作之前,记得备注下数据库!
3 |
4 | 1. 需要先将你正在使用的夜莺数据源表结构更新到和 v5.15.0 一致,[release](https://github.com/ccfos/nightingale/releases) 页面有每个版本表结构的更新说明,可以根据你正在使用的版本,按照说明,逐个执行的更新表结构的语句
5 |
6 | 2. 解压 n9e 安装包,导入 upgrade.sql 到 n9e_v5 数据库
7 | ```
8 | mysql -h 127.0.0.1 -u root -p1234 < cli/upgrade/upgrade.sql
9 | ```
10 |
11 | 3. 执行 n9e-cli 完成数据库表结构升级, webapi.conf 为 v5 版本 n9e-webapi 正在使用的配置文件
12 | ```
13 | ./n9e-cli --upgrade --config webapi.conf
14 | ```
15 |
16 | 4. 修改 n9e 配置文件中的数据库为 n9e_v5,启动 n9e 进程
17 | ```
18 | nohup ./n9e &> n9e.log &
19 | ```
20 |
21 | 5. n9e 监听的端口为 17000,需要将之前的 web 端口和数据上报的端口,都调整为 17000
--------------------------------------------------------------------------------
/cmd/cli/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "os"
7 |
8 | "github.com/ccfos/nightingale/v6/cli"
9 | "github.com/ccfos/nightingale/v6/pkg/version"
10 | )
11 |
12 | var (
13 | upgrade = flag.Bool("upgrade", false, "Upgrade the database.")
14 | showVersion = flag.Bool("version", false, "Show version.")
15 | configFile = flag.String("config", "", "Specify webapi.conf of v5.x version")
16 | )
17 |
18 | func main() {
19 | flag.Parse()
20 |
21 | if *showVersion {
22 | fmt.Println(version.Version)
23 | os.Exit(0)
24 | }
25 |
26 | if *upgrade {
27 | if *configFile == "" {
28 | fmt.Println("Please specify the configuration directory.")
29 | os.Exit(1)
30 | }
31 |
32 | err := cli.Upgrade(*configFile)
33 | if err != nil {
34 | fmt.Println(err)
35 | os.Exit(1)
36 | }
37 | fmt.Print("Upgrade successfully.")
38 | os.Exit(0)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/cmd/edge/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "log"
7 | "os"
8 | "os/signal"
9 | "syscall"
10 |
11 | "github.com/ccfos/nightingale/v6/pkg/osx"
12 | "github.com/ccfos/nightingale/v6/pkg/version"
13 |
14 | "github.com/toolkits/pkg/runner"
15 | )
16 |
17 | var (
18 | showVersion = flag.Bool("version", false, "Show version.")
19 | configDir = flag.String("configs", osx.GetEnv("N9E_EDGE_CONFIGS", "etc"), "Specify configuration directory.(env:N9E_EDGE_CONFIGS)")
20 | cryptoKey = flag.String("crypto-key", "", "Specify the secret key for configuration file field encryption.")
21 | )
22 |
23 | func main() {
24 | flag.Parse()
25 |
26 | if *showVersion {
27 | fmt.Println(version.Version)
28 | os.Exit(0)
29 | }
30 |
31 | printEnv()
32 |
33 | cleanFunc, err := Initialize(*configDir, *cryptoKey)
34 | if err != nil {
35 | log.Fatalln("failed to initialize:", err)
36 | }
37 |
38 | code := 1
39 | sc := make(chan os.Signal, 1)
40 | signal.Notify(sc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
41 |
42 | EXIT:
43 | for {
44 | sig := <-sc
45 | fmt.Println("received signal:", sig.String())
46 | switch sig {
47 | case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
48 | code = 0
49 | break EXIT
50 | case syscall.SIGHUP:
51 | // reload configuration?
52 | default:
53 | break EXIT
54 | }
55 | }
56 |
57 | cleanFunc()
58 | fmt.Println("process exited")
59 | os.Exit(code)
60 | }
61 |
62 | func printEnv() {
63 | runner.Init()
64 | fmt.Println("runner.cwd:", runner.Cwd)
65 | fmt.Println("runner.hostname:", runner.Hostname)
66 | fmt.Println("runner.fd_limits:", runner.FdLimits())
67 | fmt.Println("runner.vm_limits:", runner.VMLimits())
68 | }
69 |
--------------------------------------------------------------------------------
/conf/crypto.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ccfos/nightingale/v6/pkg/secu"
7 | )
8 |
9 | func decryptConfig(config *ConfigType, cryptoKey string) error {
10 | decryptDsn, err := secu.DealWithDecrypt(config.DB.DSN, cryptoKey)
11 | if err != nil {
12 | return fmt.Errorf("failed to decrypt the db dsn: %s", err)
13 | }
14 |
15 | config.DB.DSN = decryptDsn
16 |
17 | for k := range config.HTTP.APIForService.BasicAuth {
18 | decryptPwd, err := secu.DealWithDecrypt(config.HTTP.APIForService.BasicAuth[k], cryptoKey)
19 | if err != nil {
20 | return fmt.Errorf("failed to decrypt http basic auth password: %s", err)
21 | }
22 |
23 | config.HTTP.APIForService.BasicAuth[k] = decryptPwd
24 | }
25 |
26 | for k := range config.HTTP.APIForAgent.BasicAuth {
27 | decryptPwd, err := secu.DealWithDecrypt(config.HTTP.APIForAgent.BasicAuth[k], cryptoKey)
28 | if err != nil {
29 | return fmt.Errorf("failed to decrypt http basic auth password: %s", err)
30 | }
31 |
32 | config.HTTP.APIForAgent.BasicAuth[k] = decryptPwd
33 | }
34 |
35 | for i, v := range config.Pushgw.Writers {
36 | decryptWriterPwd, err := secu.DealWithDecrypt(v.BasicAuthPass, cryptoKey)
37 | if err != nil {
38 | return fmt.Errorf("failed to decrypt writer basic auth password: %s", err)
39 | }
40 |
41 | config.Pushgw.Writers[i].BasicAuthPass = decryptWriterPwd
42 | }
43 |
44 | return nil
45 | }
46 |
--------------------------------------------------------------------------------
/cron/clean_notify_record.go:
--------------------------------------------------------------------------------
1 | package cron
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/ccfos/nightingale/v6/models"
7 | "github.com/ccfos/nightingale/v6/pkg/ctx"
8 |
9 | "github.com/robfig/cron/v3"
10 | "github.com/toolkits/pkg/logger"
11 | )
12 |
13 | func cleanNotifyRecord(ctx *ctx.Context, day int) {
14 | lastWeek := time.Now().Unix() - 86400*int64(day)
15 | err := models.DB(ctx).Model(&models.NotificaitonRecord{}).Where("created_at < ?", lastWeek).Delete(&models.NotificaitonRecord{}).Error
16 | if err != nil {
17 | logger.Errorf("Failed to clean notify record: %v", err)
18 | }
19 |
20 | }
21 |
22 | // 每天凌晨1点执行清理任务
23 | func CleanNotifyRecord(ctx *ctx.Context, day int) {
24 | c := cron.New()
25 | if day < 1 {
26 | day = 7
27 | }
28 |
29 | // 使用cron表达式设置每天凌晨1点执行
30 | _, err := c.AddFunc("0 1 * * *", func() {
31 | cleanNotifyRecord(ctx, day)
32 | })
33 |
34 | if err != nil {
35 | logger.Errorf("Failed to add clean notify record cron job: %v", err)
36 | return
37 | }
38 |
39 | // 启动cron任务
40 | c.Start()
41 | }
42 |
--------------------------------------------------------------------------------
/datasource/prom/prom.go:
--------------------------------------------------------------------------------
1 | package prom
2 |
3 | type Prometheus struct {
4 | PrometheusAddr string `json:"prometheus.addr"`
5 | PrometheusBasic struct {
6 | PrometheusUser string `json:"prometheus.user"`
7 | PrometheusPass string `json:"prometheus.password"`
8 | } `json:"prometheus.basic"`
9 | Headers map[string]string `json:"prometheus.headers"`
10 | PrometheusTimeout int64 `json:"prometheus.timeout"`
11 | ClusterName string `json:"prometheus.cluster_name"`
12 | WriteAddr string `json:"prometheus.write_addr"`
13 | TsdbType string `json:"prometheus.tsdb_type"`
14 | InternalAddr string `json:"prometheus.internal_addr"`
15 | }
16 |
--------------------------------------------------------------------------------
/doc/active-contributors.md:
--------------------------------------------------------------------------------
1 | ## Active Contributors
2 |
3 | - [xiaoziv](https://github.com/xiaoziv)
4 | - [tanxiao1990](https://github.com/tanxiao1990)
5 | - [bbaobelief](https://github.com/bbaobelief)
6 | - [freedomkk-qfeng](https://github.com/freedomkk-qfeng)
7 | - [lsy1990](https://github.com/lsy1990)
8 |
--------------------------------------------------------------------------------
/doc/committers.md:
--------------------------------------------------------------------------------
1 | ## Committers
2 |
3 | - [YeningQin](https://github.com/710leo)
4 | - [FeiKong](https://github.com/kongfei605)
5 | - [XiaqingDai](https://github.com/jsers)
6 |
--------------------------------------------------------------------------------
/doc/contributors.md:
--------------------------------------------------------------------------------
1 | ## Contributors
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/doc/end-users.md:
--------------------------------------------------------------------------------
1 | ## End Users
2 |
3 | - [中移动](https://github.com/ccfos/nightingale/issues/897#issuecomment-1086573166)
4 | - [inke](https://github.com/ccfos/nightingale/issues/897#issuecomment-1099840636)
5 | - [方正证券](https://github.com/ccfos/nightingale/issues/897#issuecomment-1110492461)
6 |
--------------------------------------------------------------------------------
/doc/img/Nightingale_L_V.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/Nightingale_L_V.png
--------------------------------------------------------------------------------
/doc/img/alert-events.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/alert-events.png
--------------------------------------------------------------------------------
/doc/img/arch-product.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/arch-product.png
--------------------------------------------------------------------------------
/doc/img/arch-system.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/arch-system.png
--------------------------------------------------------------------------------
/doc/img/arch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/arch.png
--------------------------------------------------------------------------------
/doc/img/ccf-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/ccf-logo.png
--------------------------------------------------------------------------------
/doc/img/ccf-n9e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/ccf-n9e.png
--------------------------------------------------------------------------------
/doc/img/dingtalk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/dingtalk.png
--------------------------------------------------------------------------------
/doc/img/install-vm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/install-vm.png
--------------------------------------------------------------------------------
/doc/img/intro.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/intro.gif
--------------------------------------------------------------------------------
/doc/img/mysql-alerts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/mysql-alerts.png
--------------------------------------------------------------------------------
/doc/img/n9e-arch-latest.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/n9e-arch-latest.png
--------------------------------------------------------------------------------
/doc/img/n9e-node-dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/n9e-node-dashboard.png
--------------------------------------------------------------------------------
/doc/img/n9e-screenshot-gif-v6.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/n9e-screenshot-gif-v6.gif
--------------------------------------------------------------------------------
/doc/img/n9e-vx-new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/n9e-vx-new.png
--------------------------------------------------------------------------------
/doc/img/nightingale_logo_h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/nightingale_logo_h.png
--------------------------------------------------------------------------------
/doc/img/nightingale_logo_v.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/nightingale_logo_v.png
--------------------------------------------------------------------------------
/doc/img/readme/20240221152601.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/20240221152601.png
--------------------------------------------------------------------------------
/doc/img/readme/20240222102119.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/20240222102119.png
--------------------------------------------------------------------------------
/doc/img/readme/20240513103305.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/20240513103305.png
--------------------------------------------------------------------------------
/doc/img/readme/20240513103530.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/20240513103530.png
--------------------------------------------------------------------------------
/doc/img/readme/20240513103628.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/20240513103628.png
--------------------------------------------------------------------------------
/doc/img/readme/20240513103825.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/20240513103825.png
--------------------------------------------------------------------------------
/doc/img/readme/2025-05-23_18-43-37.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/2025-05-23_18-43-37.png
--------------------------------------------------------------------------------
/doc/img/readme/2025-05-23_18-46-06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/2025-05-23_18-46-06.png
--------------------------------------------------------------------------------
/doc/img/readme/2025-05-23_18-49-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/2025-05-23_18-49-02.png
--------------------------------------------------------------------------------
/doc/img/readme/2025-05-30_08-49-28.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/2025-05-30_08-49-28.png
--------------------------------------------------------------------------------
/doc/img/readme/logos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/logos.png
--------------------------------------------------------------------------------
/doc/img/readme/n9e-switch-i18n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/readme/n9e-switch-i18n.png
--------------------------------------------------------------------------------
/doc/img/redis-dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/redis-dash.png
--------------------------------------------------------------------------------
/doc/img/vm-cluster-arch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/vm-cluster-arch.png
--------------------------------------------------------------------------------
/doc/img/wecom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/wecom.png
--------------------------------------------------------------------------------
/doc/img/wx.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/doc/img/wx.jpg
--------------------------------------------------------------------------------
/doc/pmc.md:
--------------------------------------------------------------------------------
1 | ### PMC Chair
2 | - [laiwei](https://github.com/laiwei)
3 |
4 | ### PMC Co-Chair
5 | - [UlricQin](https://github.com/UlricQin)
6 |
7 | ### PMC Member
8 |
--------------------------------------------------------------------------------
/docker/.dockerignore:
--------------------------------------------------------------------------------
1 | compose-host-network
2 | compose-postgres
3 | compose-bridge
4 | initsql
5 | build.sh
6 |
--------------------------------------------------------------------------------
/docker/Dockerfile.goreleaser:
--------------------------------------------------------------------------------
1 | FROM --platform=$TARGETPLATFORM python:3-slim
2 |
3 |
4 | WORKDIR /app
5 | ADD n9e /app/
6 | ADD etc /app/etc/
7 | ADD integrations /app/integrations/
8 | RUN pip install requests
9 |
10 | EXPOSE 17000
11 |
12 | CMD ["/app/n9e", "-h"]
13 |
--------------------------------------------------------------------------------
/docker/Dockerfile.goreleaser.arm64:
--------------------------------------------------------------------------------
1 | FROM --platform=$TARGETPLATFORM python:3-slim
2 |
3 |
4 | WORKDIR /app
5 | ADD n9e /app/
6 | ADD etc /app/etc/
7 | ADD integrations /app/integrations/
8 |
9 | EXPOSE 17000
10 |
11 | CMD ["/app/n9e", "-h"]
12 |
--------------------------------------------------------------------------------
/docker/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | if [ $# -ne 1 ]; then
3 | echo "$0 "
4 | exit 0
5 | fi
6 |
7 | tag=$1
8 |
9 | echo "tag: ${tag}"
10 |
11 | rm -rf n9e pub
12 | cp ../n9e .
13 |
14 | docker build -t nightingale:${tag} .
15 |
16 | docker tag nightingale:${tag} ulric2019/nightingale:${tag}
17 | docker push ulric2019/nightingale:${tag}
18 |
19 | rm -rf n9e pub
20 |
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.cpu/cpu.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect per cpu
5 | # collect_per_cpu = false
6 |
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.disk/disk.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # By default stats will be gathered for all mount points.
5 | # # Set mount_points will restrict the stats to only the specified mount points.
6 | mount_points = ["/"]
7 |
8 | # Ignore mount points by filesystem type.
9 | ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs", "nsfs"]
10 |
11 |
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.diskio/diskio.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # By default, categraf will gather stats for all devices including disk partitions.
5 | # # Setting devices will restrict the stats to the specified devices.
6 | # devices = ["sda", "sdb", "vd*"]
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.kernel/kernel.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.mem/mem.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect platform specified metrics
5 | collect_platform_fields = true
6 |
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.mysql/mysql.toml:
--------------------------------------------------------------------------------
1 | [[instances]]
2 | address = "mysql:3306"
3 | username = "root"
4 | password = "1234"
5 |
6 | # # set tls=custom to enable tls
7 | # parameters = "tls=false"
8 |
9 | # extra_status_metrics = true
10 | # extra_innodb_metrics = false
11 | # gather_processlist_processes_by_state = false
12 | # gather_processlist_processes_by_user = false
13 | # gather_schema_size = true
14 | # gather_table_size = false
15 | # gather_system_table_size = false
16 | # gather_slave_status = true
17 |
18 | # # timeout
19 | # timeout_seconds = 3
20 |
21 | # # interval = global.interval * interval_times
22 | # interval_times = 1
23 |
24 | # important! use global unique string to specify instance
25 | labels = { instance="docker-compose-mysql" }
26 |
27 | ## Optional TLS Config
28 | # use_tls = false
29 | # tls_min_version = "1.2"
30 | # tls_ca = "/etc/categraf/ca.pem"
31 | # tls_cert = "/etc/categraf/cert.pem"
32 | # tls_key = "/etc/categraf/key.pem"
33 | ## Use TLS but skip chain & host verification
34 | # insecure_skip_verify = true
35 |
36 | #[[instances.queries]]
37 | # mesurement = "lock_wait"
38 | # metric_fields = [ "total" ]
39 | # timeout = "3s"
40 | # request = '''
41 | #SELECT count(*) as total FROM information_schema.innodb_trx WHERE trx_state='LOCK WAIT'
42 | #'''
43 |
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.net/net.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect protocol stats on Linux
5 | # collect_protocol_stats = false
6 |
7 | # # setting interfaces will tell categraf to gather these explicit interfaces
8 | # interfaces = ["eth0"]
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.netstat/netstat.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.processes/processes.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # force use ps command to gather
5 | # force_ps = false
6 |
7 | # # force use /proc to gather
8 | # force_proc = false
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.prometheus/prometheus.toml:
--------------------------------------------------------------------------------
1 | [[instances]]
2 | urls = [
3 | "http://nightingale:17000/metrics"
4 | ]
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.redis/redis.toml:
--------------------------------------------------------------------------------
1 | [[instances]]
2 | address = "redis:6379"
3 | username = ""
4 | password = ""
5 | # pool_size = 2
6 |
7 | ## 是否开启slowlog 收集
8 | # gather_slowlog = true
9 | ## 最多收集少条slowlog
10 | # slowlog_max_len = 100
11 | ## 收集距离现在多少秒以内的slowlog
12 | ## 注意插件的采集周期,该参数不要小于采集周期,否则会有slowlog查不到
13 | # slowlog_time_window=30
14 |
15 | # 指标
16 | # redis_slow_log{ident=dev-01 client_addr=127.0.0.1:56364 client_name= cmd="info ALL" log_id=983} 74 (单位微秒)
17 |
18 | # # Optional. Specify redis commands to retrieve values
19 | # commands = [
20 | # {command = ["get", "sample-key1"], metric = "custom_metric_name1"},
21 | # {command = ["get", "sample-key2"], metric = "custom_metric_name2"}
22 | # ]
23 |
24 | # # interval = global.interval * interval_times
25 | # interval_times = 1
26 |
27 | # important! use global unique string to specify instance
28 | labels = { instance="docker-compose-redis" }
29 |
30 | ## Optional TLS Config
31 | # use_tls = false
32 | # tls_min_version = "1.2"
33 | # tls_ca = "/etc/categraf/ca.pem"
34 | # tls_cert = "/etc/categraf/cert.pem"
35 | # tls_key = "/etc/categraf/key.pem"
36 | ## Use TLS but skip chain & host verification
37 | # insecure_skip_verify = true
38 |
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-categraf/input.system/system.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect metric: system_n_users
5 | # collect_user_number = false
6 |
--------------------------------------------------------------------------------
/docker/compose-bridge/etc-mysql/my.cnf:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | pid-file = /var/run/mysqld/mysqld.pid
3 | socket = /var/run/mysqld/mysqld.sock
4 | datadir = /var/lib/mysql
5 | bind-address = 0.0.0.0
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-categraf/input.cpu/cpu.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect per cpu
5 | # collect_per_cpu = false
6 |
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-categraf/input.disk/disk.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # By default stats will be gathered for all mount points.
5 | # # Set mount_points will restrict the stats to only the specified mount points.
6 | # mount_points = ["/"]
7 |
8 | # Ignore mount points by filesystem type.
9 | ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]
10 |
11 | ignore_mount_points = ["/boot"]
12 |
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-categraf/input.diskio/diskio.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # By default, categraf will gather stats for all devices including disk partitions.
5 | # # Setting devices will restrict the stats to the specified devices.
6 | # devices = ["sda", "sdb", "vd*"]
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-categraf/input.kernel/kernel.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-categraf/input.mem/mem.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect platform specified metrics
5 | collect_platform_fields = true
6 |
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-categraf/input.net/net.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect protocol stats on Linux
5 | # collect_protocol_stats = false
6 |
7 | # # setting interfaces will tell categraf to gather these explicit interfaces
8 | # interfaces = ["eth0"]
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-categraf/input.netstat/netstat.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-categraf/input.processes/processes.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # force use ps command to gather
5 | # force_ps = false
6 |
7 | # # force use /proc to gather
8 | # force_proc = false
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-categraf/input.system/system.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect metric: system_n_users
5 | # collect_user_number = false
6 |
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-logstash/logstash.yaml:
--------------------------------------------------------------------------------
1 | input {
2 | kafka {
3 | bootstrap_servers => "127.0.0.1:9092"
4 | topics => ["flashcatcloud"]
5 | codec => json
6 | type => n9e
7 | }
8 | }
9 |
10 | filter {
11 | grok {
12 | match => {"message" => "%{LOGLEVEL:status}"}
13 | overwrite => ["status"]
14 | }
15 | }
16 |
17 | output {
18 | elasticsearch {
19 | hosts => ["127.0.0.1:9200"]
20 | index => "n9e-%{+YYYY.MM.DD}"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-mysql/my.cnf:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | pid-file = /var/run/mysqld/mysqld.pid
3 | socket = /var/run/mysqld/mysqld.sock
4 | datadir = /var/lib/mysql
5 | bind-address = 127.0.0.1
--------------------------------------------------------------------------------
/docker/compose-host-network-metric-log/etc-prometheus/prometheus.yml:
--------------------------------------------------------------------------------
1 | # my global config
2 | global:
3 | scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
4 | evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
5 | # scrape_timeout is set to the global default (10s).
6 |
7 | # Alertmanager configuration
8 | alerting:
9 | alertmanagers:
10 | - static_configs:
11 | - targets:
12 | # - alertmanager:9093
13 |
14 | # Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
15 | rule_files:
16 | # - "first_rules.yml"
17 | # - "second_rules.yml"
18 |
19 | scrape_configs:
20 | # The job name is added as a label `job=` to any timeseries scraped from this config.
21 | - job_name: 'prometheus'
22 | static_configs:
23 | - targets: ['localhost:9090']
24 |
25 | - job_name: 'nightingale'
26 | static_configs:
27 | - targets: ['localhost:17000']
28 |
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-categraf/input.cpu/cpu.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect per cpu
5 | # collect_per_cpu = false
6 |
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-categraf/input.disk/disk.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # By default stats will be gathered for all mount points.
5 | # # Set mount_points will restrict the stats to only the specified mount points.
6 | # mount_points = ["/"]
7 |
8 | # Ignore mount points by filesystem type.
9 | ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]
10 |
11 | ignore_mount_points = ["/boot"]
12 |
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-categraf/input.diskio/diskio.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # By default, categraf will gather stats for all devices including disk partitions.
5 | # # Setting devices will restrict the stats to the specified devices.
6 | # devices = ["sda", "sdb", "vd*"]
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-categraf/input.kernel/kernel.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-categraf/input.mem/mem.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect platform specified metrics
5 | collect_platform_fields = true
6 |
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-categraf/input.net/net.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect protocol stats on Linux
5 | # collect_protocol_stats = false
6 |
7 | # # setting interfaces will tell categraf to gather these explicit interfaces
8 | # interfaces = ["eth0"]
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-categraf/input.netstat/netstat.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-categraf/input.processes/processes.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # force use ps command to gather
5 | # force_ps = false
6 |
7 | # # force use /proc to gather
8 | # force_proc = false
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-categraf/input.system/system.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect metric: system_n_users
5 | # collect_user_number = false
6 |
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-mysql/my.cnf:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | pid-file = /var/run/mysqld/mysqld.pid
3 | socket = /var/run/mysqld/mysqld.sock
4 | datadir = /var/lib/mysql
5 | bind-address = 127.0.0.1
--------------------------------------------------------------------------------
/docker/compose-host-network/etc-prometheus/prometheus.yml:
--------------------------------------------------------------------------------
1 | # my global config
2 | global:
3 | scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
4 | evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
5 | # scrape_timeout is set to the global default (10s).
6 |
7 | # Alertmanager configuration
8 | alerting:
9 | alertmanagers:
10 | - static_configs:
11 | - targets:
12 | # - alertmanager:9093
13 |
14 | # Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
15 | rule_files:
16 | # - "first_rules.yml"
17 | # - "second_rules.yml"
18 |
19 | scrape_configs:
20 | # The job name is added as a label `job=` to any timeseries scraped from this config.
21 | - job_name: 'prometheus'
22 | static_configs:
23 | - targets: ['localhost:9090']
24 |
25 | - job_name: 'nightingale'
26 | static_configs:
27 | - targets: ['localhost:17000']
28 |
--------------------------------------------------------------------------------
/docker/compose-postgres/categraf/conf/input.cpu/cpu.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect per cpu
5 | # collect_per_cpu = false
6 |
--------------------------------------------------------------------------------
/docker/compose-postgres/categraf/conf/input.disk/disk.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # By default stats will be gathered for all mount points.
5 | # # Set mount_points will restrict the stats to only the specified mount points.
6 | # mount_points = ["/"]
7 |
8 | # Ignore mount points by filesystem type.
9 | ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]
10 |
11 | ignore_mount_points = ["/boot"]
12 |
--------------------------------------------------------------------------------
/docker/compose-postgres/categraf/conf/input.diskio/diskio.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # By default, categraf will gather stats for all devices including disk partitions.
5 | # # Setting devices will restrict the stats to the specified devices.
6 | # devices = ["sda", "sdb", "vd*"]
--------------------------------------------------------------------------------
/docker/compose-postgres/categraf/conf/input.kernel/kernel.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
--------------------------------------------------------------------------------
/docker/compose-postgres/categraf/conf/input.mem/mem.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect platform specified metrics
5 | collect_platform_fields = true
6 |
--------------------------------------------------------------------------------
/docker/compose-postgres/categraf/conf/input.net/net.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect protocol stats on Linux
5 | # collect_protocol_stats = false
6 |
7 | # # setting interfaces will tell categraf to gather these explicit interfaces
8 | # interfaces = ["eth0"]
--------------------------------------------------------------------------------
/docker/compose-postgres/categraf/conf/input.netstat/netstat.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
--------------------------------------------------------------------------------
/docker/compose-postgres/categraf/conf/input.processes/processes.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # force use ps command to gather
5 | # force_ps = false
6 |
7 | # # force use /proc to gather
8 | # force_proc = false
--------------------------------------------------------------------------------
/docker/compose-postgres/categraf/conf/input.system/system.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # whether collect metric: system_n_users
5 | # collect_user_number = false
6 |
--------------------------------------------------------------------------------
/docker/compose-postgres/categraf/conf/prometheus.toml:
--------------------------------------------------------------------------------
1 | [prometheus]
2 | enable=true
3 | scrape_config_file="/etc/prometheus/prometheus.yml"
4 | ## log level, debug warn info error
5 | log_level="info"
6 | ## wal file storage path ,default ./data-agent
7 | # wal_storage_path="/path/to/storage"
8 | ## wal reserve time duration, default value is 2 hour
9 | # wal_min_duration=2
10 |
11 |
--------------------------------------------------------------------------------
/docker/compose-postgres/prometc_vm/prometheus.yml:
--------------------------------------------------------------------------------
1 | # my global config
2 | global:
3 | scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
4 | evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
5 | # scrape_timeout is set to the global default (10s).
6 |
7 | # A scrape configuration containing exactly one endpoint to scrape:
8 | # Here it's Prometheus itself.
9 | scrape_configs:
10 | # The job name is added as a label `job=` to any timeseries scraped from this config.
11 | - job_name: 'victoriametrics'
12 | # metrics_path defaults to '/metrics'
13 | # scheme defaults to 'http'.
14 | static_configs:
15 | - targets: ['victoriametrics:8428']
16 |
17 | - job_name: 'n9e'
18 | # static_configs:
19 | # - targets: ['n9e:17000']
20 | file_sd_configs:
21 | - files:
22 | - targets.json
23 |
24 | remote_write:
25 | - url: 'http://n9e:17000/prometheus/v1/write'
26 |
--------------------------------------------------------------------------------
/docker/compose-postgres/prometc_vm/targets.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "targets": [
4 | "n9e:17000"
5 | ]
6 | }
7 | ]
8 |
--------------------------------------------------------------------------------
/docker/initsql/c-init.sql:
--------------------------------------------------------------------------------
1 | CREATE USER IF NOT EXISTS 'root'@'127.0.0.1' IDENTIFIED BY '1234';
2 | GRANT ALL PRIVILEGES ON *.* TO 'root'@'127.0.0.1' WITH GRANT OPTION;
3 |
4 | CREATE USER IF NOT EXISTS 'root'@'localhost' IDENTIFIED BY '1234';
5 | GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION;
6 |
7 | CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '1234';
8 | GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
9 |
10 | FLUSH PRIVILEGES;
11 |
--------------------------------------------------------------------------------
/dscache/cache.go:
--------------------------------------------------------------------------------
1 | package dscache
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/ccfos/nightingale/v6/datasource"
7 | "github.com/toolkits/pkg/logger"
8 | )
9 |
10 | type Cache struct {
11 | datas map[string]map[int64]datasource.Datasource
12 | mutex *sync.RWMutex
13 | }
14 |
15 | var DsCache = Cache{
16 | datas: make(map[string]map[int64]datasource.Datasource),
17 | mutex: new(sync.RWMutex),
18 | }
19 |
20 | func (cs *Cache) Put(cate string, dsId int64, ds datasource.Datasource) {
21 | cs.mutex.Lock()
22 | if _, found := cs.datas[cate]; !found {
23 | cs.datas[cate] = make(map[int64]datasource.Datasource)
24 | }
25 |
26 | if _, found := cs.datas[cate][dsId]; found {
27 | if cs.datas[cate][dsId].Equal(ds) {
28 | cs.mutex.Unlock()
29 | return
30 | }
31 | }
32 | cs.mutex.Unlock()
33 |
34 | // InitClient() 在用户配置错误或远端不可用时, 会非常耗时, mutex被长期持有, 导致Get()会超时
35 | err := ds.InitClient()
36 | if err != nil {
37 | logger.Errorf("init plugin:%s %d %+v client fail: %v", cate, dsId, ds, err)
38 | return
39 | }
40 |
41 | logger.Debugf("init plugin:%s %d %+v client success", cate, dsId, ds)
42 | cs.mutex.Lock()
43 | cs.datas[cate][dsId] = ds
44 | cs.mutex.Unlock()
45 | }
46 |
47 | func (cs *Cache) Get(cate string, dsId int64) (datasource.Datasource, bool) {
48 | cs.mutex.RLock()
49 | defer cs.mutex.RUnlock()
50 | if _, found := cs.datas[cate]; !found {
51 | return nil, false
52 | }
53 |
54 | if _, found := cs.datas[cate][dsId]; !found {
55 | return nil, false
56 | }
57 |
58 | return cs.datas[cate][dsId], true
59 | }
60 |
--------------------------------------------------------------------------------
/dskit/clickhouse/clickhouse_test.go:
--------------------------------------------------------------------------------
1 | package clickhouse
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "fmt"
7 | "testing"
8 | "time"
9 |
10 | "github.com/ccfos/nightingale/v6/dskit/types"
11 | )
12 |
13 | func Test_Timeseries(t *testing.T) {
14 | ck := &Clickhouse{
15 | Nodes: []string{"127.0.0.1:8123"},
16 | User: "default",
17 | Password: "123456",
18 | }
19 |
20 | err := ck.InitCli()
21 | if err != nil {
22 | t.Fatal(err)
23 | }
24 |
25 | data, err := ck.QueryTimeseries(context.TODO(), &QueryParam{
26 | Sql: `select * from default.student limit 20`,
27 | From: time.Now().Unix() - 300,
28 | To: time.Now().Unix(),
29 | TimeField: "created_at",
30 | TimeFormat: "datetime",
31 | Keys: types.Keys{
32 | LabelKey: "age",
33 | },
34 | })
35 | if err != nil {
36 | t.Fatal(err)
37 | }
38 | bs, err := json.Marshal(data)
39 | if err != nil {
40 | t.Fatal(err)
41 | }
42 | fmt.Println(string(bs))
43 | }
44 |
--------------------------------------------------------------------------------
/dskit/clickhouse/timeseries.go:
--------------------------------------------------------------------------------
1 | package clickhouse
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "github.com/ccfos/nightingale/v6/dskit/sqlbase"
8 | "github.com/ccfos/nightingale/v6/dskit/types"
9 | )
10 |
11 | const (
12 | TimeFieldFormatEpochMilli = "epoch_millis"
13 | TimeFieldFormatEpochSecond = "epoch_second"
14 | )
15 |
16 | // 时序数据相关的API
17 | type QueryParam struct {
18 | Limit int `json:"limit" mapstructure:"limit"`
19 | Sql string `json:"sql" mapstructure:"sql"`
20 | Ref string `json:"ref" mapstructure:"ref"`
21 | From int64 `json:"from" mapstructure:"from"`
22 | To int64 `json:"to" mapstructure:"to"`
23 | TimeField string `json:"time_field" mapstructure:"time_field"`
24 | TimeFormat string `json:"time_format" mapstructure:"time_format"`
25 | Keys types.Keys `json:"keys" mapstructure:"keys"`
26 | Database string `json:"database" mapstructure:"database"`
27 | Table string `json:"table" mapstructure:"table"`
28 | }
29 |
30 | var (
31 | ckBannedOp = map[string]struct{}{
32 | "CREATE": {},
33 | "INSERT": {},
34 | "ALTER": {},
35 | "REVOKE": {},
36 | "DROP": {},
37 | "RENAME": {},
38 | "ATTACH": {},
39 | "DETACH": {},
40 | "OPTIMIZE": {},
41 | "TRUNCATE": {},
42 | "SET": {},
43 | }
44 | )
45 |
46 | func (c *Clickhouse) QueryTimeseries(ctx context.Context, query *QueryParam) ([]types.MetricValues, error) {
47 | if query.Keys.ValueKey == "" {
48 | return nil, fmt.Errorf("valueKey is required")
49 | }
50 |
51 | rows, err := c.Query(ctx, query)
52 | if err != nil {
53 | return nil, err
54 | }
55 |
56 | // 构造成时续数据
57 | return sqlbase.FormatMetricValues(query.Keys, rows, true), nil
58 | }
59 |
--------------------------------------------------------------------------------
/dskit/types/timeseries.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "strconv"
7 |
8 | "github.com/prometheus/common/model"
9 | )
10 |
11 | // 时序数据
12 | type MetricValues struct {
13 | Metric model.Metric `json:"metric"`
14 | Values [][]float64 `json:"values"`
15 | }
16 |
17 | type HistogramValues struct {
18 | Total int64 `json:"total"`
19 | Values [][]float64 `json:"values"`
20 | }
21 |
22 | // 瞬时值
23 | type AggregateValues struct {
24 | Labels map[string]string `json:"labels"`
25 | Values map[string]float64 `json:"values"`
26 | }
27 |
28 | // string
29 | func (m *MetricValues) String() string {
30 | var buf bytes.Buffer
31 | buf.WriteString(fmt.Sprintf("Metric: %+v ", m.Metric))
32 | buf.WriteString("Values: ")
33 | for _, v := range m.Values {
34 | buf.WriteString(" [")
35 | for i, ts := range v {
36 | if i > 0 {
37 | buf.WriteString(", ")
38 | }
39 | buf.WriteString(strconv.FormatFloat(ts, 'f', -1, 64))
40 | }
41 | buf.WriteString("] ")
42 | }
43 | return buf.String()
44 | }
45 |
46 | type Keys struct {
47 | ValueKey string `json:"valueKey" mapstructure:"valueKey"` // 多个用空格分隔
48 | LabelKey string `json:"labelKey" mapstructure:"labelKey"` // 多个用空格分隔
49 | TimeKey string `json:"timeKey" mapstructure:"timeKey"`
50 | TimeFormat string `json:"timeFormat" mapstructure:"timeFormat"` // not used anymore
51 | }
52 |
--------------------------------------------------------------------------------
/dskit/types/types.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | LogExtractValueTypeLong = "long"
5 | LogExtractValueTypeFloat = "float"
6 | LogExtractValueTypeText = "text"
7 | LogExtractValueTypeDate = "date"
8 | LogExtractValueTypeBool = "bool"
9 | LogExtractValueTypeObject = "object"
10 | LogExtractValueTypeArray = "array"
11 | LogExtractValueTypeJSON = "json"
12 | )
13 |
14 | type ColumnProperty struct {
15 | Field string `json:"field"`
16 | Type string `json:"type"`
17 | Type2 string `json:"type2,omitempty"` // field_property.Type
18 | Indexable bool `json:"indexable"` // 是否可以索引
19 | }
20 |
--------------------------------------------------------------------------------
/dumper/dumper.go:
--------------------------------------------------------------------------------
1 | package dumper
2 |
3 | import "github.com/gin-gonic/gin"
4 |
5 | // package level functions
6 | func ConfigRouter(r *gin.Engine) {
7 | syncDumper.ConfigRouter(r)
8 | }
9 |
--------------------------------------------------------------------------------
/fe.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cp -f ./docker/initsql/a-n9e.sql n9e.sql
4 |
5 | if [ ! -d "./pub" ]; then
6 | TAG=$(curl -sX GET https://api.github.com/repos/n9e/fe/releases/latest | awk '/tag_name/{print $4;exit}' FS='[""]')
7 |
8 | if ! curl -o n9e-fe-${TAG}.tar.gz -L https://github.com/n9e/fe/releases/download/${TAG}/n9e-fe-${TAG}.tar.gz; then
9 | echo "failed to download n9e-fe-${TAG}.tar.gz!"
10 | exit 1
11 | fi
12 |
13 | if ! tar zxf n9e-fe-${TAG}.tar.gz; then
14 | echo "failed to untar n9e-fe-${TAG}.tar.gz!"
15 | exit 2
16 | fi
17 | fi
18 |
19 | GOPATH=$(go env GOPATH)
20 | GOPATH=${GOPATH:-/home/runner/go}
21 |
22 | # Embed files into a go binary
23 | # go install github.com/rakyll/statik
24 | if ! $GOPATH/bin/statik -src=./pub -dest=./front; then
25 | echo "failed to embed files into a go binary!"
26 | exit 4
27 | fi
28 |
--------------------------------------------------------------------------------
/integrations/AMD_ROCm_SMI/collect/amd_rocm_smi/rocm.toml:
--------------------------------------------------------------------------------
1 | # Query statistics from AMD Graphics cards using rocm-smi binary
2 | # bin_path = "/opt/rocm/bin/rocm-smi"
3 |
4 | ## Optional: timeout for GPU polling
5 | # timeout = "5s"
--------------------------------------------------------------------------------
/integrations/AMD_ROCm_SMI/icon/rocm_smi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/AMD_ROCm_SMI/icon/rocm_smi.png
--------------------------------------------------------------------------------
/integrations/AliYun/collect/aliyun/cloud.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 60
3 | [[instances]]
4 | # # endpoint region 参考 https://help.aliyun.com/document_detail/28616.html#section-72p-xhs-6qt
5 | # region="cn-beijing"
6 | # endpoint="metrics.cn-hangzhou.aliyuncs.com"
7 | # access_key_id="your-access-key-id"
8 | # access_key_secret="your-access-key-secret"
9 | # interval_times=4
10 | # delay="10m"
11 | # period="60s"
12 | # # namespace 参考 https://help.aliyun.com/document_detail/163515.htm?spm=a2c4g.11186623.0.0.44d65c58mhgNw3
13 | # namespaces=["acs_ecs_dashboard"]
14 | # [[instances.metric_filters]]
15 | # # metric name 参考 https://help.aliyun.com/document_detail/163515.htm?spm=a2c4g.11186623.0.0.401d15c73Z0dZh
16 | # # 参考页面中的Metric Id 填入下面的metricName ,页面中包含中文的Metric Name对应接口中的Description
17 | # metric_names=["cpu_cores","vm.TcpCount"]
18 | # namespace=""
19 | # ratelimit=25
20 | # catch_ttl="1h"
21 | # timeout="5s"
22 |
--------------------------------------------------------------------------------
/integrations/AliYun/icon/aliyun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/AliYun/icon/aliyun.png
--------------------------------------------------------------------------------
/integrations/AliYun/markdown/ecs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/AliYun/markdown/ecs.png
--------------------------------------------------------------------------------
/integrations/AliYun/markdown/rds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/AliYun/markdown/rds.png
--------------------------------------------------------------------------------
/integrations/AliYun/markdown/redis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/AliYun/markdown/redis.png
--------------------------------------------------------------------------------
/integrations/AliYun/markdown/slb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/AliYun/markdown/slb.png
--------------------------------------------------------------------------------
/integrations/AliYun/markdown/waf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/AliYun/markdown/waf.png
--------------------------------------------------------------------------------
/integrations/AppDynamics/collect/appdynamics/app.toml:
--------------------------------------------------------------------------------
1 | #interval=15s
2 |
3 | [[instances]]
4 | #url_base = "http://{{.ip}}:{{.port}}/a.json?metric-path={{.metric_path}}&time-range-type=BETWEEN_TIMES&start-time={{.start_time}}&end-time={{.end_time}}&output=JSON"
5 | #url_vars = [
6 | # { ip="127.0.0.1", port="8090", application="cms", metric_path="Application Infrastructure Performance|AdminServer|Individual Nodes|xxxxx|Agent|App|Availability", start_time="$START_TIME", end_time="$END_TIME"},
7 | #]
8 |
9 | # # 指定url_vars中哪些key 作为最终的label附加
10 | # url_var_label_keys= []
11 |
12 | # #从url中提取变量
13 | # url_label_key="instance"
14 | # url_label_value="{{.Host}}"
15 | # #自定义 http header
16 | #headers = { Authorization="", X-Forwarded-For="", Host=""}
17 | # #每次请求的超时时间
18 | #timeout="5s"
19 |
20 | # # precision of start-time and end-time
21 | #precision="ms"
22 |
23 | ## basic auth
24 | #username=""
25 | #password=""
26 |
27 | # # endtime = now - delay
28 | #delay = "1m"
29 | # # starttime = now - delay - period = endtime - period
30 | #period = "1m"
31 |
32 | # # 想要添加的额外label
33 | #labels = {application="cms"}
34 | # # 从返回中过滤哪些指标
35 | filters = ["current", "max", "min", "value","sum", "count"]
36 |
37 | # # 限制并发请求量, 最多同时有多少个请求
38 | # # 默认范围(0,100)
39 | #request_inflight= 10
40 | ## 强制开启100以上的并发请求 (不推荐)
41 | # force_request_inflight = 1000
42 |
43 | # # 是否开启 tls
44 | # use_tls = true
45 | # # tls 最小版本
46 | ## tls_min_version = "1.2"
47 | # # tls ca证书路径
48 | ## tls_ca = "/etc/categraf/ca.pem"
49 | # # tls cert 路径
50 | ## tls_cert = "/etc/categraf/cert.pem"
51 | # # tls key 路径
52 | ## tls_key = "/etc/categraf/key.pem"
53 | # # 是否跳过证书验证
54 | ## insecure_skip_verify = true
55 |
--------------------------------------------------------------------------------
/integrations/AppDynamics/icon/appdynamics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/AppDynamics/icon/appdynamics.png
--------------------------------------------------------------------------------
/integrations/AutoMQ/collect/prometheus/采集OTEL-COLLECTOR的样例.toml:
--------------------------------------------------------------------------------
1 | interval = 15
2 |
3 | [[instances]]
4 | urls = [
5 | "http://:/metrics"
6 | ]
7 |
8 | url_label_key = "otel_collector"
9 | url_label_value = "{{.Host}}"
--------------------------------------------------------------------------------
/integrations/AutoMQ/icon/automq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/AutoMQ/icon/automq.png
--------------------------------------------------------------------------------
/integrations/AutoMQ/markdown/overview.md:
--------------------------------------------------------------------------------
1 | ## 前言
2 |
3 | AuthMQ 官方文档提供了指标吐出方式以及和监控系统的整合方式,具体可以参考[AutoMQ](https://docs.automq.com/zh/docs/automq-opensource/LkwkwdQlwizjqckhj0dcc2IdnDh)。
4 |
5 | ## 推荐方式
6 |
7 | 建议采用 AutoMQ 文档中的方案二:使用 Prometheus OTLP Receiver 的方式,把所有的指标都收集到 OTel Collector 中,然后使用 Prometheus 或者 Categraf 直接去拉取数据即可。假如使用 Categraf,就是使用 prometheus 插件去拉取数据,比如我们为 prometheus 插件提供一个单独的 automq.toml 的配置文件:`conf/input.prometheus/automq.toml` ,内容如下:
8 |
9 | ```toml
10 | [[instances]]
11 | urls = [
12 | "http://:/metrics"
13 | ]
14 |
15 | url_label_key = "otel_collector"
16 | url_label_value = "{{.Host}}"
17 | ```
18 |
19 | 注意,url_label_key 一般都是指定为 instance,但是这里故意指定为其他字符串,是因为 AutoMQ 原始的指标中包含了 instance 标签,为了避免冲突,所以指定为其他字符串。
20 |
21 |
--------------------------------------------------------------------------------
/integrations/Bind/collect/bind/bind.toml:
--------------------------------------------------------------------------------
1 | [[instances]]
2 | urls = [
3 | # "http://localhost:8053/xml/v3",
4 | ]
5 | gather_memory_contexts = true
6 | gather_views = true
7 | timeout = "5s"
8 | # labels={app="bind"}
--------------------------------------------------------------------------------
/integrations/Bind/icon/bind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Bind/icon/bind.png
--------------------------------------------------------------------------------
/integrations/Bind/markdown/README.md:
--------------------------------------------------------------------------------
1 | forked from [telegraf/snmp](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/bind)
2 |
3 | 配置示例
4 | ```
5 | [[instances]]
6 | urls = [
7 | #"http://localhost:8053/xml/v3",
8 | ]
9 |
10 | timeout = "5s"
11 | gather_memory_contexts = true
12 | gather_views = true
13 | ```
--------------------------------------------------------------------------------
/integrations/Canal/icon/canal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Canal/icon/canal.png
--------------------------------------------------------------------------------
/integrations/Canal/markdown/README.md:
--------------------------------------------------------------------------------
1 | ## canal
2 |
3 | canal 默认提供了 prometheus 格式指标的接口 [Prometheus-QuickStart](https://github.com/alibaba/canal/wiki/Prometheus-QuickStart) ,所以可以直接通过[ prometheus 插件](https://flashcat.cloud/docs/content/flashcat-monitor/categraf/plugin/prometheus)采集。
--------------------------------------------------------------------------------
/integrations/Ceph/icon/ceph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Ceph/icon/ceph.png
--------------------------------------------------------------------------------
/integrations/Ceph/markdown/README.md:
--------------------------------------------------------------------------------
1 | # ceph plugin
2 |
3 | 开启 ceph prometheus 支持
4 |
5 | ```bash
6 | ceph mgr module enable prometheus
7 | ```
8 |
9 | ## 采集配置
10 |
11 | 既然 ceph 可以暴露 prometheus 协议的 metrics 数据,则直接使用 prometheus 插件抓取即可。
12 |
13 | categraf 配置文件:`conf/input.prometheus/prometheus.toml`
14 |
15 | ```yaml
16 | [[instances]]
17 | urls = [
18 | "http://192.168.11.181:9283/metrics"
19 | ]
20 | labels = {service="ceph",cluster="ceph-cluster-001"}
21 | ```
22 |
23 |
24 | ## 仪表盘效果
25 |
26 | 夜莺内置仪表盘中已经内置了 ceph 的仪表盘,导入即可使用。
27 |
28 | 
29 |
30 | ## 告警规则
31 |
32 | 夜莺内置告警规则中已经内置了 ceph 的告警规则,导入即可使用。
33 |
34 | 
--------------------------------------------------------------------------------
/integrations/Ceph/markdown/alerts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Ceph/markdown/alerts.png
--------------------------------------------------------------------------------
/integrations/Ceph/markdown/ceph-alerts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Ceph/markdown/ceph-alerts.png
--------------------------------------------------------------------------------
/integrations/Ceph/markdown/ceph-dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Ceph/markdown/ceph-dash.png
--------------------------------------------------------------------------------
/integrations/Ceph/markdown/ceph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Ceph/markdown/ceph.png
--------------------------------------------------------------------------------
/integrations/ClickHouse/icon/clickhouse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/ClickHouse/icon/clickhouse.png
--------------------------------------------------------------------------------
/integrations/CloudWatch/icon/cloudwatch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/CloudWatch/icon/cloudwatch.png
--------------------------------------------------------------------------------
/integrations/Consul/collect/consul/consul.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | ## Consul server address
6 | # address = "localhost:8500"
7 |
8 | ## URI scheme for the Consul server, one of "http", "https"
9 | # scheme = "http"
10 |
11 | ## ACL token used in every request
12 | # token = ""
13 |
14 | ## HTTP Basic Authentication username and password.
15 | # username = ""
16 | # password = ""
17 |
18 | ## Data center to query the health checks from
19 | # datacenter = ""
20 |
21 | ## Allows any Consul server (non-leader) to service a read.
22 | ## Default is true
23 | # allow_stale = true
24 |
25 | ## Forces the read to be fully consistent.
26 | ## Default is false
27 | # require_consistent = false
28 |
29 | ## Prefix from which to expose key/value pairs.
30 | # kv_prefix = ""
31 |
32 | ## Regex that determines which keys to expose.
33 | ## Default is ".*"
34 | # kv_filter = ".*"
35 |
36 | ## Optional TLS Config
37 | # tls_ca = "/etc/telegraf/ca.pem"
38 | # tls_cert = "/etc/telegraf/cert.pem"
39 | # tls_key = "/etc/telegraf/key.pem"
40 | ## Use TLS but skip chain & host verification
41 | # insecure_skip_verify = true
42 |
--------------------------------------------------------------------------------
/integrations/Consul/icon/consul.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Consul/icon/consul.png
--------------------------------------------------------------------------------
/integrations/Dns_Query/collect/dns_query/dns_query.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | # # append some labels for series
6 | # labels = { region="cloud", product="n9e" }
7 |
8 | # # interval = global.interval * interval_times
9 | # interval_times = 1
10 |
11 | # #
12 | auto_detect_local_dns_server = false
13 |
14 | ## servers to query
15 | # servers = ["8.8.8.8"]
16 | servers = []
17 |
18 | ## Network is the network protocol name.
19 | # network = "udp"
20 |
21 | ## Domains or subdomains to query.
22 | # domains = ["."]
23 |
24 | ## Query record type.
25 | ## Possible values: A, AAAA, CNAME, MX, NS, PTR, TXT, SOA, SPF, SRV.
26 | # record_type = "A"
27 |
28 | ## Dns server port.
29 | # port = 53
30 |
31 | ## Query timeout in seconds.
32 | # timeout = 2
--------------------------------------------------------------------------------
/integrations/Dns_Query/icon/dns.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Dns_Query/icon/dns.png
--------------------------------------------------------------------------------
/integrations/Docker/icon/docker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Docker/icon/docker.png
--------------------------------------------------------------------------------
/integrations/Docker/markdown/README.md:
--------------------------------------------------------------------------------
1 | # docker
2 |
3 | forked from telegraf/inputs.docker
4 |
5 | ## change
6 |
7 | 1. Using `container_id` as label not field
8 | 1. Some metrics have been deleted
9 |
10 | ## 容器ID标签
11 |
12 | 通过下面两个配置来控制 container_id 这个标签:
13 |
14 | ```ini
15 | container_id_label_enable = true
16 | container_id_label_short_style = false
17 | ```
18 |
19 | 默认 container_id_label_enable 设置为 true,表示启用,即会把容器ID放到标签里,container_id_label_short_style 是短格式,容器ID很长,如果把 short_style 设置为 true,就会只截取前面12位
20 |
21 | ## 权限问题
22 |
23 | Categraf 最好是用 root 账号来运行,否则,请求 docker.sock 可能会遇到权限问题,需要把 Categraf 的运行账号,加到 docker group 中,假设 Categraf 使用 categraf 账号运行:
24 |
25 | ```
26 | sudo usermod -aG docker categraf
27 | ```
28 |
29 | ## 运行在容器里
30 |
31 | 如果 Categraf 运行在容器中,docker 的 unix socket 就需要挂到 Categraf 的容器里,比如通过 `-v /var/run/docker.sock:/var/run/docker.sock` 这样的参数来启动 Categraf 的容器。如果是在 compose 环境下,也可以在 docker compose 配置中加上 volume 的配置:
32 |
33 | ```yaml
34 | volumes:
35 | - /var/run/docker.sock:/var/run/docker.sock
36 | ```
37 |
38 | ## 停用该插件
39 |
40 | - 方法一:把 `input.docker` 目录改个别的名字,不用 `input.` 打头
41 | - 方法二:docker.toml 中的 endpoint 配置留空
--------------------------------------------------------------------------------
/integrations/Doris/collect/prometheus/collect_doris_examples.toml:
--------------------------------------------------------------------------------
1 | # doris_fe
2 | [[instances]]
3 | # 配置 fe metrics 服务地址
4 | urls = [
5 | "http://127.0.0.1:8030/metrics"
6 | ]
7 |
8 | url_label_key = "instance"
9 | url_label_value = "{{.Host}}"
10 | # 指定 fe 服务 group 和 job 标签,这里是仪表盘变量调用,可根据实际需求修改。
11 | labels = { group = "fe",job = "doris_cluster01"}
12 |
13 | # doris_be
14 | [[instances]]
15 | # 配置 be metrics 服务地址
16 | urls = [
17 | "http://127.0.0.1:8040/metrics"
18 | ]
19 | url_label_key = "instance"
20 | url_label_value = "{{.Host}}"
21 | # 指定 be 服务 group 和 job 标签,这里是仪表盘变量调用,可根据实际需求修改。
22 | labels = { group = "be",job = "doris_cluster01"}
--------------------------------------------------------------------------------
/integrations/Doris/icon/doris.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
27 |
--------------------------------------------------------------------------------
/integrations/Doris/markdown/README.md:
--------------------------------------------------------------------------------
1 | # Doris
2 |
3 | Doris 的进程都会暴露 `/metrics` 接口,通过这个接口暴露 Prometheus 协议的监控数据。
4 |
5 | ## 采集配置
6 |
7 | categraf 的 `conf/input.prometheus/prometheus.toml`。因为 Doris 是暴露的 Prometheus 协议的监控数据,所以使用 categraf 的 prometheus 插件即可采集。
8 |
9 | ```toml
10 | # doris_fe
11 | [[instances]]
12 | urls = [
13 | "http://127.0.0.1:8030/metrics"
14 | ]
15 |
16 | url_label_key = "instance"
17 | url_label_value = "{{.Host}}"
18 |
19 | labels = { group = "fe",job = "doris_cluster01"}
20 |
21 | # doris_be
22 | [[instances]]
23 | urls = [
24 | "http://127.0.0.1:8040/metrics"
25 | ]
26 | url_label_key = "instance"
27 | url_label_value = "{{.Host}}"
28 | labels = { group = "be",job = "doris_cluster01"}
29 | ```
30 |
31 | ## 告警规则
32 |
33 | 夜莺内置了 Doris 的告警规则,克隆到自己的业务组下即可使用。
34 |
35 | ## 仪表盘
36 |
37 | 夜莺内置了 Doris 的仪表盘,克隆到自己的业务组下即可使用。
38 |
39 |
40 |
--------------------------------------------------------------------------------
/integrations/Elasticsearch/icon/elasticsearch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Elasticsearch/icon/elasticsearch.png
--------------------------------------------------------------------------------
/integrations/Elasticsearch/markdown/README.md:
--------------------------------------------------------------------------------
1 | # elasticsearch plugin
2 |
3 | ElasticSearch 通过 HTTP JSON 的方式暴露了自身的监控指标,通过 categraf 的 [elasticsearch](https://github.com/flashcatcloud/categraf/tree/main/inputs/elasticsearch) 插件抓取。
4 |
5 | 如果是小规模集群,设置 `local=false`,从集群中某一个节点抓取数据,即可拿到整个集群所有节点的监控数据。如果是大规模集群,建议设置 `local=true`,在集群的每个节点上都部署抓取器,抓取本地 elasticsearch 进程的监控数据。
6 |
7 |
8 | ## 配置示例
9 |
10 | categraf 配置文件:`conf/input.elasticsearch/elasticsearch.toml`
11 |
12 | ```yaml
13 | [[instances]]
14 | servers = ["http://192.168.11.177:9200"]
15 | http_timeout = "10s"
16 | local = false
17 | cluster_health = true
18 | cluster_health_level = "cluster"
19 | cluster_stats = true
20 | indices_level = ""
21 | node_stats = ["jvm", "breaker", "process", "os", "fs", "indices", "thread_pool", "transport"]
22 | username = "elastic"
23 | password = "xxxxxxxx"
24 | num_most_recent_indices = 1
25 | labels = { service="es" }
26 | ```
27 |
28 | ## 仪表盘效果
29 |
30 | 夜莺内置仪表盘中已经内置了 Elasticsearch 的仪表盘,导入即可使用。
31 |
32 | 
--------------------------------------------------------------------------------
/integrations/Elasticsearch/markdown/es-dashboard.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Elasticsearch/markdown/es-dashboard.jpeg
--------------------------------------------------------------------------------
/integrations/Exec/collect/exec/exec.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | # # commands, support glob
6 | commands = [
7 | # "/opt/categraf/scripts/*.sh"
8 | ]
9 |
10 | # # timeout for each command to complete
11 | # timeout = 5
12 |
13 | # # interval = global.interval * interval_times
14 | # interval_times = 1
15 |
16 | # # choices: influx prometheus falcon
17 | # # influx stdout example: mesurement,labelkey1=labelval1,labelkey2=labelval2 field1=1.2,field2=2.3
18 | # data_format = "influx"
19 |
--------------------------------------------------------------------------------
/integrations/Exec/icon/exec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Exec/icon/exec.png
--------------------------------------------------------------------------------
/integrations/Filecount/collect/filecount/filecount.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | # # append some labels for series
6 | # labels = { region="cloud", product="n9e" }
7 |
8 | # # interval = global.interval * interval_times
9 | # interval_times = 1
10 |
11 | ## Directories to gather stats about.
12 | ## This accept standard unit glob matching rules, but with the addition of
13 | ## ** as a "super asterisk". ie:
14 | ## /var/log/** -> recursively find all directories in /var/log and count files in each directories
15 | ## /var/log/*/* -> find all directories with a parent dir in /var/log and count files in each directories
16 | ## /var/log -> count all files in /var/log and all of its subdirectories
17 | ## directories = ["/var/cache/apt", "/tmp"]
18 | directories = ["/tmp"]
19 |
20 | ## Only count files that match the name pattern. Defaults to "*".
21 | file_name = "*"
22 |
23 | ## Count files in subdirectories. Defaults to true.
24 | recursive = true
25 |
26 | ## Only count regular files. Defaults to true.
27 | regular_only = true
28 |
29 | ## Follow all symlinks while walking the directory tree. Defaults to false.
30 | follow_symlinks = false
31 |
32 | ## Only count files that are at least this size. If size is
33 | ## a negative number, only count files that are smaller than the
34 | ## absolute value of size. Acceptable units are B, KiB, MiB, KB, ...
35 | ## Without quotes and units, interpreted as size in bytes.
36 | size = "0B"
37 |
38 | ## Only count files that have not been touched for at least this
39 | ## duration. If mtime is negative, only count files that have been
40 | ## touched in this duration. Defaults to "0s".
41 | mtime = "0s"
42 |
--------------------------------------------------------------------------------
/integrations/Filecount/icon/filecount.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Filecount/icon/filecount.png
--------------------------------------------------------------------------------
/integrations/Gitlab/icon/gitlab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Gitlab/icon/gitlab.png
--------------------------------------------------------------------------------
/integrations/GoogleCloud/collect/googlecloud/gcp.toml:
--------------------------------------------------------------------------------
1 | #interval=60
2 | #[[instances]]
3 | #project_id="your-project-id"
4 | #credentials_file="/path/to/your/key.json"
5 | #delay="2m"
6 | #period="1m"
7 | #filter="metric.type=\"compute.googleapis.com/instance/cpu/utilization\" AND resource.labels.zone=\"asia-northeast1-a\""
8 | #timeout="5s"
9 | #cache_ttl="1h"
10 | #gce_host_tag="xxx"
11 | #request_inflight=30
12 |
--------------------------------------------------------------------------------
/integrations/GoogleCloud/icon/gcp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/GoogleCloud/icon/gcp.png
--------------------------------------------------------------------------------
/integrations/GoogleCloud/markdown/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # GCP 指标获取插件
4 |
5 | ## 需要权限
6 | ```shell
7 | https://www.googleapis.com/auth/monitoring.read
8 | ```
9 |
10 | ## 配置
11 | ```toml
12 | #采集周期,建议 >= 1分钟
13 | interval=60
14 | [[instances]]
15 | #配置 project_id
16 | project_id="your-project-id"
17 | #配置认证的key文件
18 | credentials_file="/path/to/your/key.json"
19 | #或者配置认证的JSON
20 | credentials_json="xxx"
21 |
22 | # 指标的end time = now - delay
23 | #delay="2m"
24 | # 指标的start time = now - deley - period
25 | #period="1m"
26 | # 过滤器
27 | #filter="metric.type=\"compute.googleapis.com/instance/cpu/utilization\" AND resource.labels.zone=\"asia-northeast1-a\""
28 | # 请求超时时间
29 | #timeout="5s"
30 | # 指标列表的缓存时长 ,filter为空时 启用
31 | #cache_ttl="1h"
32 |
33 | # 给gce的instance_name 取个别名,放到label中
34 | #gce_host_tag="xxx"
35 | # 每次最多有多少请求同时发起
36 | #request_inflight=30
37 |
38 | # request_inflight 取值(0,100]
39 | # 想配置更大的值 ,前提是你知道你在做什么
40 | force_request_inflight= 200
41 | ```
42 |
--------------------------------------------------------------------------------
/integrations/HAProxy/collect/haproxy/haproxy.toml:
--------------------------------------------------------------------------------
1 | [[instances]]
2 | # URI on which to scrape HAProxy.
3 | # e.g.
4 | # uri = "http://localhost:5000/baz?stats;csv"
5 | # uri = "http://user:pass@haproxy.example.com/haproxy?stats;csv"
6 | # uri = "unix:/run/haproxy/admin.sock"
7 | uri = ""
8 |
9 | # Flag that enables SSL certificate verification for the scrape URI
10 | ssl_verify = false
11 |
12 | # Comma-separated list of exported server metrics. See http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#9.1
13 | server_metric_fields = ""
14 |
15 | # Comma-separated list of exported server states to exclude. See https://cbonte.github.io/haproxy-dconv/1.8/management.html#9.1, field 17 status
16 | server_exclude_states = ""
17 |
18 | # Timeout for trying to get stats from HAProxy.
19 | timeout = "5s"
20 |
21 | # Flag that enables using HTTP proxy settings from environment variables ($http_proxy, $https_proxy, $no_proxy)
22 | proxy_from_env = false
23 |
--------------------------------------------------------------------------------
/integrations/HAProxy/icon/haproxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/HAProxy/icon/haproxy.png
--------------------------------------------------------------------------------
/integrations/HAProxy/markdown/README.md:
--------------------------------------------------------------------------------
1 | # HAProxy
2 |
3 | forked from [haproxy_exporter](https://github.com/prometheus/haproxy_exporter)
4 |
5 | Note: since HAProxy 2.0.0, the official source includes a Prometheus exporter module that can be built into your binary with a single flag during build time and offers an exporter-free Prometheus endpoint.
6 |
7 |
8 | haproxy configurations for `/stats`:
9 |
10 | ```
11 | frontend stats
12 | bind *:8404
13 | stats enable
14 | stats uri /stats
15 | stats refresh 10s
16 | ```
--------------------------------------------------------------------------------
/integrations/HTTP_Response/icon/http_response.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/HTTP_Response/icon/http_response.png
--------------------------------------------------------------------------------
/integrations/IPMI/collect/ipmi/conf.toml:
--------------------------------------------------------------------------------
1 | # Read metrics from the bare metal servers via freeipmi
2 | [[instances]]
3 | # target指定是本地采集还是远程采集
4 | #target="localhost"
5 | # 指定采集的用户名和密码,这里务必保证ipmi命令能获取正确输出,不是网上查到一个用户名 密码就可以。
6 | #user = "user"
7 | #pass = "1234"
8 |
9 | # ipmi协议版本,支持1.5 和 2.0
10 | #driver = "LAN_2_0"
11 |
12 | # 指定特权用户名
13 | #privilege = "user"
14 |
15 | ## session-timeout, ms
16 | #timeout = 100000
17 |
18 | # 支持的采集器 bmc, bmc-watchdog, ipmi, chassis, dcmi, sel,sm-lan-mode
19 | # 默认使用 bmc, ipmi, chassis和dcmi,建议保持下列配置便于仪表盘更好的展示
20 | collectors = [ "bmc", "ipmi", "chassis", "sel", "dcmi"]
21 |
22 | # 不关注的传感器,指定id 排除掉
23 | #exclude_sensor_ids = [ 2, 29, 32, 50, 52, 55 ]
24 |
25 | # 如果你想使用定制化的参数覆盖内置的命令,可以修改以下内容; 建议保持注释
26 | #[instances.collector_cmd]
27 | #ipmi = "sudo"
28 | #sel = "sudo"
29 | #[instances.default_args]
30 | #ipmi = [ "--bridge-sensors" ]
31 | #[instances.custom_args]
32 | #ipmi = [ "--bridge-sensors" ]
33 | #sel = [ "ipmi-sel" ]
--------------------------------------------------------------------------------
/integrations/IPMI/icon/ipmi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/IPMI/icon/ipmi.png
--------------------------------------------------------------------------------
/integrations/IPMI/markdown/README.md:
--------------------------------------------------------------------------------
1 | # IPMI plugin
2 | ipmi插件是从ipmi exporter迁移过来。 基本原理是通过执行ipmi的一系列命令并将命令输出转换为指标,如果ipmi没有配置好,是无法采集到指标的,请务必将ipmi配置好。
3 |
4 | categraf的ipmi插件配置举例如下:
5 | ```toml
6 | # Read metrics from the bare metal servers via freeipmi
7 | [[instances]]
8 | # target指定是本地采集还是远程采集
9 | #target="localhost"
10 | # 指定采集的用户名和密码,这里务必保证ipmi命令能获取正确输出,不是网上查到一个用户名 密码就可以。
11 | #user = "user"
12 | #pass = "1234"
13 |
14 | # ipmi协议版本,支持1.5 和 2.0
15 | #driver = "LAN_2_0"
16 |
17 | # 指定特权用户名
18 | #privilege = "user"
19 |
20 | ## session-timeout, ms
21 | #timeout = 100000
22 |
23 | # 支持的采集器 bmc, bmc-watchdog, ipmi, chassis, dcmi, sel,sm-lan-mode
24 | # 默认使用 bmc, ipmi, chassis和dcmi,建议保持下列配置便于仪表盘更好的展示
25 | collectors = [ "bmc", "ipmi", "chassis", "sel", "dcmi"]
26 |
27 | # 不关注的传感器,指定id 排除掉
28 | #exclude_sensor_ids = [ 2, 29, 32, 50, 52, 55 ]
29 |
30 | # 如果你想使用定制化的参数覆盖内置的命令,可以修改以下内容; 建议保持注释
31 | #[instances.collector_cmd]
32 | #ipmi = "sudo"
33 | #sel = "sudo"
34 | #[instances.default_args]
35 | #ipmi = [ "--bridge-sensors" ]
36 | #[instances.custom_args]
37 | #ipmi = [ "--bridge-sensors" ]
38 | #sel = [ "ipmi-sel" ]
39 | ```
--------------------------------------------------------------------------------
/integrations/IPVS/collect/ipvs/ipvs.toml:
--------------------------------------------------------------------------------
1 | # Collect virtual and real server stats from Linux IPVS
2 | # no configuration
3 |
--------------------------------------------------------------------------------
/integrations/IPVS/icon/ipvs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/IPVS/icon/ipvs.png
--------------------------------------------------------------------------------
/integrations/JMX/icon/jmx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/JMX/icon/jmx.png
--------------------------------------------------------------------------------
/integrations/Jenkins/collect/jenkins/jenkins.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | # Address (host:port) of jenkins server.
6 | # jenkins_url = "http://my-jenkins-instance:8080"
7 |
8 | #jenkins_username = "admin"
9 | #jenkins_password = ""
10 |
11 | #response_timeout = "5s"
12 |
13 |
--------------------------------------------------------------------------------
/integrations/Jenkins/icon/jenkins.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Jenkins/icon/jenkins.png
--------------------------------------------------------------------------------
/integrations/Jenkins/markdown/README.md:
--------------------------------------------------------------------------------
1 | ## Jenkins
2 |
3 | Jenkins 采集插件, 采集 Jenkins 数据
4 |
5 | ## Configuration
6 |
7 | ```toml
8 | # # collect interval
9 | # interval = 15
10 |
11 | [[instances]]
12 | # Address (host:port) of jenkins server.
13 | # jenkins_url = "http://my-jenkins-instance:8080"
14 |
15 | #jenkins_username = "admin"
16 | #jenkins_password = ""
17 |
18 | #response_timeout = "5s"
19 |
20 |
21 | ```
--------------------------------------------------------------------------------
/integrations/Jolokia_Agent/collect/jolokia_agent/bitbucket.toml:
--------------------------------------------------------------------------------
1 | [[instances]]
2 | urls = ["http://localhost:8778/jolokia"]
3 | metrics_name_prefix = "bitbucket_"
4 |
5 | [[instances.metric]]
6 | name = "jvm_operatingsystem"
7 | mbean = "java.lang:type=OperatingSystem"
8 |
9 | [[instances.metric]]
10 | name = "jvm_runtime"
11 | mbean = "java.lang:type=Runtime"
12 |
13 | [[instances.metric]]
14 | name = "jvm_thread"
15 | mbean = "java.lang:type=Threading"
16 |
17 | [[instances.metric]]
18 | name = "jvm_memory"
19 | mbean = "java.lang:type=Memory"
20 |
21 | [[instances.metric]]
22 | name = "jvm_class_loading"
23 | mbean = "java.lang:type=ClassLoading"
24 |
25 | [[instances.metric]]
26 | name = "jvm_memory_pool"
27 | mbean = "java.lang:type=MemoryPool,name=*"
28 |
29 | [[instances.metric]]
30 | name = "webhooks"
31 | mbean = "com.atlassian.webhooks:name=*"
32 |
33 | [[instances.metric]]
34 | name = "atlassian"
35 | mbean = "com.atlassian.bitbucket:name=*"
36 |
37 | [[instances.metric]]
38 | name = "thread_pools"
39 | mbean = "com.atlassian.bitbucket.thread-pools:name=*"
40 |
--------------------------------------------------------------------------------
/integrations/Jolokia_Agent/collect/jolokia_agent/java.toml:
--------------------------------------------------------------------------------
1 |
2 | [[instances]]
3 | urls = ["http://localhost:8080/jolokia"]
4 |
5 | [[instances.metric]]
6 | name = "java_runtime"
7 | mbean = "java.lang:type=Runtime"
8 | paths = ["Uptime"]
9 |
10 | [[instances.metric]]
11 | name = "java_memory"
12 | mbean = "java.lang:type=Memory"
13 | paths = ["HeapMemoryUsage", "NonHeapMemoryUsage", "ObjectPendingFinalizationCount"]
14 |
15 | [[instances.metric]]
16 | name = "java_garbage_collector"
17 | mbean = "java.lang:name=*,type=GarbageCollector"
18 | paths = ["CollectionTime", "CollectionCount"]
19 | tag_keys = ["name"]
20 |
21 | [[instances.metric]]
22 | name = "java_last_garbage_collection"
23 | mbean = "java.lang:name=G1 Young Generation,type=GarbageCollector"
24 | paths = ["LastGcInfo/duration", "LastGcInfo/GcThreadCount", "LastGcInfo/memoryUsageAfterGc"]
25 |
26 | [[instances.metric]]
27 | name = "java_threading"
28 | mbean = "java.lang:type=Threading"
29 | paths = ["TotalStartedThreadCount", "ThreadCount", "DaemonThreadCount", "PeakThreadCount"]
30 |
31 | [[instances.metric]]
32 | name = "java_class_loading"
33 | mbean = "java.lang:type=ClassLoading"
34 | paths = ["LoadedClassCount", "UnloadedClassCount", "TotalLoadedClassCount"]
35 |
36 | [[instances.metric]]
37 | name = "java_memory_pool"
38 | mbean = "java.lang:name=*,type=MemoryPool"
39 | paths = ["Usage", "PeakUsage", "CollectionUsage"]
40 | tag_keys = ["name"]
41 |
--------------------------------------------------------------------------------
/integrations/Jolokia_Agent/collect/jolokia_agent/zookeeper.toml:
--------------------------------------------------------------------------------
1 | [[instances]]
2 | urls = ["http://localhost:8080/jolokia"]
3 | name_prefix = "zk_"
4 |
5 | [[instances.metric]]
6 | name = "quorum"
7 | mbean = "org.apache.ZooKeeperService:name0=*"
8 | tag_keys = ["name0"]
9 |
10 | [[instances.metric]]
11 | name = "leader"
12 | mbean = "org.apache.ZooKeeperService:name0=*,name1=*,name2=Leader"
13 | tag_keys = ["name1"]
14 |
15 | [[instances.metric]]
16 | name = "follower"
17 | mbean = "org.apache.ZooKeeperService:name0=*,name1=*,name2=Follower"
18 | tag_keys = ["name1"]
19 |
--------------------------------------------------------------------------------
/integrations/Jolokia_Agent/icon/jolokia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Jolokia_Agent/icon/jolokia.png
--------------------------------------------------------------------------------
/integrations/Jolokia_Agent/markdown/README.md:
--------------------------------------------------------------------------------
1 | # Jolokia Agent
2 |
3 | forked from telegraf/inputs.jolokia2_agent
4 |
5 | ## 停用该插件
6 |
7 | - 方法一:把 `input.jolokia_agent_misc` 目录改个别的名字,不用 `input.` 打头
8 | - 方法二:xx.toml 中的配置留空
--------------------------------------------------------------------------------
/integrations/Kafka/icon/kafka.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Kafka/icon/kafka.png
--------------------------------------------------------------------------------
/integrations/Kafka/markdown/alerts-kafka.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Kafka/markdown/alerts-kafka.png
--------------------------------------------------------------------------------
/integrations/Kafka/markdown/alerts..png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Kafka/markdown/alerts..png
--------------------------------------------------------------------------------
/integrations/Kafka/markdown/dash-kafka.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Kafka/markdown/dash-kafka.png
--------------------------------------------------------------------------------
/integrations/Kafka/markdown/dashboards.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Kafka/markdown/dashboards.png
--------------------------------------------------------------------------------
/integrations/Kubernetes/icon/kubernetes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Kubernetes/icon/kubernetes.png
--------------------------------------------------------------------------------
/integrations/Kubernetes/markdown/README.md:
--------------------------------------------------------------------------------
1 | # Kubernetes
2 |
3 | 这个插件已经废弃。Kubernetes 监控系列可以参考这个 [文章](https://flashcat.cloud/categories/kubernetes%E7%9B%91%E6%8E%A7%E4%B8%93%E6%A0%8F/)。
4 |
5 | 不过 Kubernetes 这个类别下的内置告警规则和内置仪表盘都是可以使用的。
6 |
7 | ---
8 |
9 | 下面是老插件文档:
10 |
11 | forked from telegraf/kubernetes. 这个插件的作用是通过kubelet提供的API获取监控数据,包括系统容器的监控数据、node的、pod数据卷的、pod网络的、pod容器的。
12 |
13 | ## Change
14 |
15 | 增加了一些控制开关:
16 |
17 | `gather_system_container_metrics = true`
18 |
19 | 是否采集 system 容器(kubelet、runtime、misc、pods),比如 kubelet 一般就是静态容器,非业务容器
20 |
21 | `gather_node_metrics = true`
22 |
23 | 是否采集 node 层面的指标,机器层面的指标其实 categraf 来采集了,这里理论上不需要再采集了,可以设置为 false,采集也没问题,也没多少数据
24 |
25 | `gather_pod_container_metrics = true`
26 |
27 | 是否采集 Pod 中的容器的指标,这些 Pod 一般是业务容器
28 |
29 | `gather_pod_volume_metrics = true`
30 |
31 | 是否采集 Pod 的数据卷的指标
32 |
33 | `gather_pod_network_metrics = true`
34 |
35 | 是否采集 Pod 的网络监控数据
36 |
37 | ## 容器监控
38 |
39 | 通过这些开关可以看出,kubernetes 这个插件,采集的只是 pod、容器的监控指标,这些指标数据来自 kubelet 的 `/stats/summary` `/pods` 等接口。那么问题来了,容器监控到底是应该读取 `/metrics/cadvisor` 接口还是应该用这个 kubernetes 插件?有几个决策依据:
40 |
41 | 1. `/metrics/cadvisor` 采集的数据没有业务自定义标签,kubernetes 这个插件会自动带上业务自定义标签。但是业务标签可能比较混乱,建议每个公司制定规范,比如要求业务只能打 project、region、env、service、app、job 等标签,其他标签都过滤掉,通过 kubernetes 插件的 label_include label_exclude 配置,可以做标签过滤。
42 | 2. kubernetes 这个插件采集的数据比 `/metrics/cadvisor` 吐出的指标要少,不过常见的 cpu、mem、net、volume 相关的也都有。
43 |
--------------------------------------------------------------------------------
/integrations/Ldap/collect/ldap/ldap.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | # # append some labels for series
6 | # labels = { region="cloud", product="n9e" }
7 |
8 | # # interval = global.interval * interval_times
9 | # interval_times = 1
10 |
11 | ## Server to monitor
12 | ## The scheme determines the mode to use for connection with
13 | ## ldap://... -- unencrypted (non-TLS) connection
14 | ## ldaps://... -- TLS connection
15 | ## starttls://... -- StartTLS connection
16 | ## If no port is given, the default ports, 389 for ldap and starttls and
17 | ## 636 for ldaps, are used.
18 | #server = "ldap://localhost"
19 |
20 | ## Server dialect, can be "openldap" or "389ds"
21 | # dialect = "openldap"
22 |
23 | # DN and password to bind with
24 | ## If bind_dn is empty an anonymous bind is performed.
25 | bind_dn = ""
26 | bind_password = ""
27 |
28 | ## Reverse the field names constructed from the monitoring DN
29 | # reverse_field_names = false
30 |
31 | ## Optional TLS Config
32 | # use_tls = false
33 | # tls_ca = "/etc/categraf/ca.pem"
34 | # tls_cert = "/etc/categraf/cert.pem"
35 | # tls_key = "/etc/categraf/key.pem"
36 | ## Use TLS but skip chain & host verification
37 | # insecure_skip_verify = false
--------------------------------------------------------------------------------
/integrations/Ldap/icon/ldap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Ldap/icon/ldap.png
--------------------------------------------------------------------------------
/integrations/Linux/collect/arp_packet/arp_packet.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | #eth_device="ens192"
--------------------------------------------------------------------------------
/integrations/Linux/collect/netstat/netstat.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | disable_summary_stats = false
5 | ## if machine has many network connections, use this plugin may exhaust your cpu resource, diable connection stat to avoid this
6 | disable_connection_stats = true
7 |
8 | tcp_ext = false
9 | ip_ext = false
10 |
--------------------------------------------------------------------------------
/integrations/Linux/collect/ntp/ntp.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # ntp servers
5 | # ntp_servers = ["ntp.aliyun.com"]
6 |
7 | # # response time out seconds
8 | # timeout = 5
--------------------------------------------------------------------------------
/integrations/Linux/collect/processes/processes.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # # force use ps command to gather
5 | # force_ps = false
6 |
7 | # # force use /proc to gather
8 | # force_proc = false
--------------------------------------------------------------------------------
/integrations/Linux/icon/linux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Linux/icon/linux.png
--------------------------------------------------------------------------------
/integrations/Linux/markdown/README.md:
--------------------------------------------------------------------------------
1 | # Linux
2 |
3 | Linux 类别下,包含多个内置插件,比如 cpu、mem、net、netstat、kernel_vmstat 等,这些插件大都是默认是开启的,无需额外配置,可能有额外配置需求的插件如下。
4 |
5 | ## cpu
6 |
7 | 统计 CPU 使用率,默认只采集整机的情况,不采集每个 CPU Core 的情况,如果想采集每个 CPU Core 的情况,可以配置如下。
8 |
9 | ```ini
10 | collect_per_cpu = true
11 | ```
12 |
13 | ## netstat
14 |
15 | 统计网络连接数,默认配置如下,可根据实际情况调整。
16 |
17 | ```ini
18 | # 默认开启了 smmary 统计,类似 ss -s 命令的输出
19 | disable_summary_stats = false
20 | # 默认关闭了所有连接的详细统计,在连接数较多的机器上统计此数据会影响性能
21 | disable_connection_stats = true
22 | # 读取 /proc/net/netstat 的内容,默认关闭了,可以开启,这部分不影响性能
23 | tcp_ext = false
24 | ip_ext = false
25 | ```
26 |
27 | ## disk
28 |
29 | 统计磁盘使用率,默认配置如下,可根据实际情况调整。
30 |
31 | ```ini
32 | # 严格指定要采集的挂载点,如果指定了,就只采集指定的挂载点
33 | # mount_points = ["/"]
34 |
35 | # 有些 fstype 没必要采集,可以忽略
36 | ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs", "nsfs", "CDFS", "fuse.juicefs"]
37 |
38 | # 有些挂载点没必要采集,可以忽略,这里可以配置前缀,符合前缀的挂载点都会被忽略
39 | ignore_mount_points = ["/boot", "/var/lib/kubelet/pods"]
40 | ```
41 |
42 | ## kernel_vmstat
43 |
44 | 统计的信息来自 `/proc/vmstat`,只有高版本内核才支持,这个文件的内容较多,默认配置只采集了 oom_kill 次数,其他指标均未采集,如果你想打开其他采集开关,可以修改 white_list 部分的配置。下面是截取了一部分内容,供参考:
45 |
46 | ```toml
47 | [white_list]
48 | oom_kill = 1
49 | nr_free_pages = 0
50 | nr_alloc_batch = 0
51 | ...
52 | ```
53 |
54 | ## arp_package
55 |
56 | 统计 ARP 包的数量,该插件依赖 cgo,如果需要该插件需要下载 `with-cgo` 的 categraf 发布包。
57 |
58 |
59 | ## ntp
60 |
61 | 监控机器时间偏移量,只需要给出 ntp 服务端地址,Categraf 就会周期性去请求,对比本机时间,得到偏移量,监控指标是 ntp_offset_ms 顾名思义,单位是毫秒,一般这个值不能超过 1000
--------------------------------------------------------------------------------
/integrations/Logstash/collect/logstash/logstash.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # Read metrics exposed by Logstash
5 | [[instances]]
6 | # # interval = global.interval * interval_times
7 | # interval_times = 1
8 |
9 | # append labels
10 | # labels = { instance="x" }
11 |
12 | ## The URL of the exposed Logstash API endpoint.
13 | # url = "http://127.0.0.1:9600"
14 | url = ""
15 |
16 | ## Use Logstash 5 single pipeline API, set to true when monitoring
17 | ## Logstash 5.
18 | # single_pipeline = false
19 |
20 | ## Enable optional collection components. Can contain
21 | ## "pipelines", "process", and "jvm".
22 | # collect = ["pipelines", "process", "jvm"]
23 |
24 | ## Timeout for HTTP requests.
25 | # timeout = "5s"
26 |
27 | ## Optional HTTP Basic Auth credentials.
28 | # username = "username"
29 | # password = "pa$$word"
30 |
31 | ## Optional HTTP headers.
32 | # [inputs.logstash.headers]
33 | # "X-Special-Header" = "Special-Value"
34 |
35 | ## Optional TLS Config
36 | # use_tls = false
37 | # tls_min_version = "1.2"
38 | # tls_ca = "/etc/categraf/ca.pem"
39 | # tls_cert = "/etc/categraf/cert.pem"
40 | # tls_key = "/etc/categraf/key.pem"
41 | ## Use TLS but skip chain & host verification
42 | # insecure_skip_verify = true
--------------------------------------------------------------------------------
/integrations/Logstash/icon/logstash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Logstash/icon/logstash.png
--------------------------------------------------------------------------------
/integrations/Logstash/markdown/README.md:
--------------------------------------------------------------------------------
1 | # logstash
2 |
3 | logstash 监控采集插件,由telegraf改造而来。
4 |
5 | ## Configuration
6 |
7 | 请参考配置[示例](https://github.com/flashcatcloud/categraf/blob/main/conf/input.logstash/logstash.toml)
8 |
9 | ## 监控大盘和告警规则
10 |
11 | 同级目录下的 logstash-dash 是示例的监控面板, 可以直接导入夜莺使用。
--------------------------------------------------------------------------------
/integrations/MinIO/icon/minio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/MinIO/icon/minio.png
--------------------------------------------------------------------------------
/integrations/MinIO/markdown/README.md:
--------------------------------------------------------------------------------
1 | # MinIO
2 |
3 | 参考 [使用 Prometheus 采集 MinIO 指标](https://min.io/docs/minio/linux/operations/monitoring/collect-minio-metrics-using-prometheus.html?ref=docs-redirect#minio-metrics-collect-using-prometheus)
4 |
5 | 开启 MinIO Prometheus 访问;
6 |
7 | ```bash
8 | # 启动 MinIO 服务的时候加入下面的变量:
9 | MINIO_PROMETHEUS_AUTH_TYPE=public
10 | ```
11 |
12 | ## 采集配置
13 |
14 | categraf 的 `conf/input.prometheus/prometheus.toml`
15 |
16 | ```toml
17 | [[instances]]
18 | urls = [
19 | "http://192.168.1.188:9000/minio/v2/metrics/cluster"
20 | ]
21 | labels = {job="minio-cluster"}
22 | ```
23 |
24 | ## Dashboard
25 |
26 | 夜莺内置了 MinIO 的仪表盘,克隆到自己的业务组下即可使用。
27 |
28 | 
29 |
30 | ## Alerts
31 |
32 | 夜莺内置了 MinIO 的告警规则,克隆到自己的业务组下即可使用。
33 |
34 | 
--------------------------------------------------------------------------------
/integrations/MinIO/markdown/alerts-minio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/MinIO/markdown/alerts-minio.png
--------------------------------------------------------------------------------
/integrations/MinIO/markdown/alerts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/MinIO/markdown/alerts.png
--------------------------------------------------------------------------------
/integrations/MinIO/markdown/dash-minio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/MinIO/markdown/dash-minio.png
--------------------------------------------------------------------------------
/integrations/MinIO/markdown/minio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/MinIO/markdown/minio.png
--------------------------------------------------------------------------------
/integrations/MongoDB/icon/mongodb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/MongoDB/icon/mongodb.png
--------------------------------------------------------------------------------
/integrations/Mtail/collect/mtail/mtail.toml:
--------------------------------------------------------------------------------
1 | [[instances]]
2 | # progs = "/path/to/prog1" # prog dir1
3 | # logs = ["/path/to/a.log", "path/to/b.log"]
4 | # override_timezone = "Asia/Shanghai"
5 | # emit_metric_timestamp = "true" #string type
6 |
7 | # [[instances]]
8 | # progs = "/path/to/prog2" # prog dir2
9 | # logs = ["/path/to/logdir/"]
10 | # override_timezone = "Asia/Shanghai"
11 | # emit_metric_timestamp = "true" # string type
12 |
--------------------------------------------------------------------------------
/integrations/Mtail/icon/mtail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Mtail/icon/mtail.png
--------------------------------------------------------------------------------
/integrations/Mtail/markdown/timestamp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Mtail/markdown/timestamp.png
--------------------------------------------------------------------------------
/integrations/Mtail/markdown/timezone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Mtail/markdown/timezone.png
--------------------------------------------------------------------------------
/integrations/MySQL/icon/mysql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/MySQL/icon/mysql.png
--------------------------------------------------------------------------------
/integrations/N9E/icon/nightingale.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/N9E/icon/nightingale.png
--------------------------------------------------------------------------------
/integrations/N9E/markdown/README.md:
--------------------------------------------------------------------------------
1 | # N9E
2 |
3 | 夜莺V5版本分两个组件,n9e-webapi 和 n9e-server,都通过 `/metrics` 接口暴露了 Prometheus 协议的监控数据。夜莺V6版本默认只有一个组件,就是 n9e,也通过 `/metrics` 接口暴露了 Prometheus 协议的监控数据。如果使用边缘机房部署方案,会用到 n9e-edge,n9e-edge 也通过 `/metrics` 接口暴露了 Prometheus 协议的监控数据。
4 |
5 | 所以,通过 categraf 的 prometheus 插件即可采集夜莺的监控数据。
6 |
7 | ## 采集配置
8 |
9 | categraf 的 `conf/input.prometheus/prometheus.toml`
10 |
11 | ```toml
12 | [[instances]]
13 | urls = [
14 | "http://IP:17000/metrics"
15 | ]
16 | labels = {job="n9e"}
17 | ```
18 |
19 | ## Dashboard
20 |
21 | 夜莺内置了两个 N9E 仪表盘,n9e_server 是给 V5 版本用的,n9e_v6 是给 V6 版本用的。
22 |
23 |
--------------------------------------------------------------------------------
/integrations/NFSClient/collect/nfsclient/nfsclient.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | ## Read more low-level metrics (optional, defaults to false)
5 | fullstat = false
6 |
7 | ## List of mounts to explictly include or exclude (optional)
8 | ## The pattern (Go regexp) is matched against the mount point (not the
9 | ## device being mounted). If include_mounts is set, all mounts are ignored
10 | ## unless present in the list. If a mount is listed in both include_mounts
11 | ## and exclude_mounts, it is excluded. Go regexp patterns can be used.
12 |
13 | # include_mounts = []
14 | # exclude_mounts = []
15 |
16 | ## List of operations to include or exclude from collecting. This applies
17 | ## only when fullstat=true. Symantics are similar to {include,exclude}_mounts:
18 | ## the default is to collect everything; when include_operations is set, only
19 | ## those OPs are collected; when exclude_operations is set, all are collected
20 | ## except those listed. If include and exclude are set, the OP is excluded.
21 | ## See /proc/self/mountstats for a list of valid operations; note that
22 | ## NFSv3 and NFSv4 have different lists. While it is not possible to
23 | ## have different include/exclude lists for NFSv3/4, unused elements
24 | ## in the list should be okay. It is possible to have different lists
25 | ## for different mountpoints: use mulitple [[input.nfsclient]] stanzas,
26 | ## with their own lists. See "include_mounts" above, and be careful of
27 | ## duplicate metrics.
28 |
29 | # include_operations = ['READ','WRITE','ACCESS','GETATTR','READDIR','LOOKUP']
30 | # exclude_operations = []
31 |
--------------------------------------------------------------------------------
/integrations/NFSClient/icon/nfsclient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/NFSClient/icon/nfsclient.png
--------------------------------------------------------------------------------
/integrations/NFSClient/markdown/README.md:
--------------------------------------------------------------------------------
1 | # NFS Client
2 |
3 | forked from telegraf/inputs.nfsclient
4 |
5 | ## 停用该插件
6 |
7 | - 方法一:把 `input.nfsclient` 目录改个别的名字,不用 `input.` 打头
8 | - 方法二:nfsclient.toml 中的配置留空
--------------------------------------------------------------------------------
/integrations/NSQ/collect/nsq/nsq.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # [[instances]]
5 | ## The Nsq API URI used to collect statistical information.
6 | # targets = ["http://localhost:4151"]
7 |
8 | # headers={Authorization="", X-Forwarded-For="", Host=""}
9 |
10 | # timeout="5s"
11 |
12 | # # basic auth
13 | # username=""
14 | # password=""
15 |
16 | ## append some labels for series
17 | # labels = { product="nsq" }
18 |
19 | ## interval = global.interval * interval_times
20 | # interval_times = 1
21 |
--------------------------------------------------------------------------------
/integrations/NSQ/icon/nsq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/NSQ/icon/nsq.png
--------------------------------------------------------------------------------
/integrations/NVIDIA/collect/nvidia_smi/nvidia_smi.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # exec local command
5 | # e.g. nvidia_smi_command = "nvidia-smi"
6 | nvidia_smi_command = ""
7 |
8 | # exec remote command
9 | # nvidia_smi_command = "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null SSH_USER@SSH_HOST nvidia-smi"
10 |
11 | # Comma-separated list of the query fields.
12 | # You can find out possible fields by running `nvidia-smi --help-query-gpus`.
13 | # The value `AUTO` will automatically detect the fields to query.
14 | query_field_names = "AUTO"
--------------------------------------------------------------------------------
/integrations/NVIDIA/icon/nvidia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/NVIDIA/icon/nvidia.png
--------------------------------------------------------------------------------
/integrations/NVIDIA/markdown/README.md:
--------------------------------------------------------------------------------
1 | # nvidia_smi
2 |
3 | 该采集插件的原理,就是读取 nvidia-smi 命令的内容输出,转换为Prometheus格式的监控数据上报给Nightingale夜莺。
4 |
5 | 是对 [nvidia_gpu_exporter](https://github.com/utkuozdemir/nvidia_gpu_exporter) 代码的集成。
6 |
7 | ## Configuration
8 |
9 | 配置文件在 `conf/input.nvidia_smi/nvidia_smi.toml`
10 |
11 | ```toml
12 | # # collect interval
13 | # interval = 15
14 |
15 | # 下面这个配置是最重要的配置,如果要采集 nvidia-smi 的信息,就打开下面的配置,
16 | # 给出 nvidia-smi 命令的路径,最好是给绝对路径
17 | # 相当于让 Categraf 执行本机的 nvidia-smi 命令,获取本机 GPU 的状态信息
18 | # exec local command
19 | # nvidia_smi_command = "nvidia-smi"
20 |
21 | # 如果想远程方式采集远端机器的 GPU 状态信息,可以使用 ssh 命令,登录远端机器
22 | # 在远端机器执行 nvidia-smi 的命令输出,通常 Categraf 是部署在每个物理机上的
23 | # 所以,ssh 这种方式,理论上用不到
24 | # exec remote command
25 | # nvidia_smi_command = "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null SSH_USER@SSH_HOST nvidia-smi"
26 |
27 | # Comma-separated list of the query fields.
28 | # You can find out possible fields by running `nvidia-smi --help-query-gpus`.
29 | # The value `AUTO` will automatically detect the fields to query.
30 | query_field_names = "AUTO"
31 | ```
32 |
33 | ## TODO
34 |
35 | GPU 卡已经关注哪些监控指标,缺少监控大盘JSON和告警规则JSON,欢迎大家 PR
36 |
--------------------------------------------------------------------------------
/integrations/Net_Response/alerts/net_response_by_categraf.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 0,
4 | "group_id": 0,
5 | "cate": "",
6 | "datasource_ids": null,
7 | "cluster": "",
8 | "name": "Network address probe failed",
9 | "note": "",
10 | "prod": "",
11 | "algorithm": "",
12 | "algo_params": null,
13 | "delay": 0,
14 | "severity": 2,
15 | "severities": null,
16 | "disabled": 0,
17 | "prom_for_duration": 60,
18 | "prom_ql": "net_response_result_code != 0",
19 | "rule_config": null,
20 | "prom_eval_interval": 15,
21 | "enable_stime": "00:00",
22 | "enable_stimes": null,
23 | "enable_etime": "23:59",
24 | "enable_etimes": null,
25 | "enable_days_of_week": [
26 | "1",
27 | "2",
28 | "3",
29 | "4",
30 | "5",
31 | "6",
32 | "0"
33 | ],
34 | "enable_days_of_weeks": null,
35 | "enable_in_bg": 0,
36 | "notify_recovered": 1,
37 | "notify_channels": [],
38 | "notify_groups_obj": null,
39 | "notify_groups": null,
40 | "notify_repeat_step": 60,
41 | "notify_max_number": 0,
42 | "recover_duration": 0,
43 | "callbacks": [],
44 | "runbook_url": "",
45 | "append_tags": [],
46 | "annotations": null,
47 | "extra_config": null,
48 | "create_at": 0,
49 | "create_by": "",
50 | "update_at": 0,
51 | "update_by": "",
52 | "uuid": 1717556328182186000
53 | }
54 | ]
--------------------------------------------------------------------------------
/integrations/Net_Response/collect/net_response/net_response.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [mappings]
5 | # "127.0.0.1:22"= {region="local",ssh="test"}
6 | # "127.0.0.1:22"= {region="local",ssh="redis"}
7 |
8 | [[instances]]
9 | targets = [
10 | # "127.0.0.1:22",
11 | # "localhost:6379",
12 | # ":9090"
13 | ]
14 |
15 | # # append some labels for series
16 | # labels = { region="cloud", product="n9e" }
17 |
18 | # # interval = global.interval * interval_times
19 | # interval_times = 1
20 |
21 | ## Protocol, must be "tcp" or "udp"
22 | ## NOTE: because the "udp" protocol does not respond to requests, it requires
23 | ## a send/expect string pair (see below).
24 | # protocol = "tcp"
25 |
26 | ## Set timeout
27 | # timeout = "1s"
28 |
29 | ## Set read timeout (only used if expecting a response)
30 | # read_timeout = "1s"
31 |
32 | ## The following options are required for UDP checks. For TCP, they are
33 | ## optional. The plugin will send the given string to the server and then
34 | ## expect to receive the given 'expect' string back.
35 | ## string sent to the server
36 | # send = "ssh"
37 | ## expected string in answer
38 | # expect = "ssh"
39 |
--------------------------------------------------------------------------------
/integrations/Net_Response/icon/net_response.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Net_Response/icon/net_response.png
--------------------------------------------------------------------------------
/integrations/Net_Response/metrics/categraf.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 0,
4 | "uuid": 1717556328185013000,
5 | "collector": "Categraf",
6 | "typ": "Net_Response",
7 | "name": "NET 探测结果状态码",
8 | "unit": "none",
9 | "note": "0 值表示正常,大于 0 就是异常,各个值的含义如下:\n\n- 0: Success\n- 1: Timeout\n- 2: ConnectionFailed\n- 3: ReadFailed\n- 4: StringMismatch",
10 | "lang": "zh_CN",
11 | "expression": "net_response_result_code",
12 | "created_at": 0,
13 | "created_by": "",
14 | "updated_at": 0,
15 | "updated_by": ""
16 | },
17 | {
18 | "id": 0,
19 | "uuid": 1717556328186975000,
20 | "collector": "Categraf",
21 | "typ": "Net_Response",
22 | "name": "NET 探测耗时",
23 | "unit": "seconds",
24 | "note": "",
25 | "lang": "zh_CN",
26 | "expression": "net_response_response_time",
27 | "created_at": 0,
28 | "created_by": "",
29 | "updated_at": 0,
30 | "updated_by": ""
31 | }
32 | ]
--------------------------------------------------------------------------------
/integrations/Netstat_Filter/collect/netstat_filter/netstat_filter.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 | [[instances]]
4 | # laddr_ip = ""
5 | # laddr_port = 0
6 | # raddr_ip = ""
7 | # raddr_port = 0
8 |
--------------------------------------------------------------------------------
/integrations/Netstat_Filter/icon/netstat_filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Netstat_Filter/icon/netstat_filter.png
--------------------------------------------------------------------------------
/integrations/Netstat_Filter/markdown/README.md:
--------------------------------------------------------------------------------
1 | # netstat_filter
2 |
3 | 该插件采集网络连接情况,并根据用户条件进行过滤统计,以达到监控用户关心链接情况
4 | ## 指标列表
5 | tcp_established
6 | tcp_syn_sent
7 | tcp_syn_recv
8 | tcp_fin_wait1
9 | tcp_fin_wait2
10 | tcp_time_wait
11 | tcp_close
12 | tcp_close_wait
13 | tcp_last_ack
14 | tcp_listen
15 | tcp_closing
16 | tcp_none
17 | tcp_send_queue
18 | tcp_recv_queue
19 |
20 | ## 功能说明
21 | 对源IP、源端口、目标IP和目标端口过滤后进行网卡recv-Q、send-Q进行采集,该指标可以很好反应出指定连接的质量,例如rtt时间过长,导致收到服务端ack确认很慢就会使send-Q长期大于0,可以及时通过监控发现,从而提前优化网络或程序
22 |
23 | 当过滤结果为多个连接时会将send和recv值进行加和
24 | 例如:
25 | 配置文件``raddr_port = 11883``
26 | 当本地和不同IP的11883都有连接建立的情况下,会将多条连接的结果进行加和。或在并发多连接的情况下,会合并加合,总之过滤的越粗略被加合数就会越多。
27 |
28 | 多条规则请复制``[[instances]]``进行配置
29 |
30 | ## 注意事项
31 | netstat_filter_tcp_send_queue和netstat_filter_tcp_recv_queue指标目前只支持linux。windows用户默认为0。
32 |
--------------------------------------------------------------------------------
/integrations/Nginx/collect/nginx/nginx.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | ## An array of Nginx stub_status URI to gather stats.
6 | urls = [
7 | # "http://192.168.0.216:8000/nginx_status",
8 | # "https://www.baidu.com/ngx_status"
9 | ]
10 |
11 | ## append some labels for series
12 | # labels = { region="cloud", product="n9e" }
13 |
14 | ## interval = global.interval * interval_times
15 | # interval_times = 1
16 |
17 | ## Set response_timeout (default 5 seconds)
18 | response_timeout = "5s"
19 |
20 | ## Whether to follow redirects from the server (defaults to false)
21 | # follow_redirects = false
22 |
23 | ## Optional HTTP Basic Auth Credentials
24 | #username = "admin"
25 | #password = "admin"
26 |
27 | ## Optional headers
28 | # headers = ["X-From", "categraf", "X-Xyz", "abc"]
29 |
30 | ## Optional TLS Config
31 | # use_tls = false
32 | # tls_ca = "/etc/categraf/ca.pem"
33 | # tls_cert = "/etc/categraf/cert.pem"
34 | # tls_key = "/etc/categraf/key.pem"
35 | ## Use TLS but skip chain & host verification
36 | # insecure_skip_verify = false
--------------------------------------------------------------------------------
/integrations/Nginx/collect/nginx_upstream_check/nginx_upstream_check.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | targets = [
6 | # "http://127.0.0.1/status?format=json",
7 | # "http://10.2.3.56/status?format=json"
8 | ]
9 |
10 | # # append some labels for series
11 | # labels = { region="cloud", product="n9e" }
12 |
13 | # # interval = global.interval * interval_times
14 | # interval_times = 1
15 |
16 | ## Set http_proxy (categraf uses the system wide proxy settings if it's is not set)
17 | # http_proxy = "http://localhost:8888"
18 |
19 | ## Interface to use when dialing an address
20 | # interface = "eth0"
21 |
22 | ## HTTP Request Method
23 | # method = "GET"
24 |
25 | ## Set timeout (default 5 seconds)
26 | # timeout = "5s"
27 |
28 | ## Whether to follow redirects from the server (defaults to false)
29 | # follow_redirects = false
30 |
31 | ## Optional HTTP Basic Auth Credentials
32 | # username = "username"
33 | # password = "pa$$word"
34 |
35 | ## Optional headers
36 | # headers = ["X-From", "categraf", "X-Xyz", "abc"]
37 |
38 | ## Optional TLS Config
39 | # use_tls = false
40 | # tls_ca = "/etc/categraf/ca.pem"
41 | # tls_cert = "/etc/categraf/cert.pem"
42 | # tls_key = "/etc/categraf/key.pem"
43 | ## Use TLS but skip chain & host verification
44 | # insecure_skip_verify = false
45 |
--------------------------------------------------------------------------------
/integrations/Nginx/icon/nginx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Nginx/icon/nginx.png
--------------------------------------------------------------------------------
/integrations/Oracle/icon/oracle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Oracle/icon/oracle.png
--------------------------------------------------------------------------------
/integrations/Oracle/markdown/README.md:
--------------------------------------------------------------------------------
1 | # Oracle plugin
2 |
3 | Oracle 插件,用于监控 Oracle 数据库。默认无法跑在 Windows 上。如果你的 Oracle 部署在 Windows 上,也没问题,使用部署在 Linux 上的 Categraf 远程监控 Windows 上的 Oracle,也行得通。
4 |
5 | Oracle 插件的核心监控原理,就是执行下面 [这些 SQL 语句](https://github.com/flashcatcloud/categraf/blob/main/conf/input.oracle/metric.toml),然后解析出结果,上报到监控服务端。
6 |
7 | 以其中一个为例:
8 |
9 | ```toml
10 | [[metrics]]
11 | mesurement = "activity"
12 | metric_fields = [ "value" ]
13 | field_to_append = "name"
14 | timeout = "3s"
15 | request = '''
16 | SELECT name, value FROM v$sysstat WHERE name IN ('parse count (total)', 'execute count', 'user commits', 'user rollbacks')
17 | '''
18 | ```
19 |
20 | - mesurement:指标类别
21 | - label_fields:作为 label 的字段
22 | - metric_fields:作为 metric 的字段,因为是作为 metric 的字段,所以这个字段的值必须是数字
23 | - field_to_append:表示这个字段附加到 metric_name 后面,作为 metric_name 的一部分
24 | - timeout:超时时间
25 | - request:具体查询的 SQL 语句
26 |
27 | 如果你想监控的指标,默认没有采集,只需要增加自定义的 `[[metrics]]` 配置即可。
28 |
--------------------------------------------------------------------------------
/integrations/PHP/collect/phpfpm/phpfpm.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | ## An array of Nginx stub_status URI to gather stats.
6 | urls = [
7 | ## HTTP: the URL must start with http:// or https://, ie:
8 | # "http://localhost/status",
9 | # "https://www.baidu.com/phpfpm-status",
10 | ## fcgi: the URL must start with fcgi:// or cgi://, and port must be present, ie:
11 | # "fcgi://127.0.0.1:9001",
12 | # "cgi://192.168.0.1:9000/status",
13 | ## Unix socket: path to fpm socket, ie:
14 | # "/run/php/php7.2-fpm.sock",
15 | ## or using a custom fpm status path:
16 | # "/var/run/php5-fpm.sock:/fpm-custom-status-path",
17 | ## glob patterns are also supported:
18 | # "/var/run/php*.sock"
19 | ]
20 |
21 | ## append some labels for series
22 | # labels = { region="cloud", product="n9e" }
23 |
24 | ## interval = global.interval * interval_times
25 | # interval_times = 1
26 |
27 | ## Set response_timeout (default 5 seconds),HTTP urls only
28 | response_timeout = "5s"
29 |
30 | ## Whether to follow redirects from the server (defaults to false),HTTP urls only
31 | # follow_redirects = false
32 |
33 | ## Optional HTTP Basic Auth Credentials,HTTP urls only
34 | #username = "admin"
35 | #password = "admin"
36 |
37 | ## Optional headers,HTTP urls only
38 | # headers = ["X-From", "categraf", "X-Xyz", "abc"]
39 |
40 | ## Optional TLS Config,only http
41 | # use_tls = false
42 | # tls_ca = "/etc/categraf/ca.pem"
43 | # tls_cert = "/etc/categraf/cert.pem"
44 | # tls_key = "/etc/categraf/key.pem"
45 | ## Use TLS but skip chain & host verification
46 | # insecure_skip_verify = false
--------------------------------------------------------------------------------
/integrations/PHP/icon/phpfpm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/PHP/icon/phpfpm.png
--------------------------------------------------------------------------------
/integrations/PHP/markdown/README.md:
--------------------------------------------------------------------------------
1 | # PHP-FPM
2 |
3 | *PHP-FPM* (PHP FastCGI Process Manager) 监控采集插件,由telegraf的phpfpm改造而来。
4 |
5 | 该插件需要更改phpfpm的配置文件,开启 *pm.status_path*配置项
6 | ```
7 | pm.status_path = /status
8 | ```
9 |
10 |
11 | ## Configuration
12 |
13 | 请参考配置[示例](https://github.com/flashcatcloud/categraf/blob/main/conf/input.phpfpm/phpfpm.toml)文件
14 |
15 | ### 注意事项:
16 | 1. 如下配置 仅生效于HTTP的url
17 | - response_timeout
18 | - username & password
19 | - headers
20 | - TLS config
21 | 2. 如果使用 Unix socket,需要保证 categraf 和 socket path 在同一个主机上,且 categraf 运行用户拥有读取该 path 的权限。
22 | ## 监控大盘和告警规则
23 |
24 | 待更新...
--------------------------------------------------------------------------------
/integrations/Ping/collect/ping/ping.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | # send ping packets to
6 | targets = [
7 | # "www.baidu.com",
8 | # "127.0.0.1",
9 | # "10.4.5.6",
10 | # "10.4.5.7"
11 | ]
12 |
13 | # # append some labels for series
14 | # labels = { region="cloud", product="n9e" }
15 |
16 | # # interval = global.interval * interval_times
17 | # interval_times = 1
18 |
19 | ## Number of ping packets to send per interval. Corresponds to the "-c"
20 | ## option of the ping command.
21 | # count = 1
22 |
23 | ## Time to wait between sending ping packets in seconds. Operates like the
24 | ## "-i" option of the ping command.
25 | # ping_interval = 1.0
26 |
27 | ## If set, the time to wait for a ping response in seconds. Operates like
28 | ## the "-W" option of the ping command.
29 | # timeout = 3.0
30 |
31 | ## Interface or source address to send ping from. Operates like the -I or -S
32 | ## option of the ping command.
33 | # interface = ""
34 |
35 | ## Use only IPv6 addresses when resolving a hostname.
36 | # ipv6 = false
37 |
38 | ## Number of data bytes to be sent. Corresponds to the "-s"
39 | ## option of the ping command.
40 | # size = 56
41 |
42 | # max concurrency coroutine
43 | # concurrency = 50
44 |
--------------------------------------------------------------------------------
/integrations/Ping/icon/ping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Ping/icon/ping.png
--------------------------------------------------------------------------------
/integrations/Ping/markdown/README.md:
--------------------------------------------------------------------------------
1 | # ping
2 |
3 | ping 监控插件,探测远端目标地址能否 ping 通,如果机器没有禁 ping,这就是一个很好用的探测机器存活的手段
4 |
5 | ## Configuration
6 |
7 | categraf 的 `conf/input.ping/ping.toml`。
8 |
9 | 要探测的机器配置到 targets 中,targets 是个数组,可以配置多个,当然也可以拆成多个 `[[instances]]` 配置段,比如:
10 |
11 | ```
12 | [[instances]]
13 | targets = [ "10.4.5.6" ]
14 | labels = { region="cloud", product="n9e" }
15 |
16 | [[instances]]
17 | targets = [ "10.4.5.7" ]
18 | labels = { region="cloud", product="zbx" }
19 | ```
20 |
21 | 上例中是 ping 两个地址,为了信息更丰富,附加了 region 和 product 标签
22 |
23 | ## File Limit
24 |
25 | ```sh
26 | systemctl edit categraf
27 | ```
28 |
29 | Increase the number of open files:
30 |
31 | ```ini
32 | [Service]
33 | LimitNOFILE=8192
34 | ```
35 |
36 | Restart Categraf:
37 |
38 | ```sh
39 | systemctl restart categraf
40 | ```
41 |
42 | ### Linux Permissions
43 |
44 | On most systems, ping requires `CAP_NET_RAW` capabilities or for Categraf to be run as root.
45 |
46 | With systemd:
47 |
48 | ```sh
49 | systemctl edit categraf
50 | ```
51 |
52 | ```ini
53 | [Service]
54 | CapabilityBoundingSet=CAP_NET_RAW
55 | AmbientCapabilities=CAP_NET_RAW
56 | ```
57 |
58 | ```sh
59 | systemctl restart categraf
60 | ```
61 |
62 | Without systemd:
63 |
64 | ```sh
65 | setcap cap_net_raw=eip /usr/bin/categraf
66 | ```
67 |
68 | Reference [`man 7 capabilities`][man 7 capabilities] for more information about
69 | setting capabilities.
70 |
71 | [man 7 capabilities]: http://man7.org/linux/man-pages/man7/capabilities.7.html
72 |
73 | ### Other OS Permissions
74 |
75 | When using `method = "native"`, you will need permissions similar to the executable ping program for your OS.
76 |
77 | ## 监控大盘和告警规则
78 |
79 | 夜莺内置了告警规则和监控大盘,克隆到自己的业务组下即可使用。
80 |
--------------------------------------------------------------------------------
/integrations/PostgreSQL/icon/postgresql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/PostgreSQL/icon/postgresql.png
--------------------------------------------------------------------------------
/integrations/PostgreSQL/markdown/alerts-pg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/PostgreSQL/markdown/alerts-pg.png
--------------------------------------------------------------------------------
/integrations/PostgreSQL/markdown/alerts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/PostgreSQL/markdown/alerts.png
--------------------------------------------------------------------------------
/integrations/PostgreSQL/markdown/dash-pg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/PostgreSQL/markdown/dash-pg.png
--------------------------------------------------------------------------------
/integrations/PostgreSQL/markdown/postgresql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/PostgreSQL/markdown/postgresql.png
--------------------------------------------------------------------------------
/integrations/Procstat/collect/procstat/procstat.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # [[instances]]
5 | # # executable name (ie, pgrep )
6 | # search_exec_substring = "nginx"
7 |
8 | # # pattern as argument for pgrep (ie, pgrep -f )
9 | # search_cmdline_substring = "n9e server"
10 |
11 | # # windows service name
12 | # search_win_service = ""
13 |
14 | # # search process with specific user, option with exec_substring or cmdline_substring
15 | # search_user = ""
16 |
17 | # # append some labels for series
18 | # labels = { region="cloud", product="n9e" }
19 |
20 | # # interval = global.interval * interval_times
21 | # interval_times = 1
22 |
23 | # # mode to use when calculating CPU usage. can be one of 'solaris' or 'irix'
24 | # mode = "irix"
25 |
26 | # sum of threads/fd/io/cpu/mem, min of uptime/limit
27 | gather_total = true
28 |
29 | # will append pid as tag
30 | gather_per_pid = false
31 |
32 | # gather jvm metrics only when jstat is ready
33 | # gather_more_metrics = [
34 | # "threads",
35 | # "fd",
36 | # "io",
37 | # "uptime",
38 | # "cpu",
39 | # "mem",
40 | # "limit",
41 | # "jvm"
42 | # ]
43 |
--------------------------------------------------------------------------------
/integrations/Procstat/icon/process.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Procstat/icon/process.png
--------------------------------------------------------------------------------
/integrations/Prometheus/collect/prometheus/prometheus.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | urls = [
6 | # "http://localhost:19000/metrics"
7 | ]
8 |
9 | url_label_key = "instance"
10 | url_label_value = "{{.Host}}"
11 |
12 | ## Scrape Services available in Consul Catalog
13 | # [instances.consul]
14 | # enabled = false
15 | # agent = "http://localhost:8500"
16 | # query_interval = "5m"
17 |
18 | # [[instances.consul.query]]
19 | # name = "a service name"
20 | # tag = "a service tag"
21 | # url = 'http://{{if ne .ServiceAddress ""}}{{.ServiceAddress}}{{else}}{{.Address}}{{end}}:{{.ServicePort}}/{{with .ServiceMeta.metrics_path}}{{.}}{{else}}metrics{{end}}'
22 | # [instances.consul.query.tags]
23 | # host = "{{.Node}}"
24 |
25 | # bearer_token_string = ""
26 |
27 | # e.g. /run/secrets/kubernetes.io/serviceaccount/token
28 | # bearer_token_file = ""
29 |
30 | # # basic auth
31 | # username = ""
32 | # password = ""
33 |
34 | # headers = ["X-From", "categraf"]
35 |
36 | # # interval = global.interval * interval_times
37 | # interval_times = 1
38 |
39 | # labels = {}
40 |
41 | # support glob
42 | # ignore_metrics = [ "go_*" ]
43 |
44 | # support glob
45 | # ignore_label_keys = []
46 |
47 | # timeout for every url
48 | # timeout = "3s"
49 |
50 | ## Optional TLS Config
51 | # use_tls = false
52 | # tls_min_version = "1.2"
53 | # tls_ca = "/etc/categraf/ca.pem"
54 | # tls_cert = "/etc/categraf/cert.pem"
55 | # tls_key = "/etc/categraf/key.pem"
56 | ## Use TLS but skip chain & host verification
57 | # insecure_skip_verify = true
58 |
--------------------------------------------------------------------------------
/integrations/Prometheus/icon/prometheus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Prometheus/icon/prometheus.png
--------------------------------------------------------------------------------
/integrations/Prometheus/markdown/README.md:
--------------------------------------------------------------------------------
1 | # prometheus
2 |
3 | prometheus 插件的作用,就是抓取 `/metrics` 接口的数据,上报给服务端。通过,各类 exporter 会暴露 `/metrics` 接口数据,越来越多的开源组件也会内置 prometheus SDK,吐出 prometheus 格式的监控数据,比如 rabbitmq 插件,其 README 中就有介绍。
4 |
5 | 这个插件 fork 自 telegraf/prometheus,做了一些删减改造,仍然支持通过 consul 做服务发现,管理所有的目标地址,删掉了 Kubernetes 部分,Kubernetes 部分准备放到其他插件里实现。
6 |
7 | 增加了两个配置:url_label_key 和 url_label_value。为了标识监控数据是从哪个 scrape url 拉取的,会为监控数据附一个标签来标识这个 url,默认的标签 KEY 是用 instance,当然,也可以改成别的,不过不建议。url_label_value 是标签值,支持 go template 语法,如果为空,就是整个 url 的内容,也可以通过模板变量只取一部分,比如 `http://localhost:9104/metrics`,只想取 IP 和端口部分,就可以写成:
8 |
9 | ```ini
10 | url_label_value = "{{.Host}}"
11 | ```
12 |
13 | 如果 HTTP scheme 部分和 `/metrics` Path 部分都想取,可以这么写:
14 |
15 | ```ini
16 | url_label_value = "{{.Scheme}}://{{.Host}}{{.Path}}"
17 | ```
18 |
19 | 相关变量是用这个方法生成的,供大家参考:
20 |
21 | ```go
22 | func (ul *UrlLabel) GenerateLabel(u *url.URL) (string, string, error) {
23 | if ul.LabelValue == "" {
24 | return ul.LabelKey, u.String(), nil
25 | }
26 |
27 | dict := map[string]string{
28 | "Scheme": u.Scheme,
29 | "Host": u.Host,
30 | "Hostname": u.Hostname(),
31 | "Port": u.Port(),
32 | "Path": u.Path,
33 | "Query": u.RawQuery,
34 | "Fragment": u.Fragment,
35 | }
36 |
37 | var buffer bytes.Buffer
38 | err := ul.LabelValueTpl.Execute(&buffer, dict)
39 | if err != nil {
40 | return "", "", err
41 | }
42 |
43 | return ul.LabelKey, buffer.String(), nil
44 | }
45 | ```
--------------------------------------------------------------------------------
/integrations/RabbitMQ/icon/rabbitmq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/RabbitMQ/icon/rabbitmq.png
--------------------------------------------------------------------------------
/integrations/RabbitMQ/markdown/README.md:
--------------------------------------------------------------------------------
1 | # RabbitMQ
2 |
3 | 高版本(3.8以上版本)的 RabbitMQ,已经内置支持了暴露 Prometheus 协议的监控数据。所以,直接使用 categraf 的 prometheus 插件即可采集。开启 RabbitMQ Prometheus 访问:
4 |
5 | ```bash
6 | rabbitmq-plugins enable rabbitmq_prometheus
7 | ```
8 |
9 | 启用成功的话,rabbitmq 默认会在 15692 端口起监听,访问 `http://localhost:15692/metrics` 即可看到符合 prometheus 协议的监控数据。
10 |
11 | 如果低于 3.8 的版本,还是需要使用 categraf 的 rabbitmq 插件来采集监控数据。
12 |
13 | ## 告警规则
14 |
15 | 夜莺内置了 RabbitMQ 的告警规则,克隆到自己的业务组下即可使用。
16 |
17 | ## 仪表盘
18 |
19 | 夜莺内置了 RabbitMQ 的仪表盘,克隆到自己的业务组下即可使用。`rabbitmq_v3.8_gt` 是大于等于 3.8 版本的仪表盘,`rabbitmq_v3.8_lt` 是小于 3.8 版本的仪表盘。
20 |
21 | 
22 |
--------------------------------------------------------------------------------
/integrations/RabbitMQ/markdown/rabbitmq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/RabbitMQ/markdown/rabbitmq.png
--------------------------------------------------------------------------------
/integrations/Redis/collect/redis/redis.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | # address = "127.0.0.1:6379"
6 | # username = ""
7 | # password = ""
8 | # pool_size = 2
9 |
10 | # # Optional. Specify redis commands to retrieve values
11 | # commands = [
12 | # {command = ["get", "sample-key1"], metric = "custom_metric_name1"},
13 | # {command = ["get", "sample-key2"], metric = "custom_metric_name2"}
14 | # ]
15 |
16 | # # interval = global.interval * interval_times
17 | # interval_times = 1
18 |
19 | # important! use global unique string to specify instance
20 | # labels = { instance="n9e-10.2.3.4:6379" }
21 |
22 | ## Optional TLS Config
23 | # use_tls = false
24 | # tls_min_version = "1.2"
25 | # tls_ca = "/etc/categraf/ca.pem"
26 | # tls_cert = "/etc/categraf/cert.pem"
27 | # tls_key = "/etc/categraf/key.pem"
28 | ## Use TLS but skip chain & host verification
29 | # insecure_skip_verify = true
30 |
--------------------------------------------------------------------------------
/integrations/Redis/collect/redis_sentinel/redis_sentinel.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | # [protocol://][:password]@address[:port]
6 | # e.g. servers = ["tcp://localhost:26379"]
7 | servers = []
8 |
9 | # # interval = global.interval * interval_times
10 | # interval_times = 1
11 | # add some dimension data by labels
12 | # labels = {}
13 |
14 | ## Optional TLS Config
15 | # use_tls = false
16 | # tls_min_version = "1.2"
17 | # tls_ca = "/etc/categraf/ca.pem"
18 | # tls_cert = "/etc/categraf/cert.pem"
19 | # tls_key = "/etc/categraf/key.pem"
20 | ## Use TLS but skip chain & host verification
21 | # insecure_skip_verify = true
22 |
--------------------------------------------------------------------------------
/integrations/Redis/icon/redis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Redis/icon/redis.png
--------------------------------------------------------------------------------
/integrations/Redis/markdown/README.md:
--------------------------------------------------------------------------------
1 | # redis
2 |
3 | redis 的监控原理,就是连上 redis,执行 info 命令,解析结果,整理成监控数据上报。
4 |
5 | ## Configuration
6 |
7 | redis 插件的配置在 `conf/input.redis/redis.toml` 最简单的配置如下:
8 |
9 | ```toml
10 | [[instances]]
11 | address = "127.0.0.1:6379"
12 | username = ""
13 | password = ""
14 | labels = { instance="n9e-10.23.25.2:6379" }
15 | ```
16 |
17 | 如果要监控多个 redis 实例,就增加 instances 即可:
18 |
19 | ```toml
20 | [[instances]]
21 | address = "10.23.25.2:6379"
22 | username = ""
23 | password = ""
24 | labels = { instance="n9e-10.23.25.2:6379" }
25 |
26 | [[instances]]
27 | address = "10.23.25.3:6379"
28 | username = ""
29 | password = ""
30 | labels = { instance="n9e-10.23.25.3:6379" }
31 | ```
32 |
33 | 建议通过 labels 配置附加一个 instance 标签,便于后面复用监控大盘。
34 |
35 | ## 监控大盘和告警规则
36 |
37 | 夜莺内置了 redis 的告警规则和监控大盘,克隆到自己的业务组下即可使用。
38 |
39 | ## redis 集群如何监控
40 |
41 | 其实,redis 集群的监控,还是去监控每个 redis 实例。
42 |
43 | 如果一个 redis 集群有 3 个实例,对于业务应用来讲,发起一个请求,可能随机请求到某一个实例上去了,这个是没问题的,但是对于监控 client 而言,显然是希望到所有实例上获取数据的。
44 |
45 | 当然,如果多个 redis 实例组成了集群,我们希望有个标识来标识这个集群,这个时候,可以通过 labels 来实现,比如给每个实例增加一个 redis_clus 的标签,值为集群名字即可。
46 |
47 |
48 | # redis_sentinel
49 | forked from [telegraf/redis_sentinel](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/redis_sentinel)
50 |
--------------------------------------------------------------------------------
/integrations/SMART/icon/smart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/SMART/icon/smart.png
--------------------------------------------------------------------------------
/integrations/SNMP/icon/snmp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/SNMP/icon/snmp.png
--------------------------------------------------------------------------------
/integrations/SQLServer/icon/sqlserver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/SQLServer/icon/sqlserver.png
--------------------------------------------------------------------------------
/integrations/SQLServer/markdown/README.md:
--------------------------------------------------------------------------------
1 | # sqlserver
2 |
3 | forked from telegraf/sqlserver. 这个插件的作用是获取sqlserver的监控指标,这里去掉了Azure相关部分监控,只保留了本地部署sqlserver情况。
4 |
5 | # 使用
6 | 按照下面方法创建监控账号,用于读取监控数据
7 | USE master;
8 |
9 | CREATE LOGIN [categraf] WITH PASSWORD = N'mystrongpassword';
10 |
11 | GRANT VIEW SERVER STATE TO [categraf];
12 |
13 | GRANT VIEW ANY DEFINITION TO [categraf];
14 | Data Source=10.19.1.1;Initial Catalog=hc;User ID=sa;Password=mystrongpassword;
--------------------------------------------------------------------------------
/integrations/SpringBoot/icon/springboot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/SpringBoot/icon/springboot.png
--------------------------------------------------------------------------------
/integrations/SpringBoot/markdown/README.md:
--------------------------------------------------------------------------------
1 | # SpringBoot
2 |
3 | Java 生态的项目,如果要暴露 metrics 数据,一般可以选择 micrometer,不过 SpringBoot 项目可以直接使用 SpringBoot Actuator 暴露 metrics 数据,Actuator 底层也是使用 micrometer 来实现的,只是使用起来更加简单。
4 |
5 | ## 应用配置
6 |
7 | 在 application.properties 中加入如下配置:
8 |
9 | ```properties
10 | management.endpoint.metrics.enabled=true
11 | management.endpoints.web.exposure.include=*
12 | management.endpoint.prometheus.enabled=true
13 | management.metrics.export.prometheus.enabled=true
14 | ```
15 |
16 | 完事启动项目,访问 `http://localhost:8080/actuator/prometheus` 即可看到符合 prometheus 协议的监控数据。
17 |
18 | ## 采集配置
19 |
20 | 既然暴露了 Prometheus 协议的监控数据,那通过 categraf prometheus 插件直接采集即可。配置文件是 `conf/input.prometheus/prometheus.toml`。配置样例如下:
21 |
22 | ```toml
23 | [[instances]]
24 | urls = [
25 | "http://192.168.11.177:8080/actuator/prometheus"
26 | ]
27 | ```
28 |
29 | ## 仪表盘
30 |
31 | 夜莺内置了一个 SpringBoot 仪表盘,由网友贡献,克隆到自己的业务组下即可使用,欢迎大家一起来提 PR 完善。
32 |
33 | 
34 |
--------------------------------------------------------------------------------
/integrations/SpringBoot/markdown/actuator.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/SpringBoot/markdown/actuator.jpeg
--------------------------------------------------------------------------------
/integrations/SpringBoot/markdown/actuator_2.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/SpringBoot/markdown/actuator_2.0.png
--------------------------------------------------------------------------------
/integrations/Switch_Legacy/icon/switch_legacy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Switch_Legacy/icon/switch_legacy.png
--------------------------------------------------------------------------------
/integrations/Switch_Legacy/markdown/README.md:
--------------------------------------------------------------------------------
1 | # switch_legacy
2 |
3 | 交换机监控插件,fork 自 [https://github.com/gaochao1/swcollector](https://github.com/gaochao1/swcollector) 可以自动探测网络设备型号,获取 CPU、内存使用率,当然,还有各个网口的监控数据,这是通用的 oid
4 |
5 | ## Configuration
6 |
7 | 最核心的配置就是指定 IP 列表,有三种写法:
8 |
9 | ```toml
10 | [[instances]]
11 | ips = [
12 | "172.16.2.1",
13 | "172.16.4/24",
14 | "192.168.56.102-192.168.56.120"
15 | ]
16 | ```
17 |
18 | 该插件只支持 SNMP v2c,所以认证信息就是一个 community 字符串
19 |
20 | ## 唯一标识标签
21 |
22 | 网络设备的监控数据,默认都会带有 ip 标签,指定监控数据来源于哪个设备,如果想把监控数据当做夜莺里的监控对象,让网络设备自动出现在夜莺的监控对象表格里,只需要把 switch_id_label 设置为 ident 即可,这样一来,网络设备的 IP 信息会作为 ident 标签的值上报,夜莺会自动读取 ident 标签的值入库
23 |
24 | ## 名称映射
25 |
26 | 有时,我们看到网络设备的 IP,无法分辨是具体哪个设备,此时可以给 IP 一个映射名称:
27 |
28 | ```ini
29 | [mappings]
30 | "192.168.88.160" = "switch001.bj"
31 | "192.168.88.161" = "switch002.bj"
32 | ```
33 |
34 | 这样一来,上报的监控数据就不用 IP 做标识了,而是使用 switch001.bj 这样的字符串做标识,更易读一些
35 |
36 | ## 自定义 oid
37 |
38 | `[[instances.customs]]` 部分可以配置多个,表示自定义 oid,默认情况下,该插件采集的都是设备各个网口的监控数据以及CPU和内存的使用率,如果要采集别的 oid,就需要使用这个自定义功能
39 |
40 | ## 监控大盘
41 |
42 | 社区有小伙伴帮忙做了一个监控大盘,就在该 README 同级目录下,大家可以导入夜莺使用
--------------------------------------------------------------------------------
/integrations/Systemd/collect/systemd/systemd.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | enable=false # 设置为true 打开采集
5 | #unit_include=".+"
6 | #unit_exclude=""
7 | enable_start_time_metrics=true #是否采集service unit的启动时间信息 单位秒
8 | enable_task_metrics=true # 是否采集service unit task的metrics
9 | enable_restarts_metrics=true #是否采集service unit重启的次数信息
10 |
--------------------------------------------------------------------------------
/integrations/Systemd/icon/systemd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Systemd/icon/systemd.png
--------------------------------------------------------------------------------
/integrations/Systemd/markdown/README.md:
--------------------------------------------------------------------------------
1 | # systemd 插件
2 | 自 [node_exporter](https://github.com/prometheus/node_exporter/blob/master/collector/systemd_linux.go) fork 并改动
3 |
4 | ## Configuration
5 | ```toml
6 | enable=false # 设置为true 打开采集
7 | #unit_include=".+"
8 | #unit_exclude=""
9 | enable_start_time_metrics=true #是否采集service unit的启动时间信息 单位秒
10 | enable_task_metrics=true # 是否采集service unit task的metrics
11 | enable_restarts_metrics=true #是否采集service unit重启的次数信息
12 | ```
13 |
--------------------------------------------------------------------------------
/integrations/TDEngine/icon/tdengine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/TDEngine/icon/tdengine.png
--------------------------------------------------------------------------------
/integrations/TDEngine/markdown/README.md:
--------------------------------------------------------------------------------
1 | # TDEngine
2 |
3 | TDEngine 也可以暴露 Prometheus 的监控数据,具体启用方法如下:
4 |
5 | TODO
6 |
7 | ## 采集配置
8 |
9 | 既然暴露了 Prometheus 协议的监控数据,那通过 categraf prometheus 插件直接采集即可。配置文件是 `conf/input.prometheus/prometheus.toml`。配置样例如下:
10 |
11 | ```toml
12 | [[instances]]
13 | urls = [
14 | "http://192.168.11.177:8080/xxxx"
15 | ]
16 | ```
17 |
18 | ## 仪表盘
19 |
20 | 夜莺内置了一个 TDEngine 仪表盘,由网友贡献,克隆到自己的业务组下即可使用,欢迎大家一起来提 PR 完善。
--------------------------------------------------------------------------------
/integrations/TiDB/icon/tidb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/TiDB/icon/tidb.png
--------------------------------------------------------------------------------
/integrations/Tomcat/collect/tomcat/tomcat.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | # Gather metrics from the Tomcat server status page.
5 | [[instances]]
6 | ## URL of the Tomcat server status
7 | # url = "http://127.0.0.1:8080/manager/status/all?XML=true"
8 | url = ""
9 |
10 | ## HTTP Basic Auth Credentials
11 | # username = "tomcat"
12 | # password = "s3cret"
13 |
14 | ## Request timeout
15 | # timeout = "5s"
16 |
17 | # # interval = global.interval * interval_times
18 | # interval_times = 1
19 |
20 | # important! use global unique string to specify instance
21 | # labels = { instance="192.168.1.2:8080", url="-" }
22 |
23 | ## Optional TLS Config
24 | # use_tls = false
25 | # tls_min_version = "1.2"
26 | # tls_ca = "/etc/categraf/ca.pem"
27 | # tls_cert = "/etc/categraf/cert.pem"
28 | # tls_key = "/etc/categraf/key.pem"
29 | ## Use TLS but skip chain & host verification
30 | # insecure_skip_verify = true
31 |
--------------------------------------------------------------------------------
/integrations/Tomcat/icon/tomcat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Tomcat/icon/tomcat.png
--------------------------------------------------------------------------------
/integrations/VictoriaMetrics/icon/VictoriaMetrics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/VictoriaMetrics/icon/VictoriaMetrics.png
--------------------------------------------------------------------------------
/integrations/VictoriaMetrics/markdown/README.md:
--------------------------------------------------------------------------------
1 | # VictoriaMetrics
2 |
3 | VictoriaMetrics 既可以单机部署,也可以集群方式部署。不管哪种部署方式,VictoriaMetrics 的进程都会暴露 `/metrics` 接口,通过这个接口暴露 Prometheus 协议的监控数据。
4 |
5 | ## 采集配置
6 |
7 | categraf 的 `conf/input.prometheus/prometheus.toml`。因为 VictoriaMetrics 是暴露的 Prometheus 协议的监控数据,所以使用 categraf 的 prometheus 插件即可采集。
8 |
9 | ```toml
10 | # vmstorage
11 | [[instances]]
12 | urls = [
13 | "http://127.0.0.1:8482/metrics"
14 | ]
15 | labels = {service="vmstorage"}
16 |
17 | # vmselect
18 | [[instances]]
19 | urls = [
20 | "http://127.0.0.1:8481/metrics"
21 | ]
22 |
23 | labels = {service="vmselect"}
24 |
25 | # vminsert
26 | [[instances]]
27 | urls = [
28 | "http://127.0.0.1:8480/metrics"
29 | ]
30 | labels = {service="vminsert"}
31 | ```
32 |
33 | ## 告警规则
34 |
35 | 夜莺内置了 VictoriaMetrics 的告警规则,克隆到自己的业务组下即可使用。
36 |
37 | ## 仪表盘
38 |
39 | 夜莺内置了 VictoriaMetrics 的仪表盘,克隆到自己的业务组下即可使用。
40 |
41 | 
42 |
43 |
--------------------------------------------------------------------------------
/integrations/VictoriaMetrics/markdown/alerts-vm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/VictoriaMetrics/markdown/alerts-vm.png
--------------------------------------------------------------------------------
/integrations/VictoriaMetrics/markdown/alerts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/VictoriaMetrics/markdown/alerts.png
--------------------------------------------------------------------------------
/integrations/VictoriaMetrics/markdown/dash-vm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/VictoriaMetrics/markdown/dash-vm.png
--------------------------------------------------------------------------------
/integrations/VictoriaMetrics/markdown/dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/VictoriaMetrics/markdown/dashboard.png
--------------------------------------------------------------------------------
/integrations/Whois/collect/whois/whois.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | #interval = 3600
3 |
4 | #[[instances]]
5 | ## Used to collect domain name information.
6 | #domain = "baidu.com"
7 |
8 | ## append some labels for series
9 | #labels = { region="n9e", product="test1" }
10 |
11 | ## interval = global.interval * interval_times
12 | #interval_times = 1
13 |
14 |
15 | #[[instances]]
16 | ## Used to collect domain name information.
17 | #domain = "google.com"
18 |
19 | ## append some labels for series
20 | #labels = { region="n9e", product="test2" }
21 |
22 | ## interval = global.interval * interval_times
23 | #interval_times = 1
24 |
25 |
--------------------------------------------------------------------------------
/integrations/Whois/icon/whois.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Whois/icon/whois.png
--------------------------------------------------------------------------------
/integrations/Whois/markdown/README.md:
--------------------------------------------------------------------------------
1 | # whois
2 |
3 | 域名探测插件,用于探测域名的注册时间和到期时间,值为UTC0时间戳
4 |
5 |
6 | ## Configuration
7 |
8 | 最核心的配置就是 domain 配置,配置目标地址,比如想要监控一个地址:
9 | 默认保持注释状态,注释状态下,插件默认不启用
10 |
11 | ```toml
12 | # [[instances]]
13 | ## Used to collect domain name information.
14 | # domain = "baidu.com"
15 | ```
16 | 请注意这里配置的是域名不是URL
17 |
18 | ## 指标解释
19 |
20 | whois_domain_createddate 域名创建时间戳
21 | whois_domain_updateddate 域名更新时间戳
22 | whois_domain_expirationdate 域名到期时间戳
23 |
24 | ## 注意事项
25 | 请不要将interval设置过短,会导致频繁请求timeout,没太大必要性,请尽量放长请求周期
--------------------------------------------------------------------------------
/integrations/Windows/icon/windows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Windows/icon/windows.png
--------------------------------------------------------------------------------
/integrations/Windows/markdown/README.md:
--------------------------------------------------------------------------------
1 | # Windows
2 |
3 | categraf 不但支持 linux 监控数据采集,也支持 windows 监控数据采集,而且指标命名也是一样的,这样告警规则、仪表盘其实都可以复用。不需要对 windows 做额外处理。
4 |
5 | ## 安装
6 |
7 | categraf 在 windows 下安装请参考这个 [文档](https://flashcat.cloud/docs/content/flashcat-monitor/categraf/2-installation/)。
8 |
9 | ## 仪表盘
10 |
11 | linux、windows 仪表盘其实是可以复用的,只是两种操作系统个别指标不同。比如有些指标是 linux 特有的,有些指标是 windows 特有的。如果你想要分开查看,夜莺也内置了 windows 的仪表盘,克隆到自己的业务组下即可使用。
12 |
13 | ## 告警规则
14 |
15 | 夜莺虽然也内置了 windows 的告警规则,但因为 linux、windows 大部分指标都是一样的,就不建议为 windows 单独管理一份告警规则了。
16 |
--------------------------------------------------------------------------------
/integrations/Windows/markdown/windows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/Windows/markdown/windows.png
--------------------------------------------------------------------------------
/integrations/XSKYApi/collect/xskyapi/xskyapi.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 | #
4 | [[instances]]
5 | # # append some labels for series
6 | # labels = { region="cloud", product="n9e" }
7 |
8 | # # interval = global.interval * interval_times
9 | # interval_times = 1
10 |
11 | ## must be one of oss/gfs/eus
12 | dss_type = "oss"
13 |
14 | ## URL of each server in the service's cluster
15 | servers = [
16 | #"http://x.x.x.x:xx"
17 | ]
18 |
19 | ## Set response_timeout (default 5 seconds)
20 | response_timeout = "5s"
21 |
22 | xms_auth_tokens = [
23 | #"xxxxxxxxxxxxxxx"
24 | ]
25 |
26 |
--------------------------------------------------------------------------------
/integrations/XSKYApi/icon/xsky.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/XSKYApi/icon/xsky.png
--------------------------------------------------------------------------------
/integrations/XSKYApi/markdown/README.md:
--------------------------------------------------------------------------------
1 | # XSKY Api
2 |
3 | XSKY api
4 |
5 | ## Configations
6 |
7 | ```toml
8 | # # collect interval
9 | # interval = 15
10 | #
11 | [[instances]]
12 | # # append some labels for series
13 | # labels = { region="cloud", product="n9e" }
14 |
15 | # # interval = global.interval * interval_times
16 | # interval_times = 1
17 |
18 | ## must be one of oss/gfs/eus
19 | dss_type = "oss"
20 |
21 | ## URL of each server in the service's cluster
22 | servers = [
23 | #"http://x.x.x.x:xx"
24 | ]
25 |
26 | ## Set response_timeout (default 5 seconds)
27 | response_timeout = "5s"
28 |
29 | xms_auth_tokens = [
30 | #"xxxxxxxxxxxxxxx"
31 | ]
32 |
33 |
34 | ```
--------------------------------------------------------------------------------
/integrations/ZooKeeper/collect/zookeeper/zookeeper.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | # cluster_name = "dev-zk-cluster"
6 | # addresses = "127.0.0.1:2181"
7 | # timeout = 10
8 |
9 | # important! use global unique string to specify instance
10 | # labels = { instance="n9e-10.2.3.4:2181" }
11 |
12 | ## Optional TLS Config
13 | # use_tls = false
14 | # tls_min_version = "1.2"
15 | # tls_ca = "/etc/categraf/ca.pem"
16 | # tls_cert = "/etc/categraf/cert.pem"
17 | # tls_key = "/etc/categraf/key.pem"
18 | ## Use TLS but skip chain & host verification
19 | # insecure_skip_verify = true
--------------------------------------------------------------------------------
/integrations/ZooKeeper/icon/zookeeper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/ZooKeeper/icon/zookeeper.png
--------------------------------------------------------------------------------
/integrations/ZooKeeper/markdown/README.md:
--------------------------------------------------------------------------------
1 | # zookeeper
2 |
3 | 注意: `>=3.6.0` zookeeper 版本内置 [prometheus 的支持](https://zookeeper.apache.org/doc/current/zookeeperMonitor.html),即,如果 zookeeper 启用了 prometheus,Categraf 可使用 prometheus 插件从这个 metrics 接口拉取数据即可。就无需使用 zookeeper 这个插件来采集了。
4 |
5 | ## 说明
6 |
7 | categraf zookeeper 采集插件移植于 [dabealu/zookeeper-exporter](https://github.com/dabealu/zookeeper-exporter),适用于 `<3.6.0` 版本的 zookeeper, 原理就是利用 Zookeper 提供的四字命令(The Four Letter Words)获取监控信息。
8 |
9 | 需要注意的是,在 zookeeper v3.4.10 以后添加了四字命令白名单,需要在 zookeeper 的配置文件 `zoo.cfg` 中新增白名单配置:
10 |
11 | ```
12 | 4lw.commands.whitelist=mntr,ruok
13 | ```
14 |
15 | ## 配置
16 |
17 | zookeeper 插件的配置在 `conf/input.zookeeper/zookeeper.toml` 集群中的多个实例地址请用空格分隔:
18 |
19 | ```toml
20 | [[instances]]
21 | cluster_name = "dev-zk-cluster"
22 | addresses = "127.0.0.1:2181"
23 | timeout = 10
24 | ```
25 |
26 | 如果要监控多个 zookeeper 集群,就增加 instances 即可:
27 |
28 | ```toml
29 | [[instances]]
30 | cluster_name = "dev-zk-cluster"
31 | addresses = "127.0.0.1:2181"
32 | timeout = 10
33 |
34 | [[instances]]
35 | cluster_name = "test-zk-cluster"
36 | addresses = "127.0.0.1:2181 127.0.0.1:2182 127.0.0.1:2183"
37 | timeout = 10
38 | ```
39 |
40 | ## 监控大盘和告警规则
41 |
42 | 夜莺内置了 zookeeper 的监控大盘和告警规则,克隆到自己的业务组下即可使用。虽说文件名带有 `by_exporter` 字样,没关系,可以在 categraf 中使用。
43 |
44 |
--------------------------------------------------------------------------------
/integrations/cAdvisor/collect/cadvisor/cadvisor.toml:
--------------------------------------------------------------------------------
1 | # # collect interval
2 | # interval = 15
3 |
4 | [[instances]]
5 | # url = "https://1.2.3.4:10250"
6 | # type = "kubelet"
7 | ## url = "http://1.2.3.4:8080/metrics"
8 | ## type = "cadvisor"
9 |
10 | # url_label_key = "instance"
11 | # url_label_value = "{{.Host}}"
12 | # bearer_token_string = "eyJlonglongxxxx.eyJlonglongyyyy.oQsXlonglongZZZ"
13 | ## bearer_token_file = "/path/to/token/file"
14 |
15 | # ignore_label_keys = ["id","name", "container_label*"]
16 | ## choose_label_keys = ["id"]
17 |
18 | # timeout = "3s"
19 |
20 | # use_tls = true
21 | ## tls_min_version = "1.2"
22 | ## tls_ca = "/etc/categraf/ca.pem"
23 | ## tls_cert = "/etc/categraf/cert.pem"
24 | ## tls_key = "/etc/categraf/key.pem"
25 | ## Use TLS but skip chain & host verification
26 | ## insecure_skip_verify = true
--------------------------------------------------------------------------------
/integrations/cAdvisor/icon/cadvisor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/cAdvisor/icon/cadvisor.png
--------------------------------------------------------------------------------
/integrations/vSphere/icon/vsphere.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccfos/nightingale/2b448f738cc7de374bcb6f95a18d8358857a5159/integrations/vSphere/icon/vsphere.png
--------------------------------------------------------------------------------
/memsto/memsto.go:
--------------------------------------------------------------------------------
1 | package memsto
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/toolkits/pkg/logger"
7 | )
8 |
9 | // TODO 优化 exit 处理方式
10 | func exit(code int) {
11 | logger.Close()
12 | os.Exit(code)
13 | }
14 |
--------------------------------------------------------------------------------
/memsto/stat.go:
--------------------------------------------------------------------------------
1 | package memsto
2 |
3 | import "github.com/prometheus/client_golang/prometheus"
4 |
5 | type Stats struct {
6 | GaugeCronDuration *prometheus.GaugeVec
7 | GaugeSyncNumber *prometheus.GaugeVec
8 | }
9 |
10 | func NewSyncStats() *Stats {
11 | GaugeCronDuration := prometheus.NewGaugeVec(prometheus.GaugeOpts{
12 | Namespace: "n9e",
13 | Subsystem: "cron",
14 | Name: "duration",
15 | Help: "Cron method use duration, unit: ms.",
16 | }, []string{"name"})
17 |
18 | GaugeSyncNumber := prometheus.NewGaugeVec(prometheus.GaugeOpts{
19 | Namespace: "n9e",
20 | Subsystem: "cron",
21 | Name: "sync_number",
22 | Help: "Cron sync number.",
23 | }, []string{"name"})
24 |
25 | prometheus.MustRegister(
26 | GaugeCronDuration,
27 | GaugeSyncNumber,
28 | )
29 |
30 | return &Stats{
31 | GaugeCronDuration: GaugeCronDuration,
32 | GaugeSyncNumber: GaugeSyncNumber,
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/models/board_payload.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/ccfos/nightingale/v6/pkg/ctx"
7 | )
8 |
9 | type BoardPayload struct {
10 | Id int64 `json:"id" gorm:"primaryKey"`
11 | Payload string `json:"payload"`
12 | }
13 |
14 | func (p *BoardPayload) TableName() string {
15 | return "board_payload"
16 | }
17 |
18 | func (p *BoardPayload) Update(ctx *ctx.Context, selectField interface{}, selectFields ...interface{}) error {
19 | return DB(ctx).Model(p).Select(selectField, selectFields...).Updates(p).Error
20 | }
21 |
22 | func BoardPayloadGets(ctx *ctx.Context, ids []int64) ([]*BoardPayload, error) {
23 | if len(ids) == 0 {
24 | return nil, errors.New("empty ids")
25 | }
26 |
27 | var arr []*BoardPayload
28 | err := DB(ctx).Where("id in ?", ids).Find(&arr).Error
29 | return arr, err
30 | }
31 |
32 | func BoardPayloadGet(ctx *ctx.Context, id int64) (string, error) {
33 | payloads, err := BoardPayloadGets(ctx, []int64{id})
34 | if err != nil {
35 | return "", err
36 | }
37 |
38 | if len(payloads) == 0 {
39 | return "", nil
40 | }
41 |
42 | return payloads[0].Payload, nil
43 | }
44 |
45 | func BoardPayloadSave(ctx *ctx.Context, id int64, payload string) error {
46 | var bp BoardPayload
47 | err := DB(ctx).Where("id = ?", id).Find(&bp).Error
48 | if err != nil {
49 | return err
50 | }
51 |
52 | if bp.Id > 0 {
53 | // already exists
54 | bp.Payload = payload
55 | return bp.Update(ctx, "payload")
56 | }
57 |
58 | return Insert(ctx, &BoardPayload{
59 | Id: id,
60 | Payload: payload,
61 | })
62 | }
63 |
--------------------------------------------------------------------------------
/models/builtin_cate.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "github.com/ccfos/nightingale/v6/pkg/ctx"
5 | )
6 |
7 | type BuiltinCate struct {
8 | Id int64 `json:"id" gorm:"primaryKey"`
9 | Name string `json:"name"`
10 | UserId int64 `json:"user_id"`
11 | }
12 |
13 | func (b *BuiltinCate) TableName() string {
14 | return "builtin_cate"
15 | }
16 |
17 | // 创建 builtin_cate
18 | func (b *BuiltinCate) Create(c *ctx.Context) error {
19 | return Insert(c, b)
20 | }
21 |
22 | // 删除 builtin_cate
23 | func BuiltinCateDelete(c *ctx.Context, name string, userId int64) error {
24 | return DB(c).Where("name=? and user_id=?", name, userId).Delete(&BuiltinCate{}).Error
25 | }
26 |
27 | // 根据 userId 获取 builtin_cate
28 | func BuiltinCateGetByUserId(c *ctx.Context, userId int64) (map[string]BuiltinCate, error) {
29 | var builtinCates []BuiltinCate
30 | err := DB(c).Where("user_id=?", userId).Find(&builtinCates).Error
31 | var builtinCatesMap = make(map[string]BuiltinCate)
32 | for _, builtinCate := range builtinCates {
33 | builtinCatesMap[builtinCate.Name] = builtinCate
34 | }
35 |
36 | return builtinCatesMap, err
37 | }
38 |
--------------------------------------------------------------------------------
/models/chart.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import "github.com/ccfos/nightingale/v6/pkg/ctx"
4 |
5 | type Chart struct {
6 | Id int64 `json:"id" gorm:"primaryKey"`
7 | GroupId int64 `json:"group_id"`
8 | Configs string `json:"configs"`
9 | Weight int `json:"weight"`
10 | }
11 |
12 | func (c *Chart) TableName() string {
13 | return "chart"
14 | }
15 |
16 | func ChartsOf(ctx *ctx.Context, chartGroupId int64) ([]Chart, error) {
17 | var objs []Chart
18 | err := DB(ctx).Where("group_id = ?", chartGroupId).Order("weight").Find(&objs).Error
19 | return objs, err
20 | }
21 |
22 | func (c *Chart) Add(ctx *ctx.Context) error {
23 | return Insert(ctx, c)
24 | }
25 |
26 | func (c *Chart) Update(ctx *ctx.Context, selectField interface{}, selectFields ...interface{}) error {
27 | return DB(ctx).Model(c).Select(selectField, selectFields...).Updates(c).Error
28 | }
29 |
30 | func (c *Chart) Del(ctx *ctx.Context) error {
31 | return DB(ctx).Where("id=?", c.Id).Delete(&Chart{}).Error
32 | }
33 |
--------------------------------------------------------------------------------
/models/chart_share.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import "github.com/ccfos/nightingale/v6/pkg/ctx"
4 |
5 | type ChartShare struct {
6 | Id int64 `json:"id" gorm:"primaryKey"`
7 | Cluster string `json:"cluster"`
8 | DatasourceId int64 `json:"datasource_id"`
9 | Configs string `json:"configs"`
10 | CreateBy string `json:"create_by"`
11 | CreateAt int64 `json:"create_at"`
12 | }
13 |
14 | func (cs *ChartShare) TableName() string {
15 | return "chart_share"
16 | }
17 |
18 | func (cs *ChartShare) Add(ctx *ctx.Context) error {
19 | return Insert(ctx, cs)
20 | }
21 |
22 | func ChartShareGetsByIds(ctx *ctx.Context, ids []int64) ([]ChartShare, error) {
23 | var lst []ChartShare
24 | if len(ids) == 0 {
25 | return lst, nil
26 | }
27 |
28 | err := DB(ctx).Where("id in ?", ids).Order("id").Find(&lst).Error
29 | return lst, err
30 | }
31 |
--------------------------------------------------------------------------------
/models/event_processor.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/ccfos/nightingale/v6/pkg/ctx"
8 | )
9 |
10 | type Processor interface {
11 | Init(settings interface{}) (Processor, error) // 初始化配置
12 | Process(ctx *ctx.Context, event *AlertCurEvent) *AlertCurEvent // 处理告警事件
13 | }
14 |
15 | type NewProcessorFn func(settings interface{}) (Processor, error)
16 |
17 | var processorRegister = map[string]NewProcessorFn{}
18 |
19 | func RegisterProcessor(typ string, p Processor) {
20 | if _, found := processorRegister[typ]; found {
21 | return
22 | }
23 | processorRegister[typ] = p.Init
24 | }
25 |
26 | func GetProcessorByType(typ string, settings interface{}) (Processor, error) {
27 | typ = strings.TrimSpace(typ)
28 | fn, found := processorRegister[typ]
29 | if !found {
30 | return nil, fmt.Errorf("processor type %s not found", typ)
31 | }
32 |
33 | processor, err := fn(settings)
34 | if err != nil {
35 | return nil, err
36 | }
37 |
38 | return processor, nil
39 | }
40 |
--------------------------------------------------------------------------------
/models/migrate/migrate_es_index_pattern.go:
--------------------------------------------------------------------------------
1 | package migrate
2 |
3 | import (
4 | "github.com/toolkits/pkg/logger"
5 | "gorm.io/gorm"
6 | )
7 |
8 | type EsIndexPattern struct {
9 | Id int64 `gorm:"primaryKey;type:bigint unsigned"`
10 | DatasourceId int64 `gorm:"type:bigint not null default '0';uniqueIndex:idx_ds_name"`
11 | Name string `gorm:"type:varchar(191) not null default '';uniqueIndex:idx_ds_name"`
12 | TimeField string `gorm:"type:varchar(128) not null default ''"`
13 | AllowHideSystemIndices int `gorm:"type:tinyint(1) not null default 0"`
14 | FieldsFormat string `gorm:"type:varchar(4096) not null default ''"`
15 | CreateAt int64 `gorm:"type:bigint default '0'"`
16 | CreateBy string `gorm:"type:varchar(64) default ''"`
17 | UpdateAt int64 `gorm:"type:bigint default '0'"`
18 | UpdateBy string `gorm:"type:varchar(64) default ''"`
19 | }
20 |
21 | func MigrateEsIndexPatternTable(db *gorm.DB) error {
22 | db = db.Set("gorm:table_options", "CHARSET=utf8mb4")
23 | if db.Migrator().HasTable("es_index_pattern") {
24 | return nil
25 | }
26 |
27 | err := db.Table("es_index_pattern").AutoMigrate(&EsIndexPattern{})
28 | if err != nil {
29 | logger.Errorf("failed to migrate es index pattern table: %v", err)
30 | return err
31 | }
32 |
33 | return nil
34 | }
35 |
--------------------------------------------------------------------------------
/models/migrate/migrate_test.go:
--------------------------------------------------------------------------------
1 | package migrate
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/ccfos/nightingale/v6/models"
8 | "gorm.io/driver/mysql"
9 | "gorm.io/gorm"
10 | "gorm.io/gorm/schema"
11 | )
12 |
13 | func TestInsertPermPoints(t *testing.T) {
14 | db, err := gorm.Open(mysql.Open("root:1234@tcp(127.0.0.1:3306)/n9e_v6?charset=utf8mb4&parseTime=True&loc=Local&allowNativePasswords=true"), &gorm.Config{NamingStrategy: schema.NamingStrategy{
15 | SingularTable: true,
16 | }})
17 | if err != nil {
18 | fmt.Printf("failed to connect database: %v", err)
19 | }
20 |
21 | var ops []models.RoleOperation
22 | ops = append(ops, models.RoleOperation{
23 | RoleName: "Standard",
24 | Operation: "/alert-mutes/put",
25 | })
26 |
27 | ops = append(ops, models.RoleOperation{
28 | RoleName: "Standard",
29 | Operation: "/log/index-patterns",
30 | })
31 |
32 | ops = append(ops, models.RoleOperation{
33 | RoleName: "Standard",
34 | Operation: "/help/variable-configs",
35 | })
36 |
37 | ops = append(ops, models.RoleOperation{
38 | RoleName: "Standard",
39 | Operation: "/ibex-settings",
40 | })
41 |
42 | db = db.Debug()
43 | for _, op := range ops {
44 | var count int64
45 |
46 | err := db.Raw("SELECT COUNT(*) FROM role_operation WHERE operation = ? AND role_name = ?",
47 | op.Operation, op.RoleName).Scan(&count).Error
48 | fmt.Printf("count: %d\n", count)
49 |
50 | if err != nil {
51 | fmt.Printf("check role operation exists failed, %v", err)
52 | continue
53 | }
54 |
55 | if count > 0 {
56 | continue
57 | }
58 |
59 | err = db.Create(&op).Error
60 | if err != nil {
61 | fmt.Printf("insert role operation failed, %v", err)
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/models/role_operation.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "github.com/ccfos/nightingale/v6/pkg/ctx"
5 | "github.com/toolkits/pkg/slice"
6 | )
7 |
8 | type RoleOperation struct {
9 | RoleName string
10 | Operation string
11 | }
12 |
13 | func (RoleOperation) TableName() string {
14 | return "role_operation"
15 | }
16 |
17 | func RoleHasOperation(ctx *ctx.Context, roles []string, operation string) (bool, error) {
18 | if len(roles) == 0 {
19 | return false, nil
20 | }
21 |
22 | return Exists(DB(ctx).Model(&RoleOperation{}).Where("operation = ? and role_name in ?", operation, roles))
23 | }
24 |
25 | func OperationsOfRole(ctx *ctx.Context, roles []string) ([]string, error) {
26 | session := DB(ctx).Model(&RoleOperation{}).Select("distinct(operation) as operation")
27 |
28 | if !slice.ContainsString(roles, AdminRole) {
29 | session = session.Where("role_name in ?", roles)
30 | }
31 |
32 | var ret []string
33 | err := session.Pluck("operation", &ret).Error
34 | return ret, err
35 | }
36 |
37 | func RoleOperationBind(ctx *ctx.Context, roleName string, operation []string) error {
38 | tx := DB(ctx).Begin()
39 |
40 | if err := tx.Where("role_name = ?", roleName).Delete(&RoleOperation{}).Error; err != nil {
41 | tx.Rollback()
42 | return err
43 | }
44 |
45 | if len(operation) == 0 {
46 | return tx.Commit().Error
47 | }
48 |
49 | var ops []RoleOperation
50 | for _, op := range operation {
51 | ops = append(ops, RoleOperation{
52 | RoleName: roleName,
53 | Operation: op,
54 | })
55 | }
56 |
57 | if err := tx.Create(&ops).Error; err != nil {
58 | tx.Rollback()
59 | return err
60 | }
61 |
62 | return tx.Commit().Error
63 | }
64 |
--------------------------------------------------------------------------------
/models/source_token.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/ccfos/nightingale/v6/pkg/ctx"
7 | )
8 |
9 | type SourceToken struct {
10 | Id int64 `json:"id" gorm:"primaryKey"`
11 | SourceType string `json:"source_type" gorm:"column:source_type;type:varchar(64);not null;default:''"`
12 | SourceId string `json:"source_id" gorm:"column:source_id;type:varchar(255);not null;default:''"`
13 | Token string `json:"token" gorm:"column:token;type:varchar(255);not null;default:''"`
14 | ExpireAt int64 `json:"expire_at" gorm:"type:bigint;not null;default:0"`
15 | CreateAt int64 `json:"create_at" gorm:"type:bigint;not null;default:0"`
16 | CreateBy string `json:"create_by" gorm:"type:varchar(64);not null;default:''"`
17 | }
18 |
19 | func (SourceToken) TableName() string {
20 | return "source_token"
21 | }
22 |
23 | func (st *SourceToken) Add(ctx *ctx.Context) error {
24 | return Insert(ctx, st)
25 | }
26 |
27 | // GetSourceTokenBySource 根据源类型和源ID获取源令牌
28 | func GetSourceTokenBySource(ctx *ctx.Context, sourceType, sourceId, token string) (*SourceToken, error) {
29 | var st SourceToken
30 | err := DB(ctx).Where("source_type = ? AND source_id = ? AND token = ?", sourceType, sourceId, token).First(&st).Error
31 | if err != nil {
32 | return nil, err
33 | }
34 | return &st, nil
35 | }
36 |
37 | func (st *SourceToken) IsExpired() bool {
38 | if st.ExpireAt == 0 {
39 | return false // 0 表示永不过期
40 | }
41 | return time.Now().Unix() > st.ExpireAt
42 | }
43 |
44 | func CleanupExpiredTokens(ctx *ctx.Context) (int64, error) {
45 | now := time.Now().Unix()
46 | result := DB(ctx).Where("expire_at > 0 AND expire_at < ?", now).Delete(&SourceToken{})
47 | return result.RowsAffected, result.Error
48 | }
49 |
--------------------------------------------------------------------------------
/models/sso_config.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/ccfos/nightingale/v6/pkg/ctx"
7 | )
8 |
9 | type SsoConfig struct {
10 | Id int64 `json:"id"`
11 | Name string `json:"name"`
12 | Content string `json:"content"`
13 | UpdateAt int64 `json:"update_at"`
14 | }
15 |
16 | func (b *SsoConfig) TableName() string {
17 | return "sso_config"
18 | }
19 |
20 | // get all sso_config
21 | func SsoConfigGets(c *ctx.Context) ([]SsoConfig, error) {
22 | var lst []SsoConfig
23 | err := DB(c).Find(&lst).Error
24 | return lst, err
25 | }
26 |
27 | // 创建 builtin_cate
28 | func (b *SsoConfig) Create(c *ctx.Context) error {
29 | return Insert(c, b)
30 | }
31 |
32 | func (b *SsoConfig) Update(c *ctx.Context) error {
33 | b.UpdateAt = time.Now().Unix()
34 | return DB(c).Model(b).Select("content", "update_at").Updates(b).Error
35 | }
36 |
37 | // get sso_config last update time
38 | func SsoConfigLastUpdateTime(c *ctx.Context) (int64, error) {
39 | var lastUpdateTime int64
40 | err := DB(c).Model(&SsoConfig{}).Select("max(update_at)").Row().Scan(&lastUpdateTime)
41 | return lastUpdateTime, err
42 | }
43 |
44 | // get sso_config coutn by name
45 | func SsoConfigCountByName(c *ctx.Context, name string) (int64, error) {
46 | var count int64
47 | err := DB(c).Model(&SsoConfig{}).Where("name = ?", name).Count(&count).Error
48 | return count, err
49 | }
50 |
--------------------------------------------------------------------------------
/pkg/cfg/scan.go:
--------------------------------------------------------------------------------
1 | package cfg
2 |
3 | import (
4 | "io/ioutil"
5 | )
6 |
7 | type scanner struct {
8 | data []byte
9 | err error
10 | }
11 |
12 | func NewFileScanner() *scanner {
13 | return &scanner{}
14 | }
15 |
16 | func (s *scanner) Err() error {
17 | return s.err
18 | }
19 |
20 | func (s *scanner) Data() []byte {
21 | return s.data
22 | }
23 |
24 | func (s *scanner) Read(file string) {
25 | if s.err == nil {
26 | s.data, s.err = ioutil.ReadFile(file)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/choice/choice.go:
--------------------------------------------------------------------------------
1 | // Package choice provides basic functions for working with
2 | // plugin options that must be one of several values.
3 | package choice
4 |
5 | import (
6 | "fmt"
7 | "strings"
8 | )
9 |
10 | // Contains return true if the choice in the list of choices.
11 | func Contains(choice string, choices []string) bool {
12 | for _, item := range choices {
13 | if item == choice {
14 | return true
15 | }
16 | }
17 | return false
18 | }
19 |
20 | // Contains return true if the choice in the list of choices.
21 | func ContainsPrefix(choice string, choices []string) bool {
22 | for _, item := range choices {
23 | if strings.HasPrefix(choice, item) {
24 | return true
25 | }
26 | }
27 | return false
28 | }
29 |
30 | // Check returns an error if a choice is not one of
31 | // the available choices.
32 | func Check(choice string, available []string) error {
33 | if !Contains(choice, available) {
34 | return fmt.Errorf("unknown choice %s", choice)
35 | }
36 | return nil
37 | }
38 |
39 | // CheckSlice returns an error if the choices is not a subset of
40 | // available.
41 | func CheckSlice(choices, available []string) error {
42 | for _, choice := range choices {
43 | err := Check(choice, available)
44 | if err != nil {
45 | return err
46 | }
47 | }
48 | return nil
49 | }
50 |
--------------------------------------------------------------------------------
/pkg/ctx/ctx.go:
--------------------------------------------------------------------------------
1 | package ctx
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/ccfos/nightingale/v6/conf"
7 |
8 | "gorm.io/gorm"
9 | )
10 |
11 | type Context struct {
12 | DB *gorm.DB
13 | CenterApi conf.CenterApi
14 | Ctx context.Context
15 | IsCenter bool
16 | }
17 |
18 | func NewContext(ctx context.Context, db *gorm.DB, isCenter bool, centerApis ...conf.CenterApi) *Context {
19 | var api conf.CenterApi
20 | if len(centerApis) > 0 {
21 | api = centerApis[0]
22 | }
23 |
24 | return &Context{
25 | Ctx: ctx,
26 | DB: db,
27 | CenterApi: api,
28 | IsCenter: isCenter,
29 | }
30 | }
31 |
32 | // set db to Context
33 | func (c *Context) SetDB(db *gorm.DB) {
34 | c.DB = db
35 | }
36 |
37 | // get context from Context
38 | func (c *Context) GetContext() context.Context {
39 | return c.Ctx
40 | }
41 |
42 | // get db from Context
43 | func (c *Context) GetDB() *gorm.DB {
44 | return c.DB
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/fasttime/fasttime.go:
--------------------------------------------------------------------------------
1 | package fasttime
2 |
3 | import (
4 | "sync/atomic"
5 | "time"
6 | )
7 |
8 | func init() {
9 | go func() {
10 | ticker := time.NewTicker(time.Second)
11 | defer ticker.Stop()
12 | for tm := range ticker.C {
13 | t := uint64(tm.Unix())
14 | atomic.StoreUint64(¤tTimestamp, t)
15 | }
16 | }()
17 | }
18 |
19 | var currentTimestamp = uint64(time.Now().Unix())
20 |
21 | // UnixTimestamp returns the current unix timestamp in seconds.
22 | //
23 | // It is faster than time.Now().Unix()
24 | func UnixTimestamp() uint64 {
25 | return atomic.LoadUint64(¤tTimestamp)
26 | }
27 |
28 | // UnixDate returns date from the current unix timestamp.
29 | //
30 | // The date is calculated by dividing unix timestamp by (24*3600)
31 | func UnixDate() uint64 {
32 | return UnixTimestamp() / (24 * 3600)
33 | }
34 |
35 | // UnixHour returns hour from the current unix timestamp.
36 | //
37 | // The hour is calculated by dividing unix timestamp by 3600
38 | func UnixHour() uint64 {
39 | return UnixTimestamp() / 3600
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/hash/hash.go:
--------------------------------------------------------------------------------
1 | package hash
2 |
3 | import (
4 | "sort"
5 | "strings"
6 |
7 | prommodel "github.com/prometheus/common/model"
8 | "github.com/spaolacci/murmur3"
9 | )
10 |
11 | func GetHash(m prommodel.Metric, ref string) uint64 {
12 | var str string
13 | var strs []string
14 | // get keys from m
15 | for k, _ := range m {
16 | strs = append(strs, string(k))
17 | }
18 |
19 | // sort keys use sort
20 | sort.Strings(strs)
21 |
22 | for _, k := range strs {
23 | str += "/"
24 | str += k
25 | str += "/"
26 | str += string(m[prommodel.LabelName(k)])
27 | }
28 | str += "/"
29 | str += ref
30 |
31 | return murmur3.Sum64([]byte(str))
32 | }
33 |
34 | func GetTagHash(m prommodel.Metric) uint64 {
35 | var str string
36 | var strs []string
37 | // get keys from m
38 | for k, _ := range m {
39 | if k == "__name__" {
40 | continue
41 | }
42 | strs = append(strs, string(k))
43 | }
44 |
45 | // sort keys use sort
46 | sort.Strings(strs)
47 |
48 | for _, k := range strs {
49 | str += "/"
50 | str += k
51 | str += "/"
52 | str += string(m[prommodel.LabelName(k)])
53 | }
54 |
55 | return murmur3.Sum64([]byte(str))
56 | }
57 |
58 | func GetTargetTagHash(m prommodel.Metric, target []string) uint64 {
59 | builder := strings.Builder{}
60 | for _, k := range target {
61 | builder.WriteString("/")
62 | builder.WriteString(k)
63 | builder.WriteString("/")
64 | builder.WriteString(string(m[prommodel.LabelName(k)]))
65 | }
66 | return murmur3.Sum64([]byte(builder.String()))
67 | }
68 |
--------------------------------------------------------------------------------
/pkg/hash/hash_fnv.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package hash
18 |
19 | import (
20 | "hash"
21 |
22 | "github.com/davecgh/go-spew/spew"
23 | )
24 |
25 | // DeepHashObject writes specified object to hash using the spew library
26 | // which follows pointers and prints actual values of the nested objects
27 | // ensuring the hash does not change when a pointer changes.
28 | func DeepHashObject(hasher hash.Hash, objectToWrite interface{}) {
29 | hasher.Reset()
30 | printer := spew.ConfigState{
31 | Indent: " ",
32 | SortKeys: true,
33 | DisableMethods: true,
34 | SpewKeys: true,
35 | }
36 | printer.Fprintf(hasher, "%#v", objectToWrite)
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/hash/hash_md5.go:
--------------------------------------------------------------------------------
1 | package hash
2 |
3 | import (
4 | prommodel "github.com/prometheus/common/model"
5 | "github.com/toolkits/pkg/str"
6 | )
7 |
8 | func GetHash2(m prommodel.Metric, ref string) string {
9 | var s string
10 | for k, v := range m {
11 | s += "/"
12 | s += string(k)
13 | s += "/"
14 | s += string(v)
15 | }
16 | s += "/"
17 | s += ref
18 | return str.MD5(s)
19 | }
20 |
21 | func GetTagHash2(m prommodel.Metric) string {
22 | var s string
23 | for k, v := range m {
24 | if k == "__name__" {
25 | continue
26 | }
27 |
28 | s += "/"
29 | s += string(k)
30 | s += "/"
31 | s += string(v)
32 | }
33 | return str.MD5(s)
34 | }
35 |
--------------------------------------------------------------------------------
/pkg/i18nx/i18n.go:
--------------------------------------------------------------------------------
1 | package i18nx
2 |
3 | import (
4 | "encoding/json"
5 | "path"
6 |
7 | "github.com/toolkits/pkg/file"
8 | "github.com/toolkits/pkg/i18n"
9 | "github.com/toolkits/pkg/logger"
10 | )
11 |
12 | func Init(configDir string) {
13 | filePath := path.Join(configDir, "i18n.json")
14 | m := make(map[string]map[string]string)
15 | builtInConf := make(map[string]map[string]string)
16 |
17 | var content = I18N
18 | var err error
19 | //use built-in config
20 | err = json.Unmarshal([]byte(content), &builtInConf)
21 | if err != nil {
22 | logger.Errorf("parse i18n config file %s fail: %s\n", filePath, err)
23 | return
24 | }
25 | if !file.IsExist(filePath) {
26 | m = builtInConf
27 | } else {
28 | //expand config
29 | //prioritize the settings within the expand config options in case of conflicts
30 | content, err = file.ToTrimString(filePath)
31 | if err != nil {
32 | logger.Errorf("read i18n config file %s fail: %s\n", filePath, err)
33 | return
34 | }
35 | err = json.Unmarshal([]byte(content), &m)
36 | if err != nil {
37 | logger.Errorf("parse i18n config file %s fail: %s\n", filePath, err)
38 | return
39 | }
40 | // json Example:
41 | //{
42 | // "zh": {
43 | // "username":"用户名"
44 | // },
45 | // "fr": {
46 | // "username":"nom d'utilisateur"
47 | // }
48 | //}
49 | for languageKey, languageDict := range builtInConf {
50 | if _, hasL := m[languageKey]; hasL { //languages
51 | for k, v := range languageDict {
52 | if _, has := m[languageKey][k]; !has {
53 | m[languageKey][k] = v
54 | }
55 | }
56 | } else {
57 | m[languageKey] = languageDict
58 | }
59 | }
60 | }
61 |
62 | i18n.DictRegister(m)
63 | }
64 |
--------------------------------------------------------------------------------
/pkg/logx/logx.go:
--------------------------------------------------------------------------------
1 | package logx
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/pkg/errors"
7 | "github.com/toolkits/pkg/logger"
8 | )
9 |
10 | type Config struct {
11 | Dir string
12 | Level string
13 | Output string
14 | KeepHours uint
15 | RotateNum int
16 | RotateSize uint64
17 | OutputToOneFile bool
18 | }
19 |
20 | func Init(c Config) (func(), error) {
21 | logger.SetSeverity(c.Level)
22 |
23 | if c.Output == "stderr" {
24 | logger.LogToStderr()
25 | } else if c.Output == "file" {
26 | lb, err := logger.NewFileBackend(c.Dir)
27 | if err != nil {
28 | return nil, errors.WithMessage(err, "NewFileBackend failed")
29 | }
30 |
31 | if c.KeepHours != 0 {
32 | lb.SetRotateByHour(true)
33 | lb.SetKeepHours(c.KeepHours)
34 | } else if c.RotateNum != 0 {
35 | lb.Rotate(c.RotateNum, c.RotateSize*1024*1024)
36 | } else {
37 | return nil, errors.New("KeepHours and Rotatenum both are 0")
38 | }
39 | lb.OutputToOneFile(c.OutputToOneFile)
40 |
41 | logger.SetLogging(c.Level, lb)
42 | }
43 |
44 | return func() {
45 | fmt.Println("logger exiting")
46 | logger.Close()
47 | }, nil
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/macros/macros.go:
--------------------------------------------------------------------------------
1 | package macros
2 |
3 | var Macro func(sql string, start, end int64) (string, error)
4 |
5 | func RegisterMacro(f func(sql string, start, end int64) (string, error)) {
6 | Macro = f
7 | }
8 |
9 | func MacroInVain(sql string, start, end int64) (string, error) {
10 | return sql, nil
11 | }
12 |
--------------------------------------------------------------------------------
/pkg/osx/osx.go:
--------------------------------------------------------------------------------
1 | package osx
2 |
3 | import "os"
4 |
5 | // GetEnv returns the value of an environment variable, or returns the provided fallback value
6 | func GetEnv(key, fallback string) string {
7 | if value, ok := os.LookupEnv(key); ok {
8 | return value
9 | }
10 | return fallback
11 | }
12 |
--------------------------------------------------------------------------------
/pkg/poster/post_test.go:
--------------------------------------------------------------------------------
1 | package poster
2 |
3 | import (
4 | "encoding/json"
5 | "net/http"
6 | "net/http/httptest"
7 | "testing"
8 |
9 | "github.com/ccfos/nightingale/v6/conf"
10 | "github.com/ccfos/nightingale/v6/pkg/ctx"
11 | )
12 |
13 | func TestPostByUrls(t *testing.T) {
14 |
15 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
16 | response := DataResponse[interface{}]{Dat: "", Err: ""}
17 | json.NewEncoder(w).Encode(response)
18 | }))
19 | defer server.Close()
20 |
21 | ctx := &ctx.Context{
22 | CenterApi: conf.CenterApi{
23 | Addrs: []string{server.URL},
24 | }}
25 |
26 | if err := PostByUrls(ctx, "/v1/n9e/server-heartbeat", map[string]string{"a": "aa"}); err != nil {
27 | t.Errorf("PostByUrls() error = %v ", err)
28 | }
29 | }
30 |
31 | func TestPostByUrlsWithResp(t *testing.T) {
32 |
33 | expected := int64(123)
34 |
35 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
36 | response := DataResponse[int64]{Dat: expected, Err: ""}
37 | json.NewEncoder(w).Encode(response)
38 | }))
39 | defer server.Close()
40 |
41 | ctx := &ctx.Context{
42 | CenterApi: conf.CenterApi{
43 | Addrs: []string{server.URL},
44 | }}
45 |
46 | gotT, err := PostByUrlsWithResp[int64](ctx, "/v1/n9e/event-persist", map[string]string{"b": "bb"})
47 | if err != nil {
48 | t.Errorf("PostByUrlsWithResp() error = %v", err)
49 | return
50 | }
51 | if gotT != expected {
52 | t.Errorf("PostByUrlsWithResp() gotT = %v,expected = %v", gotT, expected)
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/pkg/prom/client_option.go:
--------------------------------------------------------------------------------
1 | package prom
2 |
3 | type ClientOptions struct {
4 | Url string
5 | BasicAuthUser string
6 | BasicAuthPass string
7 | Headers []string
8 | }
9 |
--------------------------------------------------------------------------------
/pkg/slice/contains.go:
--------------------------------------------------------------------------------
1 | package slice
2 |
3 | func HaveIntersection[T comparable](slice1, slice2 []T) bool {
4 | elemMap := make(map[T]bool)
5 | for _, val := range slice1 {
6 | elemMap[val] = true
7 | }
8 |
9 | for _, val := range slice2 {
10 | if elemMap[val] {
11 | return true
12 | }
13 | }
14 | return false
15 | }
16 |
--------------------------------------------------------------------------------
/pkg/strx/verify.go:
--------------------------------------------------------------------------------
1 | package strx
2 |
3 | import (
4 | "net/http"
5 | "regexp"
6 | "strconv"
7 | "strings"
8 |
9 | "github.com/toolkits/pkg/errorx"
10 | )
11 |
12 | func IsValidURL(url string) bool {
13 | re := regexp.MustCompile(`^https?://[^\s/$.?#].[^\s]*$`)
14 | return re.MatchString(url)
15 | }
16 |
17 | func IdsInt64ForAPI(ids string, sep ...string) []int64 {
18 | if ids == "" {
19 | return []int64{}
20 | }
21 |
22 | s := ","
23 | if len(sep) > 0 {
24 | s = sep[0]
25 | }
26 |
27 | var arr []string
28 |
29 | if s == " " {
30 | arr = strings.Fields(ids)
31 | } else {
32 | arr = strings.Split(ids, s)
33 | }
34 |
35 | count := len(arr)
36 | ret := make([]int64, 0, count)
37 | for i := 0; i < count; i++ {
38 | if arr[i] != "" {
39 | id, err := strconv.ParseInt(arr[i], 10, 64)
40 | if err != nil {
41 | errorx.Bomb(http.StatusBadRequest, "cannot convert %s to int64", arr[i])
42 | }
43 |
44 | ret = append(ret, id)
45 | }
46 | }
47 |
48 | return ret
49 | }
50 |
--------------------------------------------------------------------------------
/pkg/version/version.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | import (
4 | "sync/atomic"
5 | "time"
6 |
7 | "github.com/hashicorp/go-version"
8 | "github.com/toolkits/pkg/logger"
9 | "github.com/toolkits/pkg/net/httplib"
10 | )
11 |
12 | var Version = "unknown"
13 | var GithubVersion atomic.Value
14 |
15 | func CompareVersion(v1, v2 string) (int, error) {
16 | version1, err := version.NewVersion(v1)
17 | if err != nil {
18 | return 0, err
19 | }
20 | version2, err := version.NewVersion(v2)
21 | if err != nil {
22 | return 0, err
23 | }
24 |
25 | if version1.LessThan(version2) {
26 | return -1, nil
27 | }
28 | if version1.GreaterThan(version2) {
29 | return 1, nil
30 | }
31 | return 0, nil
32 | }
33 |
34 | func GetGithubVersion() {
35 | for {
36 | req := httplib.Get("https://api.github.com/repos/ccfos/nightingale/releases/latest")
37 | var release GithubRelease
38 | err := req.ToJSON(&release)
39 | if err != nil {
40 | logger.Errorf("get github version fail: %v", err)
41 | }
42 |
43 | GithubVersion.Store(release.TagName)
44 | time.Sleep(24 * time.Hour)
45 | }
46 | }
47 |
48 | type GithubRelease struct {
49 | TagName string `json:"tag_name"`
50 | }
51 |
--------------------------------------------------------------------------------
/pushgw/router/router_target.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/ccfos/nightingale/v6/pushgw/idents"
5 | "github.com/gin-gonic/gin"
6 | "github.com/toolkits/pkg/ginx"
7 | )
8 |
9 | func (rt *Router) targetUpdate(c *gin.Context) {
10 | var f idents.TargetUpdate
11 | ginx.BindJSON(c, &f)
12 |
13 | m := make(map[string]struct{})
14 | for _, ident := range f.Lst {
15 | m[ident] = struct{}{}
16 | }
17 |
18 | rt.IdentSet.MSet(m)
19 | ginx.NewRender(c).Message(nil)
20 | }
21 |
--------------------------------------------------------------------------------
/pushgw/router/vars.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | var globalCounter uint64
4 |
--------------------------------------------------------------------------------
/pushgw/writer/json/json-iterator.go:
--------------------------------------------------------------------------------
1 | package json
2 |
3 | import (
4 | "math"
5 | "unsafe"
6 |
7 | jsoniter "github.com/json-iterator/go"
8 | )
9 |
10 | func init() {
11 | // 为了处理prom数据中的NaN值
12 | jsoniter.RegisterTypeEncoderFunc("float64", func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
13 | f := *(*float64)(ptr)
14 | if math.IsNaN(f) {
15 | stream.WriteString("null")
16 | } else {
17 | stream.WriteFloat64(f)
18 | }
19 | }, func(ptr unsafe.Pointer) bool {
20 | return true
21 | })
22 | }
23 |
24 | func MarshalWithCustomFloat(items interface{}) ([]byte, error) {
25 | var json = jsoniter.ConfigCompatibleWithStandardLibrary
26 | return json.Marshal(items)
27 | }
28 |
--------------------------------------------------------------------------------
/storage/redis_test.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/alicebob/miniredis/v2"
8 | "github.com/redis/go-redis/v9"
9 | "github.com/stretchr/testify/assert"
10 | )
11 |
12 | func TestMiniRedisMGet(t *testing.T) {
13 | s, err := miniredis.Run()
14 | if err != nil {
15 | t.Fatalf("failed to start miniredis: %v", err)
16 | }
17 | defer s.Close()
18 |
19 | rdb := redis.NewClient(&redis.Options{
20 | Addr: s.Addr(),
21 | })
22 |
23 | err = rdb.Ping(context.Background()).Err()
24 | if err != nil {
25 | t.Fatalf("failed to ping miniredis: %v", err)
26 | }
27 |
28 | mp := make(map[string]interface{})
29 | mp["key1"] = "value1"
30 | mp["key2"] = "value2"
31 | mp["key3"] = "value3"
32 |
33 | err = MSet(context.Background(), rdb, mp)
34 | if err != nil {
35 | t.Fatalf("failed to set miniredis value: %v", err)
36 | }
37 |
38 | ctx := context.Background()
39 | keys := []string{"key1", "key2", "key3", "key4"}
40 | vals := MGet(ctx, rdb, keys)
41 |
42 | expected := [][]byte{[]byte("value1"), []byte("value2"), []byte("value3")}
43 | assert.Equal(t, expected, vals)
44 | }
45 |
--------------------------------------------------------------------------------
/storage/storage.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | import (
4 | "github.com/ccfos/nightingale/v6/pkg/ormx"
5 |
6 | "gorm.io/gorm"
7 | )
8 |
9 | func New(cfg ormx.DBConfig) (*gorm.DB, error) {
10 | db, err := ormx.New(cfg)
11 | if err != nil {
12 | return nil, err
13 | }
14 |
15 | return db, nil
16 | }
17 |
--------------------------------------------------------------------------------