├── .gitignore
├── pic
├── a.png
└── b.png
├── go.mod
├── README-cn.md
├── .github
└── workflows
│ └── package.yml
├── README.md
├── main.go
├── go.sum
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 |
3 |
--------------------------------------------------------------------------------
/pic/a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/3x-ui-traffic-exporter/main/pic/a.png
--------------------------------------------------------------------------------
/pic/b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/3x-ui-traffic-exporter/main/pic/b.png
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module 3x-ui-traffic-exporter
2 |
3 | go 1.25.0
4 |
5 | require (
6 | github.com/alecthomas/kingpin/v2 v2.4.0
7 | github.com/prometheus/client_golang v1.21.1
8 | github.com/prometheus/common v0.62.0
9 | github.com/prometheus/exporter-toolkit v0.14.0
10 | modernc.org/sqlite v1.36.0
11 | )
12 |
13 | require (
14 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
15 | github.com/beorn7/perks v1.0.1 // indirect
16 | github.com/cespare/xxhash/v2 v2.3.0 // indirect
17 | github.com/coreos/go-systemd/v22 v22.5.0 // indirect
18 | github.com/dustin/go-humanize v1.0.1 // indirect
19 | github.com/google/uuid v1.6.0 // indirect
20 | github.com/jpillora/backoff v1.0.0 // indirect
21 | github.com/klauspost/compress v1.17.11 // indirect
22 | github.com/mattn/go-isatty v0.0.20 // indirect
23 | github.com/mdlayher/socket v0.4.1 // indirect
24 | github.com/mdlayher/vsock v1.2.1 // indirect
25 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
26 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
27 | github.com/ncruces/go-strftime v0.1.9 // indirect
28 | github.com/prometheus/client_model v0.6.1 // indirect
29 | github.com/prometheus/procfs v0.15.1 // indirect
30 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
31 | github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
32 | golang.org/x/crypto v0.32.0 // indirect
33 | golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect
34 | golang.org/x/net v0.33.0 // indirect
35 | golang.org/x/oauth2 v0.24.0 // indirect
36 | golang.org/x/sync v0.10.0 // indirect
37 | golang.org/x/sys v0.30.0 // indirect
38 | golang.org/x/text v0.21.0 // indirect
39 | google.golang.org/protobuf v1.36.1 // indirect
40 | gopkg.in/yaml.v2 v2.4.0 // indirect
41 | modernc.org/libc v1.61.13 // indirect
42 | modernc.org/mathutil v1.7.1 // indirect
43 | modernc.org/memory v1.8.2 // indirect
44 | )
45 |
--------------------------------------------------------------------------------
/README-cn.md:
--------------------------------------------------------------------------------
1 |
3x-ui Traffic Exporter
2 |
3 |
4 | [](https://github.com/itning/3x-ui-traffic-exporter/stargazers)
5 | [](https://github.com/itning/3x-ui-traffic-exporter/network/members)
6 | [](https://github.com/itning/3x-ui-traffic-exporter/watchers)
7 | [](https://github.com/itning?tab=followers)
8 |
9 |
10 |
11 |
12 |
13 |
14 | [](https://github.com/itning/3x-ui-traffic-exporter/issues)
15 | [](https://github.com/itning/3x-ui-traffic-exporter/blob/master/LICENSE)
16 | [](https://github.com/itning/3x-ui-traffic-exporter/commits)
17 | [](https://github.com/itning/3x-ui-traffic-exporter)
18 | [](https://github.com/itning/hit-count)
19 |
20 |
21 |
22 | ---
23 |
24 | # 介绍
25 |
26 | 功能:将3x-ui中的流量信息上报给Prometheus
27 |
28 | 实现效果:
29 |
30 | 
31 |
32 | 在3x-ui中:
33 |
34 | 
35 |
36 | # 使用
37 |
38 | ```shell
39 | ./3x-ui-traffic-exporter-linux-amd64 --web.listen-address=":9100"
40 | ```
41 |
42 | ```text
43 | # HELP email_download_bytes_total Total bytes downloaded by each email.
44 | # TYPE email_download_bytes_total counter
45 | email_download_bytes_total{email="60fvu4mn",enable="1"} 1.247432473107e+12
46 | email_download_bytes_total{email="6g0ff2mh",enable="1"} 1.4792804919e+10
47 | email_download_bytes_total{email="jk8120as",enable="1"} 2.725568336e+09
48 | email_download_bytes_total{email="rda66ai2",enable="1"} 1.78623051e+08
49 | # HELP email_upload_bytes_total Total bytes uploaded by each email.
50 | # TYPE email_upload_bytes_total counter
51 | email_upload_bytes_total{email="60fvu4mn",enable="1"} 2.24460727439e+11
52 | email_upload_bytes_total{email="6g0ff2mh",enable="1"} 1.43013856e+08
53 | email_upload_bytes_total{email="jk8120as",enable="1"} 1.33524713e+08
54 | email_upload_bytes_total{email="rda66ai2",enable="1"} 4.6806666e+07
55 | ```
56 |
57 | 默认使用3x-ui sqlite数据库位置为:`/etc/x-ui/x-ui.db`
58 |
59 | 如果不在默认位置可以通过参数修改,例如`--db-path=/home/xui.db`
60 |
61 | 支持TLS:`--web.config.file=web-config.yml`
62 |
63 | 具体配置:[exporter-toolkit web-configuration](https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md)
64 |
65 | # 感谢
66 |
67 | 
--------------------------------------------------------------------------------
/.github/workflows/package.yml:
--------------------------------------------------------------------------------
1 | name: Build Multi-Platform Binaries and Upload to Release
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | version:
7 | description: 'Version tag (e.g., v1.0.0)'
8 | required: true
9 | default: 'v1.0.0'
10 |
11 | jobs:
12 | create-release:
13 | runs-on: ubuntu-latest
14 | outputs:
15 | upload_url: ${{ steps.create_release.outputs.upload_url }}
16 | steps:
17 | - name: Create Release
18 | id: create_release
19 | uses: actions/create-release@v1
20 | env:
21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22 | with:
23 | tag_name: ${{ github.event.inputs.version }}
24 | release_name: Release ${{ github.event.inputs.version }}
25 | draft: true
26 | prerelease: false
27 |
28 | build-and-upload:
29 | runs-on: ubuntu-latest
30 | needs: create-release
31 | strategy:
32 | matrix:
33 | os: [linux, windows, darwin]
34 | arch: [amd64, arm64]
35 |
36 | steps:
37 | - name: Checkout Code
38 | uses: actions/checkout@v4
39 | with:
40 | fetch-depth: 0 # 获取所有 git 历史用于版本信息
41 |
42 | - name: Set up Go
43 | uses: actions/setup-go@v5
44 | with:
45 | go-version: '1.25.0'
46 |
47 | - name: Get Git Info
48 | id: git
49 | run: |
50 | echo "revision=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
51 | echo "branch=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_OUTPUT
52 | echo "build_date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $GITHUB_OUTPUT
53 |
54 | - name: Build Binary
55 | id: build
56 | run: |
57 | export GOOS=${{ matrix.os }}
58 | export GOARCH=${{ matrix.arch }}
59 | # Determine the output file name with .exe extension for Windows
60 | OUTPUT_FILE="3x-ui-traffic-exporter-${GOOS}-${GOARCH}${{ matrix.os == 'windows' && '.exe' || '' }}"
61 | echo "Building for ${GOOS}/${GOARCH}..."
62 |
63 | # 设置版本信息 ldflags
64 | LDFLAGS="-X 'github.com/prometheus/common/version.Version=${{ github.event.inputs.version }}' \
65 | -X 'github.com/prometheus/common/version.Revision=${{ steps.git.outputs.revision }}' \
66 | -X 'github.com/prometheus/common/version.Branch=${{ steps.git.outputs.branch }}' \
67 | -X 'github.com/prometheus/common/version.BuildUser=github-actions' \
68 | -X 'github.com/prometheus/common/version.BuildDate=${{ steps.git.outputs.build_date }}'"
69 |
70 | go build -ldflags "$LDFLAGS" -o $OUTPUT_FILE main.go
71 | echo "output_file=$OUTPUT_FILE" >> $GITHUB_ENV
72 |
73 | - name: Upload Release Asset
74 | uses: actions/upload-release-asset@v1
75 | env:
76 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
77 | with:
78 | upload_url: ${{ needs.create-release.outputs.upload_url }}
79 | asset_path: ${{ env.output_file }}
80 | asset_name: ${{ env.output_file }}
81 | asset_content_type: application/octet-stream
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 3x-ui Traffic Exporter
2 |
3 |
4 | [](https://github.com/itning/3x-ui-traffic-exporter/stargazers)
5 | [](https://github.com/itning/3x-ui-traffic-exporter/network/members)
6 | [](https://github.com/itning/3x-ui-traffic-exporter/watchers)
7 | [](https://github.com/itning?tab=followers)
8 |
9 |
10 |
11 |
12 |
13 |
14 | [](https://github.com/itning/3x-ui-traffic-exporter/issues)
15 | [](https://github.com/itning/3x-ui-traffic-exporter/blob/master/LICENSE)
16 | [](https://github.com/itning/3x-ui-traffic-exporter/commits)
17 | [](https://github.com/itning/3x-ui-traffic-exporter)
18 | [](https://github.com/itning/hit-count)
19 |
20 |
21 |
22 | ---
23 |
24 | [中文](https://github.com/itning/3x-ui-traffic-exporter/blob/main/README-cn.md)
25 |
26 | # Introduction
27 |
28 | Function: Report traffic information from 3x-ui to Prometheus.
29 |
30 | Implementation effect:
31 |
32 | 
33 |
34 | In 3x-ui:
35 |
36 | 
37 |
38 | # Usage
39 |
40 | ```shell
41 | ./3x-ui-traffic-exporter-linux-amd64 --web.listen-address=":9100"
42 | ```
43 |
44 | ```text
45 | # HELP email_download_bytes_total Total bytes downloaded by each email.
46 | # TYPE email_download_bytes_total counter
47 | email_download_bytes_total{email="60fvu4mn",enable="1"} 1.247432473107e+12
48 | email_download_bytes_total{email="6g0ff2mh",enable="1"} 1.4792804919e+10
49 | email_download_bytes_total{email="jk8120as",enable="1"} 2.725568336e+09
50 | email_download_bytes_total{email="rda66ai2",enable="1"} 1.78623051e+08
51 | # HELP email_upload_bytes_total Total bytes uploaded by each email.
52 | # TYPE email_upload_bytes_total counter
53 | email_upload_bytes_total{email="60fvu4mn",enable="1"} 2.24460727439e+11
54 | email_upload_bytes_total{email="6g0ff2mh",enable="1"} 1.43013856e+08
55 | email_upload_bytes_total{email="jk8120as",enable="1"} 1.33524713e+08
56 | email_upload_bytes_total{email="rda66ai2",enable="1"} 4.6806666e+07
57 | ```
58 |
59 | The default location for the 3x-ui SQLite database is: `/etc/x-ui/x-ui.db`.
60 |
61 | If not in the default location, it can be modified via a parameter, for example: `--db-path=/home/xui.db`.
62 |
63 | Supports TLS: `--web.config.file=web-config.yml`.
64 |
65 | For specific configuration details: [exporter-toolkit web-configuration](https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md).
66 |
67 | # Acknowledgments
68 |
69 | 
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "database/sql"
6 | "log"
7 | "net/http"
8 | "os"
9 | "runtime"
10 |
11 | "github.com/alecthomas/kingpin/v2"
12 | "github.com/prometheus/client_golang/prometheus"
13 | "github.com/prometheus/client_golang/prometheus/promhttp"
14 | "github.com/prometheus/common/promslog"
15 | "github.com/prometheus/common/promslog/flag"
16 | "github.com/prometheus/common/version"
17 | "github.com/prometheus/exporter-toolkit/web"
18 | "github.com/prometheus/exporter-toolkit/web/kingpinflag"
19 | _ "modernc.org/sqlite"
20 | )
21 |
22 | const (
23 | namespace = "email"
24 | subsystem = "traffic"
25 | )
26 |
27 | var (
28 | upBytesDesc = prometheus.NewDesc(
29 | prometheus.BuildFQName(namespace, subsystem, "upload_bytes_total"),
30 | "Total bytes uploaded by each email.",
31 | []string{"email", "enable"}, nil,
32 | )
33 |
34 | downBytesDesc = prometheus.NewDesc(
35 | prometheus.BuildFQName(namespace, subsystem, "download_bytes_total"),
36 | "Total bytes downloaded by each email.",
37 | []string{"email", "enable"}, nil,
38 | )
39 | )
40 |
41 | type EmailTrafficCollector struct {
42 | db *sql.DB
43 | }
44 |
45 | func (c *EmailTrafficCollector) Describe(ch chan<- *prometheus.Desc) {
46 | ch <- upBytesDesc
47 | ch <- downBytesDesc
48 | }
49 |
50 | func (c *EmailTrafficCollector) Collect(ch chan<- prometheus.Metric) {
51 | rows, err := c.db.Query("SELECT email, up, down, enable FROM client_traffics")
52 | if err != nil {
53 | log.Printf("Error querying database: %v", err)
54 | return
55 | }
56 | defer rows.Close()
57 |
58 | for rows.Next() {
59 | var email string
60 | var up, down int64
61 | var enable bool
62 |
63 | if err := rows.Scan(&email, &up, &down, &enable); err != nil {
64 | log.Printf("Error scanning row: %v", err)
65 | continue
66 | }
67 |
68 | enableStr := "false"
69 | if enable {
70 | enableStr = "true"
71 | }
72 |
73 | ch <- prometheus.MustNewConstMetric(upBytesDesc, prometheus.CounterValue, float64(up), email, enableStr)
74 | ch <- prometheus.MustNewConstMetric(downBytesDesc, prometheus.CounterValue, float64(down), email, enableStr)
75 | }
76 |
77 | if err := rows.Err(); err != nil {
78 | log.Printf("Error iterating rows: %v", err)
79 | }
80 | }
81 |
82 | func IsSQLiteFile(filePath string) (bool, error) {
83 | signature := []byte("SQLite format 3\x00")
84 | buf := make([]byte, len(signature))
85 | file, err := os.Open(filePath)
86 | if err != nil {
87 | return false, err
88 | }
89 | defer file.Close()
90 | _, err = file.ReadAt(buf, 0)
91 | if err != nil {
92 | return false, err
93 | }
94 | return bytes.Equal(buf, signature), nil
95 | }
96 |
97 | func main() {
98 | var (
99 | metricsPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String()
100 | maxProcs = kingpin.Flag("runtime.gomaxprocs", "The target number of CPUs Go will run on (GOMAXPROCS)").Envar("GOMAXPROCS").Default("1").Int()
101 | dbPath = kingpin.Flag("db-path", "Path to the SQLite database").Default("/etc/x-ui/x-ui.db").String()
102 | toolkitFlags = kingpinflag.AddFlags(kingpin.CommandLine, ":9100")
103 | )
104 |
105 | promslogConfig := &promslog.Config{}
106 | flag.AddFlags(kingpin.CommandLine, promslogConfig)
107 | kingpin.Version(version.Print("3x-ui-traffic-exporter"))
108 | kingpin.CommandLine.UsageWriter(os.Stdout)
109 | kingpin.HelpFlag.Short('h')
110 | kingpin.Parse()
111 | logger := promslog.New(promslogConfig)
112 |
113 | logger.Info("Starting 3x-ui-traffic-exporter", "version", version.Info())
114 | logger.Info("Build context", "build_context", version.BuildContext())
115 |
116 | isSQLite, err := IsSQLiteFile(*dbPath)
117 | if err != nil {
118 | logger.Error("Failed to check SQLite file", "error", err)
119 | return
120 | }
121 | if !isSQLite {
122 | logger.Error("Not a valid SQLite file", "path", *dbPath)
123 | return
124 | }
125 |
126 | db, err := sql.Open("sqlite", *dbPath)
127 | if err != nil {
128 | logger.Error("Failed to open database", "error", err)
129 | return
130 | }
131 | defer db.Close()
132 |
133 | runtime.GOMAXPROCS(*maxProcs)
134 | logger.Debug("Go MAXPROCS", "procs", runtime.GOMAXPROCS(0))
135 |
136 | collector := &EmailTrafficCollector{db: db}
137 | prometheus.MustRegister(collector)
138 |
139 | http.Handle(*metricsPath, promhttp.Handler())
140 | if *metricsPath != "/" {
141 | landingConfig := web.LandingConfig{
142 | Name: "3x-ui Traffic Exporter",
143 | Description: "Exports email traffic statistics from 3x-ui SQLite DB",
144 | Version: version.Info(),
145 | Links: []web.LandingLinks{
146 | {
147 | Address: *metricsPath,
148 | Text: "Metrics",
149 | },
150 | },
151 | }
152 | landingPage, err := web.NewLandingPage(landingConfig)
153 | if err != nil {
154 | logger.Error("Failed to create landing page", "error", err)
155 | os.Exit(1)
156 | }
157 | http.Handle("/", landingPage)
158 | }
159 |
160 | server := &http.Server{}
161 | if err := web.ListenAndServe(server, toolkitFlags, logger); err != nil {
162 | logger.Error("Server failed to start", "error", err)
163 | os.Exit(1)
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
2 | github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
3 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
4 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
5 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
6 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
7 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
8 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
9 | github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
10 | github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
11 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
13 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
14 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
15 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
16 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
17 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
18 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
19 | github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
20 | github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
21 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
22 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
23 | github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
24 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
25 | github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
26 | github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
27 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
28 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
29 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
30 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
31 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
32 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
33 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
34 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
35 | github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
36 | github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
37 | github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
38 | github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
39 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
40 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
41 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
42 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
43 | github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
44 | github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
45 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
46 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
47 | github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
48 | github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
49 | github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
50 | github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
51 | github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
52 | github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
53 | github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg=
54 | github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA=
55 | github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
56 | github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
57 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
58 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
59 | github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
60 | github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
61 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
62 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
63 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
64 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
65 | github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
66 | github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
67 | golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
68 | golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
69 | golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo=
70 | golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
71 | golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
72 | golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
73 | golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
74 | golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
75 | golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
76 | golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
77 | golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
78 | golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
79 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
80 | golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
81 | golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
82 | golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
83 | golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
84 | golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
85 | golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
86 | google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
87 | google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
88 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
89 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
90 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
91 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
92 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
93 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
94 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
95 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
96 | modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
97 | modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
98 | modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=
99 | modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo=
100 | modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
101 | modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
102 | modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
103 | modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
104 | modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
105 | modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
106 | modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
107 | modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
108 | modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
109 | modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU=
110 | modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
111 | modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
112 | modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
113 | modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
114 | modernc.org/sqlite v1.36.0 h1:EQXNRn4nIS+gfsKeUTymHIz1waxuv5BzU7558dHSfH8=
115 | modernc.org/sqlite v1.36.0/go.mod h1:7MPwH7Z6bREicF9ZVUR78P1IKuxfZ8mRIDHD0iD+8TU=
116 | modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
117 | modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
118 | modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
119 | modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
120 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------