├── .drone.yml
├── .env.example
├── .gitignore
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cmd
└── transmission-exporter
│ ├── main.go
│ ├── session_collector.go
│ ├── session_stats_collector.go
│ └── torrent_collector.go
├── dashboards
├── dashboard.json
├── jsonnetfile.json
├── transmission.json
├── transmission.jsonnet
└── transmission2024.json
├── examples
├── docker-compose.yml
├── kubernetes
│ └── transmission.yml
└── prometheus
│ └── prometheus.yml
├── go.mod
├── go.sum
├── session.go
├── session_stats.go
├── torrent.go
└── transmission.go
/.drone.yml:
--------------------------------------------------------------------------------
1 | ---
2 | kind: pipeline
3 | name: default
4 |
5 | platform:
6 | os: linux
7 | arch: amd64
8 |
9 | workspace:
10 | base: /go
11 | path: src/github.com/metalmatze/transmission-exporter
12 |
13 | steps:
14 | - name: build
15 | pull: default
16 | image: golang:1.13-alpine
17 | environment:
18 | GOPROXY: https://proxy.golang.org
19 | commands:
20 | - apk add -U git make
21 | - make fmt
22 | - make vet
23 | - make lint
24 | - make build
25 |
26 | - name: docker-master
27 | pull: always
28 | image: plugins/docker
29 | settings:
30 | username:
31 | from_secret: docker_username
32 | password:
33 | from_secret: docker_password
34 | repo: metalmatze/transmission-exporter
35 | tags:
36 | - master
37 | when:
38 | branch:
39 | - master
40 | event:
41 | - push
42 |
43 | - name: docker-tag
44 | pull: always
45 | image: plugins/docker
46 | settings:
47 | username:
48 | from_secret: docker_username
49 | password:
50 | from_secret: docker_password
51 | repo: metalmatze/transmission-exporter
52 | tag:
53 | - 0.3
54 | - 0.3.0
55 | - latest
56 | when:
57 | event:
58 | - tag
59 |
60 | ...
61 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | TRANSMISSION_ADDR=http://localhost:9091
2 | TRANSMISSION_PASSWORD=
3 | TRANSMISSION_USERNAME=
4 | WEB_ADDR=:19091
5 | WEB_PATH=/metrics
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.env
2 | /dashboards/jsonnetfile.lock.json
3 | /dashboards/vendor/
4 | /transmission-exporter
5 |
6 | *.o
7 | *.a
8 | *.so
9 | _obj
10 | _test
11 | *.[568vq]
12 | [568vq].out
13 | *.cgo1.go
14 | *.cgo2.c
15 | _cgo_defun.c
16 | _cgo_gotypes.go
17 | _cgo_export.*
18 | _testmain.go
19 | *.exe
20 | *.test
21 | *.prof
22 | *.out
23 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:latest
2 | RUN apk add --update ca-certificates
3 |
4 | ADD ./transmission-exporter /usr/bin/transmission-exporter
5 |
6 | EXPOSE 19091
7 |
8 | ENTRYPOINT ["/usr/bin/transmission-exporter"]
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Matthias Loibl
4 | Copyright (c) 2014 Long Nguyen, Tobias Blom
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | GO ?= GO111MODULE=on CGO_ENABLED=0 go
2 | PACKAGES = $(shell go list ./... | grep -v /vendor/)
3 |
4 | .PHONY: all
5 | all: install
6 |
7 | .PHONY: clean
8 | clean:
9 | $(GO) clean -i ./...
10 |
11 | .PHONY: install
12 | install:
13 | $(GO) install -v ./cmd/transmission-exporter
14 |
15 | .PHONY: build
16 | build:
17 | $(GO) build -v ./cmd/transmission-exporter
18 |
19 | .PHONY: fmt
20 | fmt:
21 | $(GO) fmt $(PACKAGES)
22 |
23 | .PHONY: vet
24 | vet:
25 | $(GO) vet $(PACKAGES)
26 |
27 | .PHONY: lint
28 | lint:
29 | @which golint > /dev/null; if [ $$? -ne 0 ]; then \
30 | $(GO) get -u golang.org/x/lint/golint; \
31 | fi
32 | for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
33 |
34 | .PHONY: dashboards
35 | dashboards:
36 | jsonnet fmt -i dashboards/transmission.jsonnet
37 | jsonnet -J dashboards/vendor -m dashboards -e "(import 'dashboards/transmission.jsonnet').grafanaDashboards"
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Transmission Exporter for Prometheus [](https://cloud.drone.io/metalmatze/transmission-exporter)
2 |
3 | [](https://hub.docker.com/r/metalmatze/transmission-exporter)
4 | [](https://goreportcard.com/report/github.com/metalmatze/transmission-exporter)
5 |
6 | Prometheus exporter for [Transmission](https://transmissionbt.com/) metrics, written in Go.
7 |
8 | # LOOKING FOR MAINTAINERS
9 | I don't use this exporter anymore and I'd be happy if others would want to take over and maintain it in the future!
10 | Write me a DM via [Twitter](https://twitter.com/metalmatze)!
11 |
12 | ### Installation
13 |
14 | $ go get github.com/metalmatze/transmission-exporter
15 |
16 | ### Configuration
17 |
18 | ENV Variable | Description
19 | |----------|-----|
20 | | WEB_PATH | Path for metrics, default: `/metrics` |
21 | | WEB_ADDR | Address for this exporter to run, default: `:19091` |
22 | | TRANSMISSION_ADDR | Transmission address to connect with, default: `http://localhost:9091` |
23 | | TRANSMISSION_USERNAME | Transmission username, no default |
24 | | TRANSMISSION_PASSWORD | Transmission password, no default |
25 |
26 | ### Docker
27 |
28 | docker pull metalmatze/transmission-exporter
29 | docker run -d -p 19091:19091 metalmatze/transmission-exporter
30 |
31 | ### Kubernetes (Prometheus)
32 |
33 | A sample kubernetes manifest is available in [example/kubernetes](https://github.com/metalmatze/transmission-exporter/blob/master/examples/kubernetes/docker-compose.yml)
34 |
35 | Please run: `kubectl apply -f examples/kubernetes/transmission.yml`
36 |
37 | You should:
38 | * Attach the config and downloads volume
39 | * Configure the password for the exporter
40 |
41 | Your prometheus instance will start scraping the metrics automatically. (if configured with annotation based discovery). [more info](https://www.weave.works/docs/cloud/latest/tasks/monitor/configuration-k8s/)
42 |
43 | ### Docker Compose
44 |
45 | Example `docker-compose.yml` with Transmission also running in docker.
46 |
47 | transmission:
48 | image: linuxserver/transmission
49 | restart: always
50 | ports:
51 | - "127.0.0.1:9091:9091"
52 | - "51413:51413"
53 | - "51413:51413/udp"
54 | transmission-exporter:
55 | image: metalmatze/transmission-exporter
56 | restart: always
57 | links:
58 | - transmission
59 | ports:
60 | - "127.0.0.1:19091:19091"
61 | environment:
62 | TRANSMISSION_ADDR: http://transmission:9091
63 |
64 | ### Development
65 |
66 | make
67 |
68 | For development we encourage you to use `make install` instead, it's faster.
69 |
70 | Now simply copy the `.env.example` to `.env`, like `cp .env.example .env` and set your preferences.
71 | Now you're good to go.
72 |
73 | ### Original authors of the Transmission package
74 | Tobias Blom (https://github.com/tubbebubbe/transmission)
75 | Long Nguyen (https://github.com/longnguyen11288/go-transmission)
76 |
--------------------------------------------------------------------------------
/cmd/transmission-exporter/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | arg "github.com/alexflint/go-arg"
8 | "github.com/joho/godotenv"
9 | transmission "github.com/metalmatze/transmission-exporter"
10 | "github.com/prometheus/client_golang/prometheus"
11 | )
12 |
13 | // Config gets its content from env and passes it on to different packages
14 | type Config struct {
15 | TransmissionAddr string `arg:"env:TRANSMISSION_ADDR"`
16 | TransmissionPassword string `arg:"env:TRANSMISSION_PASSWORD"`
17 | TransmissionUsername string `arg:"env:TRANSMISSION_USERNAME"`
18 | WebAddr string `arg:"env:WEB_ADDR"`
19 | WebPath string `arg:"env:WEB_PATH"`
20 | }
21 |
22 | func main() {
23 | log.Println("starting transmission-exporter")
24 |
25 | err := godotenv.Load()
26 | if err != nil {
27 | log.Println("no .env present")
28 | }
29 |
30 | c := Config{
31 | WebPath: "/metrics",
32 | WebAddr: ":19091",
33 | TransmissionAddr: "http://localhost:9091",
34 | }
35 |
36 | arg.MustParse(&c)
37 |
38 | var user *transmission.User
39 | if c.TransmissionUsername != "" && c.TransmissionPassword != "" {
40 | user = &transmission.User{
41 | Username: c.TransmissionUsername,
42 | Password: c.TransmissionPassword,
43 | }
44 | }
45 |
46 | client := transmission.New(c.TransmissionAddr, user)
47 |
48 | prometheus.MustRegister(NewTorrentCollector(client))
49 | prometheus.MustRegister(NewSessionCollector(client))
50 | prometheus.MustRegister(NewSessionStatsCollector(client))
51 |
52 | http.Handle(c.WebPath, prometheus.Handler())
53 |
54 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
55 | w.Write([]byte(`
56 |
Node Exporter
57 |
58 | Transmission Exporter
59 | Metrics
60 |
61 | `))
62 | })
63 |
64 | log.Fatal(http.ListenAndServe(c.WebAddr, nil))
65 | }
66 |
67 | func boolToString(true bool) string {
68 | if true {
69 | return "1"
70 | }
71 | return "0"
72 | }
73 |
--------------------------------------------------------------------------------
/cmd/transmission-exporter/session_collector.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 |
6 | "github.com/metalmatze/transmission-exporter"
7 | "github.com/prometheus/client_golang/prometheus"
8 | )
9 |
10 | // SessionCollector exposes session metrics
11 | type SessionCollector struct {
12 | client *transmission.Client
13 |
14 | AltSpeedDown *prometheus.Desc
15 | AltSpeedUp *prometheus.Desc
16 | CacheSize *prometheus.Desc
17 | FreeSpace *prometheus.Desc
18 | QueueDown *prometheus.Desc
19 | QueueUp *prometheus.Desc
20 | PeerLimitGlobal *prometheus.Desc
21 | PeerLimitTorrent *prometheus.Desc
22 | SeedRatioLimit *prometheus.Desc
23 | SpeedLimitDown *prometheus.Desc
24 | SpeedLimitUp *prometheus.Desc
25 | Version *prometheus.Desc
26 | }
27 |
28 | // NewSessionCollector takes a transmission.Client and returns a SessionCollector
29 | func NewSessionCollector(client *transmission.Client) *SessionCollector {
30 | return &SessionCollector{
31 | client: client,
32 |
33 | AltSpeedDown: prometheus.NewDesc(
34 | namespace+"alt_speed_down",
35 | "Alternative max global download speed",
36 | []string{"enabled"},
37 | nil,
38 | ),
39 | AltSpeedUp: prometheus.NewDesc(
40 | namespace+"alt_speed_up",
41 | "Alternative max global upload speed",
42 | []string{"enabled"},
43 | nil,
44 | ),
45 | CacheSize: prometheus.NewDesc(
46 | namespace+"cache_size_bytes",
47 | "Maximum size of the disk cache",
48 | nil,
49 | nil,
50 | ),
51 | FreeSpace: prometheus.NewDesc(
52 | namespace+"free_space",
53 | "Free space left on device to download to",
54 | []string{"download_dir", "incomplete_dir"},
55 | nil,
56 | ),
57 | QueueDown: prometheus.NewDesc(
58 | namespace+"queue_down",
59 | "Max number of torrents to download at once",
60 | []string{"enabled"},
61 | nil,
62 | ),
63 | QueueUp: prometheus.NewDesc(
64 | namespace+"queue_up",
65 | "Max number of torrents to upload at once",
66 | []string{"enabled"},
67 | nil,
68 | ),
69 | PeerLimitGlobal: prometheus.NewDesc(
70 | namespace+"global_peer_limit",
71 | "Maximum global number of peers",
72 | nil,
73 | nil,
74 | ),
75 | PeerLimitTorrent: prometheus.NewDesc(
76 | namespace+"torrent_peer_limit",
77 | "Maximum number of peers for a single torrent",
78 | nil,
79 | nil,
80 | ),
81 | SeedRatioLimit: prometheus.NewDesc(
82 | namespace+"seed_ratio_limit",
83 | "The default seed ratio for torrents to use",
84 | []string{"enabled"},
85 | nil,
86 | ),
87 | SpeedLimitDown: prometheus.NewDesc(
88 | namespace+"speed_limit_down_bytes",
89 | "Max global download speed",
90 | []string{"enabled"},
91 | nil,
92 | ),
93 | SpeedLimitUp: prometheus.NewDesc(
94 | namespace+"speed_limit_up_bytes",
95 | "Max global upload speed",
96 | []string{"enabled"},
97 | nil,
98 | ),
99 | Version: prometheus.NewDesc(
100 | namespace+"version",
101 | "Transmission version as label",
102 | []string{"version"},
103 | nil,
104 | ),
105 | }
106 | }
107 |
108 | // Describe implements the prometheus.Collector interface
109 | func (sc *SessionCollector) Describe(ch chan<- *prometheus.Desc) {
110 | ch <- sc.AltSpeedDown
111 | ch <- sc.AltSpeedUp
112 | ch <- sc.CacheSize
113 | ch <- sc.FreeSpace
114 | ch <- sc.QueueDown
115 | ch <- sc.QueueUp
116 | ch <- sc.PeerLimitGlobal
117 | ch <- sc.PeerLimitTorrent
118 | ch <- sc.SeedRatioLimit
119 | ch <- sc.SpeedLimitDown
120 | ch <- sc.SpeedLimitUp
121 | ch <- sc.Version
122 | }
123 |
124 | // Collect implements the prometheus.Collector interface
125 | func (sc *SessionCollector) Collect(ch chan<- prometheus.Metric) {
126 | session, err := sc.client.GetSession()
127 | if err != nil {
128 | log.Printf("failed to get session: %v", err)
129 | return
130 | }
131 |
132 | ch <- prometheus.MustNewConstMetric(
133 | sc.AltSpeedDown,
134 | prometheus.GaugeValue,
135 | float64(session.AltSpeedDown),
136 | boolToString(session.AltSpeedEnabled),
137 | )
138 | ch <- prometheus.MustNewConstMetric(
139 | sc.AltSpeedUp,
140 | prometheus.GaugeValue,
141 | float64(session.AltSpeedUp),
142 | boolToString(session.AltSpeedEnabled),
143 | )
144 | ch <- prometheus.MustNewConstMetric(
145 | sc.CacheSize,
146 | prometheus.GaugeValue,
147 | float64(session.CacheSizeMB*1024*1024),
148 | )
149 | ch <- prometheus.MustNewConstMetric(
150 | sc.FreeSpace,
151 | prometheus.GaugeValue,
152 | float64(session.DownloadDirFreeSpace),
153 | session.DownloadDir, session.IncompleteDir,
154 | )
155 | ch <- prometheus.MustNewConstMetric(
156 | sc.QueueDown,
157 | prometheus.GaugeValue,
158 | float64(session.DownloadQueueSize),
159 | boolToString(session.DownloadQueueEnabled),
160 | )
161 | ch <- prometheus.MustNewConstMetric(
162 | sc.QueueUp,
163 | prometheus.GaugeValue,
164 | float64(session.SeedQueueSize),
165 | boolToString(session.SeedQueueEnabled),
166 | )
167 | ch <- prometheus.MustNewConstMetric(
168 | sc.PeerLimitGlobal,
169 | prometheus.GaugeValue,
170 | float64(session.PeerLimitGlobal),
171 | )
172 | ch <- prometheus.MustNewConstMetric(
173 | sc.PeerLimitTorrent,
174 | prometheus.GaugeValue,
175 | float64(session.PeerLimitPerTorrent),
176 | )
177 | ch <- prometheus.MustNewConstMetric(
178 | sc.SeedRatioLimit,
179 | prometheus.GaugeValue,
180 | float64(session.SeedRatioLimit),
181 | boolToString(session.SeedRatioLimited),
182 | )
183 | ch <- prometheus.MustNewConstMetric(
184 | sc.SpeedLimitDown,
185 | prometheus.GaugeValue,
186 | float64(session.SpeedLimitDown),
187 | boolToString(session.SpeedLimitDownEnabled),
188 | )
189 | ch <- prometheus.MustNewConstMetric(
190 | sc.SpeedLimitUp,
191 | prometheus.GaugeValue,
192 | float64(session.SpeedLimitUp),
193 | boolToString(session.SpeedLimitUpEnabled),
194 | )
195 | ch <- prometheus.MustNewConstMetric(
196 | sc.Version,
197 | prometheus.GaugeValue,
198 | float64(1),
199 | session.Version,
200 | )
201 | }
202 |
--------------------------------------------------------------------------------
/cmd/transmission-exporter/session_stats_collector.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "time"
6 |
7 | "github.com/metalmatze/transmission-exporter"
8 | "github.com/prometheus/client_golang/prometheus"
9 | )
10 |
11 | // SessionStatsCollector exposes SessionStats as metrics
12 | type SessionStatsCollector struct {
13 | client *transmission.Client
14 |
15 | DownloadSpeed *prometheus.Desc
16 | UploadSpeed *prometheus.Desc
17 | TorrentsTotal *prometheus.Desc
18 | TorrentsActive *prometheus.Desc
19 | TorrentsPaused *prometheus.Desc
20 |
21 | Downloaded *prometheus.Desc
22 | Uploaded *prometheus.Desc
23 | FilesAdded *prometheus.Desc
24 | ActiveTime *prometheus.Desc
25 | SessionCount *prometheus.Desc
26 | }
27 |
28 | // NewSessionStatsCollector takes a transmission.Client and returns a SessionStatsCollector
29 | func NewSessionStatsCollector(client *transmission.Client) *SessionStatsCollector {
30 | const collectorNamespace = "session_stats_"
31 |
32 | return &SessionStatsCollector{
33 | client: client,
34 |
35 | DownloadSpeed: prometheus.NewDesc(
36 | namespace+collectorNamespace+"download_speed_bytes",
37 | "Current download speed in bytes",
38 | nil,
39 | nil,
40 | ),
41 | UploadSpeed: prometheus.NewDesc(
42 | namespace+collectorNamespace+"upload_speed_bytes",
43 | "Current download speed in bytes",
44 | nil,
45 | nil,
46 | ),
47 | TorrentsTotal: prometheus.NewDesc(
48 | namespace+collectorNamespace+"torrents_total",
49 | "The total number of torrents",
50 | nil,
51 | nil,
52 | ),
53 | TorrentsActive: prometheus.NewDesc(
54 | namespace+collectorNamespace+"torrents_active",
55 | "The number of active torrents",
56 | nil,
57 | nil,
58 | ),
59 | TorrentsPaused: prometheus.NewDesc(
60 | namespace+collectorNamespace+"torrents_paused",
61 | "The number of paused torrents",
62 | nil,
63 | nil,
64 | ),
65 |
66 | Downloaded: prometheus.NewDesc(
67 | namespace+collectorNamespace+"downloaded_bytes",
68 | "The number of downloaded bytes",
69 | []string{"type"},
70 | nil,
71 | ),
72 | Uploaded: prometheus.NewDesc(
73 | namespace+collectorNamespace+"uploaded_bytes",
74 | "The number of uploaded bytes",
75 | []string{"type"},
76 | nil,
77 | ),
78 | FilesAdded: prometheus.NewDesc(
79 | namespace+collectorNamespace+"files_added",
80 | "The number of files added",
81 | []string{"type"},
82 | nil,
83 | ),
84 | ActiveTime: prometheus.NewDesc(
85 | namespace+collectorNamespace+"active",
86 | "The time transmission is active since",
87 | []string{"type"},
88 | nil,
89 | ),
90 | SessionCount: prometheus.NewDesc(
91 | namespace+collectorNamespace+"sessions",
92 | "Count of the times transmission started",
93 | []string{"type"},
94 | nil,
95 | ),
96 | }
97 | }
98 |
99 | // Describe implements the prometheus.Collector interface
100 | func (sc *SessionStatsCollector) Describe(ch chan<- *prometheus.Desc) {
101 | ch <- sc.DownloadSpeed
102 | ch <- sc.UploadSpeed
103 | ch <- sc.TorrentsTotal
104 | ch <- sc.TorrentsActive
105 | ch <- sc.TorrentsPaused
106 | }
107 |
108 | // Collect implements the prometheus.Collector interface
109 | func (sc *SessionStatsCollector) Collect(ch chan<- prometheus.Metric) {
110 | stats, err := sc.client.GetSessionStats()
111 | if err != nil {
112 | log.Printf("failed to get session stats: %v", err)
113 | return
114 | }
115 |
116 | ch <- prometheus.MustNewConstMetric(
117 | sc.DownloadSpeed,
118 | prometheus.GaugeValue,
119 | float64(stats.DownloadSpeed),
120 | )
121 | ch <- prometheus.MustNewConstMetric(
122 | sc.UploadSpeed,
123 | prometheus.GaugeValue,
124 | float64(stats.UploadSpeed),
125 | )
126 | ch <- prometheus.MustNewConstMetric(
127 | sc.TorrentsTotal,
128 | prometheus.GaugeValue,
129 | float64(stats.TorrentCount),
130 | )
131 | ch <- prometheus.MustNewConstMetric(
132 | sc.TorrentsActive,
133 | prometheus.GaugeValue,
134 | float64(stats.ActiveTorrentCount),
135 | )
136 | ch <- prometheus.MustNewConstMetric(
137 | sc.TorrentsPaused,
138 | prometheus.GaugeValue,
139 | float64(stats.PausedTorrentCount),
140 | )
141 |
142 | types := []string{"current", "cumulative"}
143 | for _, t := range types {
144 | var stateStats transmission.SessionStateStats
145 | if t == types[0] {
146 | stateStats = stats.CurrentStats
147 | } else {
148 | stateStats = stats.CumulativeStats
149 | }
150 |
151 | ch <- prometheus.MustNewConstMetric(
152 | sc.Downloaded,
153 | prometheus.GaugeValue,
154 | float64(stateStats.DownloadedBytes),
155 | t,
156 | )
157 | ch <- prometheus.MustNewConstMetric(
158 | sc.Uploaded,
159 | prometheus.GaugeValue,
160 | float64(stateStats.UploadedBytes),
161 | t,
162 | )
163 | ch <- prometheus.MustNewConstMetric(
164 | sc.FilesAdded,
165 | prometheus.GaugeValue,
166 | float64(stateStats.FilesAdded),
167 | t,
168 | )
169 |
170 | dur := time.Duration(stateStats.SecondsActive) * time.Second
171 | timestamp := time.Now().Add(-1 * dur).Unix()
172 |
173 | ch <- prometheus.MustNewConstMetric(
174 | sc.ActiveTime,
175 | prometheus.GaugeValue,
176 | float64(timestamp),
177 | t,
178 | )
179 | ch <- prometheus.MustNewConstMetric(
180 | sc.SessionCount,
181 | prometheus.GaugeValue,
182 | float64(stateStats.SessionCount),
183 | t,
184 | )
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/cmd/transmission-exporter/torrent_collector.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "strconv"
6 |
7 | transmission "github.com/metalmatze/transmission-exporter"
8 | "github.com/prometheus/client_golang/prometheus"
9 | )
10 |
11 | const (
12 | namespace string = "transmission_"
13 | )
14 |
15 | // TorrentCollector has a transmission.Client to create torrent metrics
16 | type TorrentCollector struct {
17 | client *transmission.Client
18 |
19 | Status *prometheus.Desc
20 | Added *prometheus.Desc
21 | Files *prometheus.Desc
22 | Finished *prometheus.Desc
23 | Done *prometheus.Desc
24 | Ratio *prometheus.Desc
25 | Download *prometheus.Desc
26 | Upload *prometheus.Desc
27 | PeersConnected *prometheus.Desc
28 | PeersGettingFromUs *prometheus.Desc
29 | TotalSize *prometheus.Desc
30 | UploadedEver *prometheus.Desc
31 |
32 | // TrackerStats
33 | Downloads *prometheus.Desc
34 | Leechers *prometheus.Desc
35 | Seeders *prometheus.Desc
36 | }
37 |
38 | // NewTorrentCollector creates a new torrent collector with the transmission.Client
39 | func NewTorrentCollector(client *transmission.Client) *TorrentCollector {
40 | const collectorNamespace = "torrent_"
41 |
42 | return &TorrentCollector{
43 | client: client,
44 |
45 | Status: prometheus.NewDesc(
46 | namespace+collectorNamespace+"status",
47 | "Status of a torrent",
48 | []string{"id", "name"},
49 | nil,
50 | ),
51 | Added: prometheus.NewDesc(
52 | namespace+collectorNamespace+"added",
53 | "The unixtime time a torrent was added",
54 | []string{"id", "name"},
55 | nil,
56 | ),
57 | Files: prometheus.NewDesc(
58 | namespace+collectorNamespace+"files_total",
59 | "The total number of files in a torrent",
60 | []string{"id", "name"},
61 | nil,
62 | ),
63 | Finished: prometheus.NewDesc(
64 | namespace+collectorNamespace+"finished",
65 | "Indicates if a torrent is finished (1) or not (0)",
66 | []string{"id", "name"},
67 | nil,
68 | ),
69 | Done: prometheus.NewDesc(
70 | namespace+collectorNamespace+"done",
71 | "The percent of a torrent being done",
72 | []string{"id", "name"},
73 | nil,
74 | ),
75 | Ratio: prometheus.NewDesc(
76 | namespace+collectorNamespace+"ratio",
77 | "The upload ratio of a torrent",
78 | []string{"id", "name"},
79 | nil,
80 | ),
81 | Download: prometheus.NewDesc(
82 | namespace+collectorNamespace+"download_bytes",
83 | "The current download rate of a torrent in bytes",
84 | []string{"id", "name"},
85 | nil,
86 | ),
87 | Upload: prometheus.NewDesc(
88 | namespace+collectorNamespace+"upload_bytes",
89 | "The current upload rate of a torrent in bytes",
90 | []string{"id", "name"},
91 | nil,
92 | ),
93 | PeersConnected: prometheus.NewDesc(
94 | namespace+collectorNamespace+"peers_connected",
95 | "The current number of peers connected to us",
96 | []string{"id", "name"},
97 | nil,
98 | ),
99 | PeersGettingFromUs: prometheus.NewDesc(
100 | namespace+collectorNamespace+"peers_getting_from_us",
101 | "The current number of peers downloading from us",
102 | []string{"id", "name"},
103 | nil,
104 | ),
105 | TotalSize: prometheus.NewDesc(
106 | namespace+collectorNamespace+"total_size",
107 | "The total size of the torrent",
108 | []string{"id", "name"},
109 | nil,
110 | ),
111 | UploadedEver: prometheus.NewDesc(
112 | namespace+collectorNamespace+"uploaded_ever",
113 | "The total uploaded of the torrent",
114 | []string{"id", "name"},
115 | nil,
116 | ),
117 |
118 | // TrackerStats
119 | Downloads: prometheus.NewDesc(
120 | namespace+collectorNamespace+"downloads_total",
121 | "How often this torrent was downloaded",
122 | []string{"id", "name", "tracker"},
123 | nil,
124 | ),
125 | Leechers: prometheus.NewDesc(
126 | namespace+collectorNamespace+"leechers",
127 | "The number of peers downloading this torrent",
128 | []string{"id", "name", "tracker"},
129 | nil,
130 | ),
131 | Seeders: prometheus.NewDesc(
132 | namespace+collectorNamespace+"seeders",
133 | "The number of peers uploading this torrent",
134 | []string{"id", "name", "tracker"},
135 | nil,
136 | ),
137 | }
138 | }
139 |
140 | // Describe implements the prometheus.Collector interface
141 | func (tc *TorrentCollector) Describe(ch chan<- *prometheus.Desc) {
142 | ch <- tc.Status
143 | ch <- tc.Added
144 | ch <- tc.Files
145 | ch <- tc.Finished
146 | ch <- tc.Done
147 | ch <- tc.Ratio
148 | ch <- tc.Download
149 | ch <- tc.Upload
150 | ch <- tc.Downloads
151 | ch <- tc.Leechers
152 | ch <- tc.Seeders
153 | ch <- tc.PeersConnected
154 | ch <- tc.PeersGettingFromUs
155 | ch <- tc.TotalSize
156 | ch <- tc.UploadedEver
157 | }
158 |
159 | // Collect implements the prometheus.Collector interface
160 | func (tc *TorrentCollector) Collect(ch chan<- prometheus.Metric) {
161 | torrents, err := tc.client.GetTorrents()
162 | if err != nil {
163 | log.Printf("failed to get torrents: %v", err)
164 | return
165 | }
166 |
167 | for _, t := range torrents {
168 | var finished float64
169 |
170 | id := strconv.Itoa(t.ID)
171 |
172 | if t.IsFinished {
173 | finished = 1
174 | }
175 |
176 | ch <- prometheus.MustNewConstMetric(
177 | tc.Status,
178 | prometheus.GaugeValue,
179 | float64(t.Status),
180 | id, t.Name,
181 | )
182 | ch <- prometheus.MustNewConstMetric(
183 | tc.Added,
184 | prometheus.GaugeValue,
185 | float64(t.Added),
186 | id, t.Name,
187 | )
188 | ch <- prometheus.MustNewConstMetric(
189 | tc.Files,
190 | prometheus.GaugeValue,
191 | float64(len(t.Files)),
192 | id, t.Name,
193 | )
194 | ch <- prometheus.MustNewConstMetric(
195 | tc.Finished,
196 | prometheus.GaugeValue,
197 | finished,
198 | id, t.Name,
199 | )
200 | ch <- prometheus.MustNewConstMetric(
201 | tc.Done,
202 | prometheus.GaugeValue,
203 | t.PercentDone,
204 | id, t.Name,
205 | )
206 | ch <- prometheus.MustNewConstMetric(
207 | tc.Ratio,
208 | prometheus.GaugeValue,
209 | t.UploadRatio,
210 | id, t.Name,
211 | )
212 | ch <- prometheus.MustNewConstMetric(
213 | tc.Download,
214 | prometheus.GaugeValue,
215 | float64(t.RateDownload),
216 | id, t.Name,
217 | )
218 | ch <- prometheus.MustNewConstMetric(
219 | tc.Upload,
220 | prometheus.GaugeValue,
221 | float64(t.RateUpload),
222 | id, t.Name,
223 | )
224 | ch <- prometheus.MustNewConstMetric(
225 | tc.PeersConnected,
226 | prometheus.GaugeValue,
227 | float64(t.PeersConnected),
228 | id, t.Name,
229 | )
230 | ch <- prometheus.MustNewConstMetric(
231 | tc.PeersGettingFromUs,
232 | prometheus.GaugeValue,
233 | float64(t.PeersGettingFromUs),
234 | id, t.Name,
235 | )
236 | ch <- prometheus.MustNewConstMetric(
237 | tc.TotalSize,
238 | prometheus.GaugeValue,
239 | float64(t.TotalSize),
240 | id, t.Name,
241 | )
242 | ch <- prometheus.MustNewConstMetric(
243 | tc.UploadedEver,
244 | prometheus.GaugeValue,
245 | float64(t.UploadedEver),
246 | id, t.Name,
247 | )
248 |
249 | tstats := make(map[string]transmission.TrackerStat)
250 |
251 | for _, tracker := range t.TrackerStats {
252 | if tr, exists := tstats[tracker.Host]; exists {
253 | tr.DownloadCount += tracker.DownloadCount
254 | } else {
255 | tstats[tracker.Host] = tracker
256 | }
257 | }
258 |
259 | for _, tracker := range tstats {
260 | ch <- prometheus.MustNewConstMetric(
261 | tc.Downloads,
262 | prometheus.GaugeValue,
263 | float64(tracker.DownloadCount),
264 | id, t.Name, tracker.Host,
265 | )
266 |
267 | ch <- prometheus.MustNewConstMetric(
268 | tc.Leechers,
269 | prometheus.GaugeValue,
270 | float64(tracker.LeecherCount),
271 | id, t.Name, tracker.Host,
272 | )
273 |
274 | ch <- prometheus.MustNewConstMetric(
275 | tc.Seeders,
276 | prometheus.GaugeValue,
277 | float64(tracker.SeederCount),
278 | id, t.Name, tracker.Host,
279 | )
280 | }
281 | }
282 | }
283 |
--------------------------------------------------------------------------------
/dashboards/dashboard.json:
--------------------------------------------------------------------------------
1 | {
2 | "annotations": {
3 | "list": [
4 | {
5 | "builtIn": 1,
6 | "datasource": {
7 | "type": "datasource",
8 | "uid": "grafana"
9 | },
10 | "enable": true,
11 | "hide": true,
12 | "iconColor": "rgba(0, 211, 255, 1)",
13 | "name": "Annotations & Alerts",
14 | "target": {
15 | "limit": 100,
16 | "matchAny": false,
17 | "tags": [],
18 | "type": "dashboard"
19 | },
20 | "type": "dashboard"
21 | }
22 | ]
23 | },
24 | "editable": true,
25 | "fiscalYearStartMonth": 0,
26 | "gnetId": 15116,
27 | "graphTooltip": 0,
28 | "id": 3,
29 | "links": [],
30 | "liveNow": false,
31 | "panels": [
32 | {
33 | "datasource": {
34 | "type": "prometheus",
35 | "uid": "PBFA97CFB590B2093"
36 | },
37 | "fieldConfig": {
38 | "defaults": {
39 | "decimals": 2,
40 | "mappings": [
41 | {
42 | "id": 0,
43 | "op": "=",
44 | "text": "N/A",
45 | "type": 1,
46 | "value": "null"
47 | }
48 | ],
49 | "thresholds": {
50 | "mode": "absolute",
51 | "steps": [
52 | {
53 | "color": "green",
54 | "value": null
55 | }
56 | ]
57 | },
58 | "unit": "decbytes"
59 | },
60 | "overrides": []
61 | },
62 | "gridPos": {
63 | "h": 5,
64 | "w": 6,
65 | "x": 0,
66 | "y": 0
67 | },
68 | "id": 34,
69 | "options": {
70 | "colorMode": "value",
71 | "graphMode": "area",
72 | "justifyMode": "auto",
73 | "orientation": "horizontal",
74 | "reduceOptions": {
75 | "calcs": [
76 | "lastNotNull"
77 | ],
78 | "fields": "",
79 | "values": false
80 | },
81 | "showPercentChange": false,
82 | "text": {},
83 | "textMode": "auto",
84 | "wideLayout": true
85 | },
86 | "pluginVersion": "10.4.3",
87 | "targets": [
88 | {
89 | "datasource": {
90 | "type": "prometheus",
91 | "uid": "PBFA97CFB590B2093"
92 | },
93 | "disableTextWrap": false,
94 | "editorMode": "builder",
95 | "expr": "transmission_session_stats_downloaded_bytes{type=\"current\"}",
96 | "fullMetaSearch": false,
97 | "includeNullMetadata": true,
98 | "legendFormat": "__auto",
99 | "range": true,
100 | "refId": "A",
101 | "useBackend": false
102 | }
103 | ],
104 | "title": "Session Downloaded",
105 | "type": "stat"
106 | },
107 | {
108 | "datasource": {
109 | "type": "prometheus",
110 | "uid": "PBFA97CFB590B2093"
111 | },
112 | "fieldConfig": {
113 | "defaults": {
114 | "decimals": 2,
115 | "mappings": [],
116 | "thresholds": {
117 | "mode": "absolute",
118 | "steps": [
119 | {
120 | "color": "green",
121 | "value": null
122 | }
123 | ]
124 | },
125 | "unit": "decbytes"
126 | },
127 | "overrides": []
128 | },
129 | "gridPos": {
130 | "h": 5,
131 | "w": 6,
132 | "x": 6,
133 | "y": 0
134 | },
135 | "id": 30,
136 | "options": {
137 | "colorMode": "value",
138 | "graphMode": "area",
139 | "justifyMode": "auto",
140 | "orientation": "auto",
141 | "reduceOptions": {
142 | "calcs": [
143 | "lastNotNull"
144 | ],
145 | "fields": "",
146 | "values": false
147 | },
148 | "showPercentChange": false,
149 | "text": {},
150 | "textMode": "auto",
151 | "wideLayout": true
152 | },
153 | "pluginVersion": "10.4.3",
154 | "targets": [
155 | {
156 | "datasource": {
157 | "type": "prometheus",
158 | "uid": "PBFA97CFB590B2093"
159 | },
160 | "disableTextWrap": false,
161 | "editorMode": "builder",
162 | "expr": "transmission_session_stats_downloaded_bytes{type=\"cumulative\"}",
163 | "fullMetaSearch": false,
164 | "includeNullMetadata": true,
165 | "legendFormat": "__auto",
166 | "range": true,
167 | "refId": "A",
168 | "useBackend": false
169 | }
170 | ],
171 | "title": "All Time Downloaded",
172 | "type": "stat"
173 | },
174 | {
175 | "datasource": {
176 | "type": "prometheus",
177 | "uid": "PBFA97CFB590B2093"
178 | },
179 | "fieldConfig": {
180 | "defaults": {
181 | "decimals": 2,
182 | "mappings": [],
183 | "thresholds": {
184 | "mode": "absolute",
185 | "steps": [
186 | {
187 | "color": "rgb(255, 172, 10)",
188 | "value": null
189 | }
190 | ]
191 | },
192 | "unit": "decbytes"
193 | },
194 | "overrides": []
195 | },
196 | "gridPos": {
197 | "h": 5,
198 | "w": 6,
199 | "x": 12,
200 | "y": 0
201 | },
202 | "id": 32,
203 | "options": {
204 | "colorMode": "value",
205 | "graphMode": "area",
206 | "justifyMode": "auto",
207 | "orientation": "auto",
208 | "reduceOptions": {
209 | "calcs": [
210 | "lastNotNull"
211 | ],
212 | "fields": "",
213 | "values": false
214 | },
215 | "showPercentChange": false,
216 | "text": {},
217 | "textMode": "auto",
218 | "wideLayout": true
219 | },
220 | "pluginVersion": "10.4.3",
221 | "targets": [
222 | {
223 | "datasource": {
224 | "type": "prometheus",
225 | "uid": "PBFA97CFB590B2093"
226 | },
227 | "disableTextWrap": false,
228 | "editorMode": "builder",
229 | "expr": "transmission_session_stats_uploaded_bytes{type=\"cumulative\"}",
230 | "fullMetaSearch": false,
231 | "includeNullMetadata": true,
232 | "instant": false,
233 | "legendFormat": "__auto",
234 | "refId": "A",
235 | "useBackend": false
236 | }
237 | ],
238 | "title": "All Time Uploaded",
239 | "type": "stat"
240 | },
241 | {
242 | "datasource": {
243 | "type": "prometheus",
244 | "uid": "PBFA97CFB590B2093"
245 | },
246 | "fieldConfig": {
247 | "defaults": {
248 | "decimals": 2,
249 | "mappings": [],
250 | "thresholds": {
251 | "mode": "absolute",
252 | "steps": [
253 | {
254 | "color": "rgb(255, 172, 10)",
255 | "value": null
256 | }
257 | ]
258 | },
259 | "unit": "decbytes"
260 | },
261 | "overrides": []
262 | },
263 | "gridPos": {
264 | "h": 5,
265 | "w": 6,
266 | "x": 18,
267 | "y": 0
268 | },
269 | "id": 35,
270 | "options": {
271 | "colorMode": "value",
272 | "graphMode": "area",
273 | "justifyMode": "auto",
274 | "orientation": "auto",
275 | "reduceOptions": {
276 | "calcs": [
277 | "lastNotNull"
278 | ],
279 | "fields": "",
280 | "values": false
281 | },
282 | "showPercentChange": false,
283 | "text": {},
284 | "textMode": "auto",
285 | "wideLayout": true
286 | },
287 | "pluginVersion": "10.4.3",
288 | "targets": [
289 | {
290 | "datasource": {
291 | "type": "prometheus",
292 | "uid": "PBFA97CFB590B2093"
293 | },
294 | "disableTextWrap": false,
295 | "editorMode": "builder",
296 | "expr": "transmission_session_stats_uploaded_bytes{type=\"current\"}",
297 | "fullMetaSearch": false,
298 | "includeNullMetadata": true,
299 | "instant": false,
300 | "legendFormat": "__auto",
301 | "refId": "A",
302 | "useBackend": false
303 | }
304 | ],
305 | "title": "Session Uploaded",
306 | "type": "stat"
307 | },
308 | {
309 | "datasource": {
310 | "type": "prometheus",
311 | "uid": "PBFA97CFB590B2093"
312 | },
313 | "fieldConfig": {
314 | "defaults": {
315 | "color": {
316 | "mode": "thresholds"
317 | },
318 | "mappings": [
319 | {
320 | "options": {
321 | "match": "null",
322 | "result": {
323 | "text": "N/A"
324 | }
325 | },
326 | "type": "special"
327 | }
328 | ],
329 | "thresholds": {
330 | "mode": "absolute",
331 | "steps": [
332 | {
333 | "color": "green",
334 | "value": null
335 | },
336 | {
337 | "color": "red",
338 | "value": 80
339 | }
340 | ]
341 | },
342 | "unit": "none"
343 | },
344 | "overrides": []
345 | },
346 | "gridPos": {
347 | "h": 4,
348 | "w": 3,
349 | "x": 0,
350 | "y": 5
351 | },
352 | "id": 6,
353 | "maxDataPoints": 100,
354 | "options": {
355 | "colorMode": "none",
356 | "graphMode": "none",
357 | "justifyMode": "auto",
358 | "orientation": "horizontal",
359 | "reduceOptions": {
360 | "calcs": [
361 | "mean"
362 | ],
363 | "fields": "",
364 | "values": false
365 | },
366 | "showPercentChange": false,
367 | "text": {},
368 | "textMode": "auto",
369 | "wideLayout": true
370 | },
371 | "pluginVersion": "10.4.3",
372 | "targets": [
373 | {
374 | "datasource": {
375 | "type": "prometheus",
376 | "uid": "PBFA97CFB590B2093"
377 | },
378 | "editorMode": "code",
379 | "expr": "count(transmission_torrent_status != -1)",
380 | "instant": true,
381 | "interval": "",
382 | "legendFormat": "__auto",
383 | "refId": "A"
384 | }
385 | ],
386 | "title": "Total Torrents",
387 | "type": "stat"
388 | },
389 | {
390 | "datasource": {
391 | "type": "prometheus",
392 | "uid": "PBFA97CFB590B2093"
393 | },
394 | "fieldConfig": {
395 | "defaults": {
396 | "color": {
397 | "mode": "thresholds"
398 | },
399 | "mappings": [
400 | {
401 | "options": {
402 | "match": "null",
403 | "result": {
404 | "color": "rgb(33, 33, 35)",
405 | "text": "0"
406 | }
407 | },
408 | "type": "special"
409 | }
410 | ],
411 | "thresholds": {
412 | "mode": "absolute",
413 | "steps": [
414 | {
415 | "color": "rgb(33, 33, 35)",
416 | "value": null
417 | },
418 | {
419 | "color": "#37872D",
420 | "value": 1
421 | },
422 | {
423 | "color": "#d44a3a"
424 | }
425 | ]
426 | },
427 | "unit": "none"
428 | },
429 | "overrides": []
430 | },
431 | "gridPos": {
432 | "h": 4,
433 | "w": 3,
434 | "x": 3,
435 | "y": 5
436 | },
437 | "id": 8,
438 | "maxDataPoints": 100,
439 | "options": {
440 | "colorMode": "background",
441 | "graphMode": "none",
442 | "justifyMode": "auto",
443 | "orientation": "horizontal",
444 | "reduceOptions": {
445 | "calcs": [
446 | "mean"
447 | ],
448 | "fields": "",
449 | "values": false
450 | },
451 | "showPercentChange": false,
452 | "text": {},
453 | "textMode": "auto",
454 | "wideLayout": true
455 | },
456 | "pluginVersion": "10.4.3",
457 | "targets": [
458 | {
459 | "datasource": {
460 | "type": "prometheus",
461 | "uid": "PBFA97CFB590B2093"
462 | },
463 | "editorMode": "code",
464 | "expr": "sum(transmission_torrent_peers_sending_to_us)",
465 | "instant": true,
466 | "legendFormat": "__auto",
467 | "refId": "A"
468 | }
469 | ],
470 | "title": "Downloading From",
471 | "type": "stat"
472 | },
473 | {
474 | "datasource": {
475 | "type": "prometheus",
476 | "uid": "PBFA97CFB590B2093"
477 | },
478 | "fieldConfig": {
479 | "defaults": {
480 | "color": {
481 | "mode": "thresholds"
482 | },
483 | "decimals": 2,
484 | "mappings": [
485 | {
486 | "options": {
487 | "match": "null",
488 | "result": {
489 | "text": "N/A"
490 | }
491 | },
492 | "type": "special"
493 | }
494 | ],
495 | "thresholds": {
496 | "mode": "absolute",
497 | "steps": [
498 | {
499 | "color": "transparent",
500 | "value": null
501 | },
502 | {
503 | "color": "#37872D",
504 | "value": 1
505 | }
506 | ]
507 | },
508 | "unit": "Bps"
509 | },
510 | "overrides": []
511 | },
512 | "gridPos": {
513 | "h": 4,
514 | "w": 6,
515 | "x": 6,
516 | "y": 5
517 | },
518 | "id": 12,
519 | "maxDataPoints": 100,
520 | "options": {
521 | "colorMode": "background",
522 | "graphMode": "none",
523 | "justifyMode": "auto",
524 | "orientation": "horizontal",
525 | "reduceOptions": {
526 | "calcs": [
527 | "mean"
528 | ],
529 | "fields": "",
530 | "values": false
531 | },
532 | "showPercentChange": false,
533 | "text": {},
534 | "textMode": "auto",
535 | "wideLayout": true
536 | },
537 | "pluginVersion": "10.4.3",
538 | "targets": [
539 | {
540 | "datasource": {
541 | "type": "prometheus",
542 | "uid": "PBFA97CFB590B2093"
543 | },
544 | "editorMode": "code",
545 | "expr": "transmission_session_stats_download_speed_bytes",
546 | "instant": true,
547 | "legendFormat": "__auto",
548 | "refId": "A"
549 | }
550 | ],
551 | "title": "Global Download Speed",
552 | "type": "stat"
553 | },
554 | {
555 | "datasource": {
556 | "type": "prometheus",
557 | "uid": "PBFA97CFB590B2093"
558 | },
559 | "fieldConfig": {
560 | "defaults": {
561 | "color": {
562 | "mode": "thresholds"
563 | },
564 | "decimals": 2,
565 | "mappings": [
566 | {
567 | "options": {
568 | "match": "null",
569 | "result": {
570 | "text": "N/A"
571 | }
572 | },
573 | "type": "special"
574 | }
575 | ],
576 | "thresholds": {
577 | "mode": "absolute",
578 | "steps": [
579 | {
580 | "color": "rgb(33, 33, 35)",
581 | "value": null
582 | },
583 | {
584 | "color": "rgba(237, 158, 40, 0.89)",
585 | "value": 1
586 | },
587 | {
588 | "color": "#d44a3a"
589 | }
590 | ]
591 | },
592 | "unit": "Bps"
593 | },
594 | "overrides": []
595 | },
596 | "gridPos": {
597 | "h": 4,
598 | "w": 6,
599 | "x": 12,
600 | "y": 5
601 | },
602 | "id": 14,
603 | "maxDataPoints": 100,
604 | "options": {
605 | "colorMode": "background",
606 | "graphMode": "none",
607 | "justifyMode": "auto",
608 | "orientation": "horizontal",
609 | "reduceOptions": {
610 | "calcs": [
611 | "mean"
612 | ],
613 | "fields": "",
614 | "values": false
615 | },
616 | "showPercentChange": false,
617 | "text": {},
618 | "textMode": "auto",
619 | "wideLayout": true
620 | },
621 | "pluginVersion": "10.4.3",
622 | "targets": [
623 | {
624 | "datasource": {
625 | "type": "prometheus",
626 | "uid": "PBFA97CFB590B2093"
627 | },
628 | "editorMode": "code",
629 | "expr": "transmission_session_stats_upload_speed_bytes",
630 | "instant": true,
631 | "refId": "A"
632 | }
633 | ],
634 | "title": "Global Upload Speed",
635 | "type": "stat"
636 | },
637 | {
638 | "datasource": {
639 | "type": "prometheus",
640 | "uid": "PBFA97CFB590B2093"
641 | },
642 | "fieldConfig": {
643 | "defaults": {
644 | "color": {
645 | "mode": "thresholds"
646 | },
647 | "mappings": [
648 | {
649 | "options": {
650 | "match": "null",
651 | "result": {
652 | "color": "rgb(33, 33, 35)",
653 | "text": "0"
654 | }
655 | },
656 | "type": "special"
657 | }
658 | ],
659 | "thresholds": {
660 | "mode": "absolute",
661 | "steps": [
662 | {
663 | "color": "rgb(33, 33, 35)",
664 | "value": null
665 | },
666 | {
667 | "color": "red",
668 | "value": 0
669 | },
670 | {
671 | "color": "orange",
672 | "value": 7
673 | },
674 | {
675 | "color": "yellow",
676 | "value": 15
677 | },
678 | {
679 | "color": "green",
680 | "value": 25
681 | }
682 | ]
683 | },
684 | "unit": "none"
685 | },
686 | "overrides": []
687 | },
688 | "gridPos": {
689 | "h": 4,
690 | "w": 3,
691 | "x": 18,
692 | "y": 5
693 | },
694 | "id": 10,
695 | "maxDataPoints": 100,
696 | "options": {
697 | "colorMode": "background",
698 | "graphMode": "none",
699 | "justifyMode": "auto",
700 | "orientation": "horizontal",
701 | "reduceOptions": {
702 | "calcs": [
703 | "mean"
704 | ],
705 | "fields": "",
706 | "values": false
707 | },
708 | "showPercentChange": false,
709 | "text": {},
710 | "textMode": "auto",
711 | "wideLayout": true
712 | },
713 | "pluginVersion": "10.4.3",
714 | "targets": [
715 | {
716 | "datasource": {
717 | "type": "prometheus",
718 | "uid": "PBFA97CFB590B2093"
719 | },
720 | "editorMode": "code",
721 | "expr": "sum(transmission_torrent_peers_getting_from_us)",
722 | "instant": true,
723 | "refId": "A"
724 | }
725 | ],
726 | "title": "Seeding To",
727 | "type": "stat"
728 | },
729 | {
730 | "datasource": {
731 | "type": "prometheus",
732 | "uid": "PBFA97CFB590B2093"
733 | },
734 | "fieldConfig": {
735 | "defaults": {
736 | "color": {
737 | "mode": "thresholds"
738 | },
739 | "decimals": 2,
740 | "mappings": [],
741 | "max": 1,
742 | "min": 0,
743 | "thresholds": {
744 | "mode": "absolute",
745 | "steps": [
746 | {
747 | "color": "green",
748 | "value": null
749 | }
750 | ]
751 | }
752 | },
753 | "overrides": []
754 | },
755 | "gridPos": {
756 | "h": 4,
757 | "w": 3,
758 | "x": 21,
759 | "y": 5
760 | },
761 | "id": 37,
762 | "options": {
763 | "minVizHeight": 75,
764 | "minVizWidth": 75,
765 | "orientation": "auto",
766 | "reduceOptions": {
767 | "calcs": [
768 | "lastNotNull"
769 | ],
770 | "fields": "",
771 | "values": false
772 | },
773 | "showThresholdLabels": false,
774 | "showThresholdMarkers": true,
775 | "sizing": "auto",
776 | "text": {}
777 | },
778 | "pluginVersion": "10.4.3",
779 | "targets": [
780 | {
781 | "datasource": {
782 | "type": "prometheus",
783 | "uid": "PBFA97CFB590B2093"
784 | },
785 | "disableTextWrap": false,
786 | "editorMode": "code",
787 | "exemplar": true,
788 | "expr": "transmission_session_stats_uploaded_bytes{type=\"cumulative\"} / transmission_session_stats_downloaded_bytes{type=\"cumulative\"}",
789 | "fullMetaSearch": false,
790 | "includeNullMetadata": true,
791 | "interval": "",
792 | "legendFormat": "__auto",
793 | "range": true,
794 | "refId": "A",
795 | "useBackend": false
796 | }
797 | ],
798 | "title": "Global Ratio",
799 | "type": "gauge"
800 | },
801 | {
802 | "datasource": {
803 | "type": "prometheus",
804 | "uid": "PBFA97CFB590B2093"
805 | },
806 | "fieldConfig": {
807 | "defaults": {
808 | "color": {
809 | "mode": "palette-classic"
810 | },
811 | "custom": {
812 | "axisBorderShow": false,
813 | "axisCenteredZero": false,
814 | "axisColorMode": "text",
815 | "axisLabel": "",
816 | "axisPlacement": "auto",
817 | "barAlignment": 0,
818 | "drawStyle": "line",
819 | "fillOpacity": 10,
820 | "gradientMode": "none",
821 | "hideFrom": {
822 | "legend": false,
823 | "tooltip": false,
824 | "viz": false
825 | },
826 | "insertNulls": false,
827 | "lineInterpolation": "linear",
828 | "lineWidth": 1,
829 | "pointSize": 5,
830 | "scaleDistribution": {
831 | "type": "linear"
832 | },
833 | "showPoints": "never",
834 | "spanNulls": false,
835 | "stacking": {
836 | "group": "A",
837 | "mode": "none"
838 | },
839 | "thresholdsStyle": {
840 | "mode": "off"
841 | }
842 | },
843 | "decimals": 2,
844 | "links": [],
845 | "mappings": [],
846 | "min": 0,
847 | "thresholds": {
848 | "mode": "absolute",
849 | "steps": [
850 | {
851 | "color": "green",
852 | "value": null
853 | },
854 | {
855 | "color": "orange",
856 | "value": 50
857 | },
858 | {
859 | "color": "red",
860 | "value": 70
861 | }
862 | ]
863 | },
864 | "unit": "Bps"
865 | },
866 | "overrides": []
867 | },
868 | "gridPos": {
869 | "h": 7,
870 | "w": 24,
871 | "x": 0,
872 | "y": 9
873 | },
874 | "id": 2,
875 | "interval": "5",
876 | "options": {
877 | "legend": {
878 | "calcs": [],
879 | "displayMode": "list",
880 | "placement": "right",
881 | "showLegend": true
882 | },
883 | "tooltip": {
884 | "mode": "multi",
885 | "sort": "none"
886 | }
887 | },
888 | "pluginVersion": "10.4.3",
889 | "targets": [
890 | {
891 | "datasource": {
892 | "type": "prometheus",
893 | "uid": "PBFA97CFB590B2093"
894 | },
895 | "editorMode": "code",
896 | "expr": "transmission_session_stats_download_speed_bytes",
897 | "interval": "",
898 | "legendFormat": "Downloaded",
899 | "range": true,
900 | "refId": "A"
901 | },
902 | {
903 | "datasource": {
904 | "type": "prometheus",
905 | "uid": "PBFA97CFB590B2093"
906 | },
907 | "editorMode": "code",
908 | "expr": "transmission_session_stats_upload_speed_bytes",
909 | "interval": "",
910 | "legendFormat": "Upload",
911 | "range": true,
912 | "refId": "B"
913 | }
914 | ],
915 | "title": "Upload / Download Speeds",
916 | "type": "timeseries"
917 | },
918 | {
919 | "datasource": {
920 | "type": "prometheus",
921 | "uid": "PBFA97CFB590B2093"
922 | },
923 | "fieldConfig": {
924 | "defaults": {
925 | "color": {
926 | "mode": "palette-classic"
927 | },
928 | "custom": {
929 | "axisBorderShow": false,
930 | "axisCenteredZero": false,
931 | "axisColorMode": "text",
932 | "axisGridShow": true,
933 | "axisLabel": "",
934 | "axisPlacement": "left",
935 | "barAlignment": 0,
936 | "drawStyle": "line",
937 | "fillOpacity": 11,
938 | "gradientMode": "none",
939 | "hideFrom": {
940 | "legend": false,
941 | "tooltip": false,
942 | "viz": false
943 | },
944 | "insertNulls": false,
945 | "lineInterpolation": "smooth",
946 | "lineStyle": {
947 | "fill": "solid"
948 | },
949 | "lineWidth": 1.4,
950 | "pointSize": 1,
951 | "scaleDistribution": {
952 | "type": "linear"
953 | },
954 | "showPoints": "never",
955 | "spanNulls": false,
956 | "stacking": {
957 | "group": "A",
958 | "mode": "none"
959 | },
960 | "thresholdsStyle": {
961 | "mode": "off"
962 | }
963 | },
964 | "decimals": 2,
965 | "fieldMinMax": false,
966 | "links": [],
967 | "mappings": [],
968 | "thresholds": {
969 | "mode": "absolute",
970 | "steps": [
971 | {
972 | "color": "green",
973 | "value": null
974 | },
975 | {
976 | "color": "red",
977 | "value": 80
978 | }
979 | ]
980 | },
981 | "unit": "Bps"
982 | },
983 | "overrides": []
984 | },
985 | "gridPos": {
986 | "h": 7,
987 | "w": 24,
988 | "x": 0,
989 | "y": 16
990 | },
991 | "id": 26,
992 | "interval": "5",
993 | "options": {
994 | "legend": {
995 | "calcs": [],
996 | "displayMode": "list",
997 | "placement": "bottom",
998 | "showLegend": false,
999 | "width": 200
1000 | },
1001 | "tooltip": {
1002 | "hoverProximity": 1,
1003 | "mode": "multi",
1004 | "sort": "desc"
1005 | }
1006 | },
1007 | "pluginVersion": "10.4.3",
1008 | "targets": [
1009 | {
1010 | "datasource": {
1011 | "type": "prometheus",
1012 | "uid": "PBFA97CFB590B2093"
1013 | },
1014 | "disableTextWrap": false,
1015 | "editorMode": "builder",
1016 | "exemplar": false,
1017 | "expr": "topk(5, transmission_torrent_upload_bytes)",
1018 | "format": "time_series",
1019 | "fullMetaSearch": false,
1020 | "includeNullMetadata": true,
1021 | "instant": false,
1022 | "legendFormat": "{{name}}",
1023 | "range": true,
1024 | "refId": "A",
1025 | "useBackend": false
1026 | }
1027 | ],
1028 | "title": "Upload Speed by Torrent",
1029 | "type": "timeseries"
1030 | },
1031 | {
1032 | "datasource": {
1033 | "type": "prometheus",
1034 | "uid": "PBFA97CFB590B2093"
1035 | },
1036 | "fieldConfig": {
1037 | "defaults": {
1038 | "color": {
1039 | "mode": "thresholds"
1040 | },
1041 | "custom": {
1042 | "align": "auto",
1043 | "cellOptions": {
1044 | "type": "auto"
1045 | },
1046 | "inspect": false
1047 | },
1048 | "mappings": [],
1049 | "thresholds": {
1050 | "mode": "absolute",
1051 | "steps": [
1052 | {
1053 | "color": "green",
1054 | "value": null
1055 | },
1056 | {
1057 | "color": "red",
1058 | "value": 80
1059 | }
1060 | ]
1061 | }
1062 | },
1063 | "overrides": [
1064 | {
1065 | "matcher": {
1066 | "id": "byName",
1067 | "options": "Progress"
1068 | },
1069 | "properties": [
1070 | {
1071 | "id": "unit",
1072 | "value": "percentunit"
1073 | },
1074 | {
1075 | "id": "decimals",
1076 | "value": 2
1077 | }
1078 | ]
1079 | },
1080 | {
1081 | "matcher": {
1082 | "id": "byName",
1083 | "options": "Download Speed"
1084 | },
1085 | "properties": [
1086 | {
1087 | "id": "unit",
1088 | "value": "Bps"
1089 | },
1090 | {
1091 | "id": "decimals",
1092 | "value": 2
1093 | }
1094 | ]
1095 | },
1096 | {
1097 | "matcher": {
1098 | "id": "byName",
1099 | "options": "Upload Speed"
1100 | },
1101 | "properties": [
1102 | {
1103 | "id": "unit",
1104 | "value": "Bps"
1105 | },
1106 | {
1107 | "id": "decimals",
1108 | "value": 2
1109 | }
1110 | ]
1111 | },
1112 | {
1113 | "matcher": {
1114 | "id": "byName",
1115 | "options": "Bytes Downloaded"
1116 | },
1117 | "properties": [
1118 | {
1119 | "id": "unit",
1120 | "value": "decbytes"
1121 | },
1122 | {
1123 | "id": "decimals",
1124 | "value": 2
1125 | }
1126 | ]
1127 | },
1128 | {
1129 | "matcher": {
1130 | "id": "byName",
1131 | "options": "Bytes Uploaded"
1132 | },
1133 | "properties": [
1134 | {
1135 | "id": "unit",
1136 | "value": "decbytes"
1137 | },
1138 | {
1139 | "id": "decimals",
1140 | "value": 2
1141 | }
1142 | ]
1143 | },
1144 | {
1145 | "matcher": {
1146 | "id": "byName",
1147 | "options": "Date Added"
1148 | },
1149 | "properties": [
1150 | {
1151 | "id": "unit",
1152 | "value": "dateTimeAsSystem"
1153 | }
1154 | ]
1155 | },
1156 | {
1157 | "matcher": {
1158 | "id": "byName",
1159 | "options": "Ratio"
1160 | },
1161 | "properties": [
1162 | {
1163 | "id": "decimals",
1164 | "value": 2
1165 | }
1166 | ]
1167 | },
1168 | {
1169 | "matcher": {
1170 | "id": "byName",
1171 | "options": "Status"
1172 | },
1173 | "properties": [
1174 | {
1175 | "id": "mappings",
1176 | "value": [
1177 | {
1178 | "options": {
1179 | "0": {
1180 | "color": "red",
1181 | "index": 0,
1182 | "text": "Stopped"
1183 | },
1184 | "1": {
1185 | "color": "orange",
1186 | "index": 1,
1187 | "text": "Checking"
1188 | },
1189 | "2": {
1190 | "color": "orange",
1191 | "index": 2,
1192 | "text": "Checking"
1193 | },
1194 | "3": {
1195 | "color": "blue",
1196 | "index": 3,
1197 | "text": "Downloading"
1198 | },
1199 | "4": {
1200 | "color": "blue",
1201 | "index": 4,
1202 | "text": "Downloading"
1203 | },
1204 | "5": {
1205 | "color": "green",
1206 | "index": 5,
1207 | "text": "Seeding"
1208 | },
1209 | "6": {
1210 | "color": "green",
1211 | "index": 6,
1212 | "text": "Seeding"
1213 | }
1214 | },
1215 | "type": "value"
1216 | }
1217 | ]
1218 | }
1219 | ]
1220 | }
1221 | ]
1222 | },
1223 | "gridPos": {
1224 | "h": 7,
1225 | "w": 24,
1226 | "x": 0,
1227 | "y": 23
1228 | },
1229 | "id": 24,
1230 | "options": {
1231 | "cellHeight": "sm",
1232 | "footer": {
1233 | "countRows": false,
1234 | "fields": "",
1235 | "reducer": [
1236 | "sum"
1237 | ],
1238 | "show": false
1239 | },
1240 | "frameIndex": 0,
1241 | "showHeader": true,
1242 | "sortBy": [
1243 | {
1244 | "desc": true,
1245 | "displayName": "Upload Speed"
1246 | }
1247 | ]
1248 | },
1249 | "pluginVersion": "10.4.3",
1250 | "targets": [
1251 | {
1252 | "datasource": {
1253 | "type": "prometheus",
1254 | "uid": "PBFA97CFB590B2093"
1255 | },
1256 | "disableTextWrap": false,
1257 | "editorMode": "builder",
1258 | "exemplar": false,
1259 | "expr": "transmission_torrent_added * 1000",
1260 | "format": "table",
1261 | "fullMetaSearch": false,
1262 | "hide": false,
1263 | "includeNullMetadata": false,
1264 | "instant": true,
1265 | "legendFormat": "Added",
1266 | "range": false,
1267 | "refId": "A",
1268 | "useBackend": false
1269 | },
1270 | {
1271 | "datasource": {
1272 | "type": "prometheus",
1273 | "uid": "PBFA97CFB590B2093"
1274 | },
1275 | "editorMode": "code",
1276 | "exemplar": false,
1277 | "expr": "transmission_torrent_done",
1278 | "format": "table",
1279 | "hide": false,
1280 | "instant": true,
1281 | "legendFormat": "Done",
1282 | "range": false,
1283 | "refId": "B"
1284 | },
1285 | {
1286 | "datasource": {
1287 | "type": "prometheus",
1288 | "uid": "PBFA97CFB590B2093"
1289 | },
1290 | "editorMode": "code",
1291 | "exemplar": false,
1292 | "expr": "transmission_torrent_downloaded_ever_bytes",
1293 | "format": "table",
1294 | "hide": false,
1295 | "instant": true,
1296 | "legendFormat": "Bytes Downloaded",
1297 | "range": false,
1298 | "refId": "C"
1299 | },
1300 | {
1301 | "datasource": {
1302 | "type": "prometheus",
1303 | "uid": "PBFA97CFB590B2093"
1304 | },
1305 | "editorMode": "code",
1306 | "exemplar": false,
1307 | "expr": "transmission_torrent_peers_getting_from_us",
1308 | "format": "table",
1309 | "hide": false,
1310 | "instant": true,
1311 | "legendFormat": "Leechers",
1312 | "range": false,
1313 | "refId": "D"
1314 | },
1315 | {
1316 | "datasource": {
1317 | "type": "prometheus",
1318 | "uid": "PBFA97CFB590B2093"
1319 | },
1320 | "editorMode": "code",
1321 | "exemplar": false,
1322 | "expr": "transmission_torrent_peers_sending_to_us",
1323 | "format": "table",
1324 | "hide": false,
1325 | "instant": true,
1326 | "legendFormat": "Seeders",
1327 | "range": false,
1328 | "refId": "E"
1329 | },
1330 | {
1331 | "datasource": {
1332 | "type": "prometheus",
1333 | "uid": "PBFA97CFB590B2093"
1334 | },
1335 | "editorMode": "code",
1336 | "exemplar": false,
1337 | "expr": "transmission_torrent_ratio",
1338 | "format": "table",
1339 | "hide": false,
1340 | "instant": true,
1341 | "legendFormat": "Ratio",
1342 | "range": false,
1343 | "refId": "F"
1344 | },
1345 | {
1346 | "datasource": {
1347 | "type": "prometheus",
1348 | "uid": "PBFA97CFB590B2093"
1349 | },
1350 | "editorMode": "code",
1351 | "exemplar": false,
1352 | "expr": "transmission_torrent_uploaded_ever_bytes",
1353 | "format": "table",
1354 | "hide": false,
1355 | "instant": true,
1356 | "legendFormat": "Bytes Uploaded",
1357 | "range": false,
1358 | "refId": "G"
1359 | },
1360 | {
1361 | "datasource": {
1362 | "type": "prometheus",
1363 | "uid": "PBFA97CFB590B2093"
1364 | },
1365 | "editorMode": "code",
1366 | "exemplar": false,
1367 | "expr": "transmission_torrent_status",
1368 | "format": "table",
1369 | "hide": false,
1370 | "instant": true,
1371 | "legendFormat": "Status",
1372 | "range": false,
1373 | "refId": "H"
1374 | },
1375 | {
1376 | "datasource": {
1377 | "type": "prometheus",
1378 | "uid": "PBFA97CFB590B2093"
1379 | },
1380 | "editorMode": "code",
1381 | "exemplar": false,
1382 | "expr": "transmission_torrent_upload_bytes",
1383 | "format": "table",
1384 | "hide": false,
1385 | "instant": true,
1386 | "legendFormat": "Upload Speed",
1387 | "range": false,
1388 | "refId": "I"
1389 | },
1390 | {
1391 | "datasource": {
1392 | "type": "prometheus",
1393 | "uid": "PBFA97CFB590B2093"
1394 | },
1395 | "editorMode": "code",
1396 | "exemplar": false,
1397 | "expr": "transmission_torrent_download_bytes",
1398 | "format": "table",
1399 | "hide": false,
1400 | "instant": true,
1401 | "legendFormat": "Download Speed",
1402 | "range": false,
1403 | "refId": "J"
1404 | }
1405 | ],
1406 | "title": "Torrents",
1407 | "transformations": [
1408 | {
1409 | "id": "concatenate",
1410 | "options": {
1411 | "frameNameLabel": "",
1412 | "frameNameMode": "drop"
1413 | }
1414 | },
1415 | {
1416 | "id": "filterFieldsByName",
1417 | "options": {
1418 | "byVariable": false,
1419 | "include": {
1420 | "names": [
1421 | "name 1",
1422 | "Value #A",
1423 | "Value #B",
1424 | "Value #C",
1425 | "Value #D",
1426 | "Value #E",
1427 | "Value #F",
1428 | "Value #G",
1429 | "Value #H",
1430 | "Value #J",
1431 | "Value #I"
1432 | ]
1433 | }
1434 | }
1435 | },
1436 | {
1437 | "id": "organize",
1438 | "options": {
1439 | "excludeByName": {},
1440 | "includeByName": {},
1441 | "indexByName": {
1442 | "Value #A": 8,
1443 | "Value #B": 1,
1444 | "Value #C": 4,
1445 | "Value #D": 7,
1446 | "Value #E": 6,
1447 | "Value #F": 9,
1448 | "Value #G": 5,
1449 | "Value #H": 10,
1450 | "Value #I": 3,
1451 | "Value #J": 2,
1452 | "name 1": 0
1453 | },
1454 | "renameByName": {
1455 | "Value #A": "Date Added",
1456 | "Value #B": "Progress",
1457 | "Value #C": "Bytes Downloaded",
1458 | "Value #D": "Leechers",
1459 | "Value #E": "Seeders",
1460 | "Value #F": "Ratio",
1461 | "Value #G": "Bytes Uploaded",
1462 | "Value #H": "Status",
1463 | "Value #I": "Upload Speed",
1464 | "Value #J": "Download Speed",
1465 | "name 1": "Name"
1466 | }
1467 | }
1468 | }
1469 | ],
1470 | "type": "table"
1471 | },
1472 | {
1473 | "datasource": {
1474 | "type": "prometheus",
1475 | "uid": "PBFA97CFB590B2093"
1476 | },
1477 | "fieldConfig": {
1478 | "defaults": {
1479 | "decimals": 2,
1480 | "mappings": [
1481 | {
1482 | "from": "",
1483 | "id": 2,
1484 | "operator": "",
1485 | "text": "N/A",
1486 | "to": "",
1487 | "type": 1,
1488 | "value": "null"
1489 | }
1490 | ],
1491 | "max": 1,
1492 | "min": 0,
1493 | "thresholds": {
1494 | "mode": "absolute",
1495 | "steps": [
1496 | {
1497 | "color": "dark-red",
1498 | "value": null
1499 | },
1500 | {
1501 | "color": "dark-orange",
1502 | "value": 0.25
1503 | },
1504 | {
1505 | "color": "#EAB839",
1506 | "value": 0.5
1507 | },
1508 | {
1509 | "color": "semi-dark-green",
1510 | "value": 0.75
1511 | },
1512 | {
1513 | "color": "rgb(206, 206, 206)",
1514 | "value": 1
1515 | }
1516 | ]
1517 | },
1518 | "unit": "percentunit"
1519 | },
1520 | "overrides": []
1521 | },
1522 | "gridPos": {
1523 | "h": 10,
1524 | "w": 24,
1525 | "x": 0,
1526 | "y": 30
1527 | },
1528 | "id": 22,
1529 | "options": {
1530 | "displayMode": "lcd",
1531 | "maxVizHeight": 300,
1532 | "minVizHeight": 16,
1533 | "minVizWidth": 8,
1534 | "namePlacement": "auto",
1535 | "orientation": "horizontal",
1536 | "reduceOptions": {
1537 | "calcs": [
1538 | "lastNotNull"
1539 | ],
1540 | "fields": "",
1541 | "values": false
1542 | },
1543 | "showUnfilled": true,
1544 | "sizing": "auto",
1545 | "text": {},
1546 | "valueMode": "color"
1547 | },
1548 | "pluginVersion": "10.4.3",
1549 | "targets": [
1550 | {
1551 | "datasource": {
1552 | "type": "prometheus",
1553 | "uid": "PBFA97CFB590B2093"
1554 | },
1555 | "editorMode": "code",
1556 | "expr": "transmission_torrent_done < 1",
1557 | "instant": true,
1558 | "legendFormat": "{{name}}",
1559 | "refId": "A"
1560 | }
1561 | ],
1562 | "title": "Incomplete Torrents",
1563 | "type": "bargauge"
1564 | }
1565 | ],
1566 | "schemaVersion": 39,
1567 | "tags": [],
1568 | "templating": {
1569 | "list": []
1570 | },
1571 | "time": {
1572 | "from": "now-1h",
1573 | "to": "now"
1574 | },
1575 | "timepicker": {
1576 | "refresh_intervals": [
1577 | "5s",
1578 | "10s",
1579 | "30s",
1580 | "1m",
1581 | "5m",
1582 | "15m",
1583 | "30m",
1584 | "1h",
1585 | "2h",
1586 | "1d"
1587 | ]
1588 | },
1589 | "timezone": "",
1590 | "title": "Transmission",
1591 | "uid": "OEyH9tQZk",
1592 | "version": 52,
1593 | "weekStart": ""
1594 | }
1595 |
--------------------------------------------------------------------------------
/dashboards/jsonnetfile.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": [
3 | {
4 | "name": "grafana-builder",
5 | "source": {
6 | "git": {
7 | "remote": "https://github.com/grafana/jsonnet-libs",
8 | "subdir": "grafana-builder"
9 | }
10 | },
11 | "version": "master"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/dashboards/transmission.json:
--------------------------------------------------------------------------------
1 | {
2 | "annotations": {
3 | "list": [ ]
4 | },
5 | "editable": true,
6 | "gnetId": null,
7 | "graphTooltip": 0,
8 | "hideControls": false,
9 | "links": [ ],
10 | "refresh": "10s",
11 | "rows": [
12 | {
13 | "collapse": false,
14 | "height": "250px",
15 | "panels": [
16 | {
17 | "aliasColors": { },
18 | "bars": false,
19 | "dashLength": 10,
20 | "dashes": false,
21 | "datasource": "$datasource",
22 | "fill": 10,
23 | "id": 0,
24 | "legend": {
25 | "avg": false,
26 | "current": false,
27 | "max": false,
28 | "min": false,
29 | "show": true,
30 | "total": false,
31 | "values": false
32 | },
33 | "lines": true,
34 | "linewidth": 0,
35 | "links": [ ],
36 | "nullPointMode": "null as zero",
37 | "percentage": false,
38 | "pointradius": 5,
39 | "points": false,
40 | "renderer": "flot",
41 | "seriesOverrides": [ ],
42 | "spaceLength": 10,
43 | "span": 12,
44 | "stack": true,
45 | "steppedLine": false,
46 | "targets": [
47 | {
48 | "expr": "max(transmission_torrent_download_bytes{name=~\"$torrent\"}) by (name) > 0",
49 | "format": "time_series",
50 | "intervalFactor": 2,
51 | "legendFormat": "{{name}}",
52 | "legendLink": null,
53 | "step": 10
54 | }
55 | ],
56 | "thresholds": [ ],
57 | "timeFrom": null,
58 | "timeShift": null,
59 | "title": "Downloads (bytes/second)",
60 | "tooltip": {
61 | "shared": true,
62 | "sort": 0,
63 | "value_type": "individual"
64 | },
65 | "type": "graph",
66 | "xaxis": {
67 | "buckets": null,
68 | "mode": "time",
69 | "name": null,
70 | "show": true,
71 | "values": [ ]
72 | },
73 | "yaxes": [
74 | {
75 | "format": "bytes",
76 | "label": null,
77 | "logBase": 1,
78 | "max": null,
79 | "min": 0,
80 | "show": true
81 | },
82 | {
83 | "format": "short",
84 | "label": null,
85 | "logBase": 1,
86 | "max": null,
87 | "min": null,
88 | "show": false
89 | }
90 | ]
91 | }
92 | ],
93 | "repeat": null,
94 | "repeatIteration": null,
95 | "repeatRowId": null,
96 | "showTitle": true,
97 | "title": "Downloads",
98 | "titleSize": "h6"
99 | },
100 | {
101 | "collapse": false,
102 | "height": "250px",
103 | "panels": [
104 | {
105 | "aliasColors": { },
106 | "bars": false,
107 | "dashLength": 10,
108 | "dashes": false,
109 | "datasource": "$datasource",
110 | "fill": 10,
111 | "id": 1,
112 | "legend": {
113 | "avg": false,
114 | "current": false,
115 | "max": false,
116 | "min": false,
117 | "show": true,
118 | "total": false,
119 | "values": false
120 | },
121 | "lines": true,
122 | "linewidth": 0,
123 | "links": [ ],
124 | "nullPointMode": "null as zero",
125 | "percentage": false,
126 | "pointradius": 5,
127 | "points": false,
128 | "renderer": "flot",
129 | "seriesOverrides": [ ],
130 | "spaceLength": 10,
131 | "span": 12,
132 | "stack": true,
133 | "steppedLine": false,
134 | "targets": [
135 | {
136 | "expr": "max(transmission_torrent_upload_bytes{name=~\"$torrent\"}) by (name) > 0",
137 | "format": "time_series",
138 | "intervalFactor": 2,
139 | "legendFormat": "{{name}}",
140 | "legendLink": null,
141 | "step": 10
142 | }
143 | ],
144 | "thresholds": [ ],
145 | "timeFrom": null,
146 | "timeShift": null,
147 | "title": "Uploads (bytes/second)",
148 | "tooltip": {
149 | "shared": true,
150 | "sort": 0,
151 | "value_type": "individual"
152 | },
153 | "type": "graph",
154 | "xaxis": {
155 | "buckets": null,
156 | "mode": "time",
157 | "name": null,
158 | "show": true,
159 | "values": [ ]
160 | },
161 | "yaxes": [
162 | {
163 | "format": "bytes",
164 | "label": null,
165 | "logBase": 1,
166 | "max": null,
167 | "min": 0,
168 | "show": true
169 | },
170 | {
171 | "format": "short",
172 | "label": null,
173 | "logBase": 1,
174 | "max": null,
175 | "min": null,
176 | "show": false
177 | }
178 | ]
179 | }
180 | ],
181 | "repeat": null,
182 | "repeatIteration": null,
183 | "repeatRowId": null,
184 | "showTitle": true,
185 | "title": "Upload",
186 | "titleSize": "h6"
187 | },
188 | {
189 | "collapse": false,
190 | "height": "250px",
191 | "panels": [
192 | {
193 | "aliasColors": { },
194 | "bars": false,
195 | "dashLength": 10,
196 | "dashes": false,
197 | "datasource": "$datasource",
198 | "fill": 1,
199 | "id": 2,
200 | "legend": {
201 | "avg": false,
202 | "current": false,
203 | "max": false,
204 | "min": false,
205 | "show": true,
206 | "total": false,
207 | "values": false
208 | },
209 | "lines": true,
210 | "linewidth": 1,
211 | "links": [ ],
212 | "nullPointMode": "null as zero",
213 | "percentage": false,
214 | "pointradius": 5,
215 | "points": false,
216 | "renderer": "flot",
217 | "seriesOverrides": [ ],
218 | "spaceLength": 10,
219 | "span": 12,
220 | "stack": false,
221 | "steppedLine": false,
222 | "styles": [
223 | {
224 | "alias": "Time",
225 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
226 | "pattern": "Time",
227 | "type": "hidden"
228 | },
229 | {
230 | "alias": "Progress",
231 | "colorMode": null,
232 | "colors": [ ],
233 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
234 | "decimals": 2,
235 | "link": false,
236 | "linkTooltip": "Drill down",
237 | "linkUrl": "",
238 | "pattern": "Value #A",
239 | "thresholds": [ ],
240 | "type": "number",
241 | "unit": "percentunit"
242 | },
243 | {
244 | "alias": "Ratio",
245 | "colorMode": null,
246 | "colors": [ ],
247 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
248 | "decimals": 2,
249 | "link": false,
250 | "linkTooltip": "Drill down",
251 | "linkUrl": "",
252 | "pattern": "Value #B",
253 | "thresholds": [ ],
254 | "type": "number",
255 | "unit": "short"
256 | },
257 | {
258 | "alias": "Leechers",
259 | "colorMode": null,
260 | "colors": [ ],
261 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
262 | "decimals": 2,
263 | "link": false,
264 | "linkTooltip": "Drill down",
265 | "linkUrl": "",
266 | "pattern": "Value #C",
267 | "thresholds": [ ],
268 | "type": "number",
269 | "unit": "short"
270 | },
271 | {
272 | "alias": "Seeders",
273 | "colorMode": null,
274 | "colors": [ ],
275 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
276 | "decimals": 2,
277 | "link": false,
278 | "linkTooltip": "Drill down",
279 | "linkUrl": "",
280 | "pattern": "Value #D",
281 | "thresholds": [ ],
282 | "type": "number",
283 | "unit": "short"
284 | },
285 | {
286 | "alias": "",
287 | "colorMode": null,
288 | "colors": [ ],
289 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
290 | "decimals": 2,
291 | "pattern": "/.*/",
292 | "thresholds": [ ],
293 | "type": "string",
294 | "unit": "short"
295 | }
296 | ],
297 | "targets": [
298 | {
299 | "expr": "max(transmission_torrent_done{name=~\"$torrent\"}) by (name)",
300 | "format": "table",
301 | "instant": true,
302 | "intervalFactor": 2,
303 | "legendFormat": "",
304 | "refId": "A",
305 | "step": 10
306 | },
307 | {
308 | "expr": "max(transmission_torrent_ratio{name=~\"$torrent\"}) by (name)",
309 | "format": "table",
310 | "instant": true,
311 | "intervalFactor": 2,
312 | "legendFormat": "",
313 | "refId": "B",
314 | "step": 10
315 | },
316 | {
317 | "expr": "max(transmission_torrent_leechers{name=~\"$torrent\"}) by (name)",
318 | "format": "table",
319 | "instant": true,
320 | "intervalFactor": 2,
321 | "legendFormat": "",
322 | "refId": "C",
323 | "step": 10
324 | },
325 | {
326 | "expr": "max(transmission_torrent_seeders{name=~\"$torrent\"}) by (name)",
327 | "format": "table",
328 | "instant": true,
329 | "intervalFactor": 2,
330 | "legendFormat": "",
331 | "refId": "D",
332 | "step": 10
333 | }
334 | ],
335 | "thresholds": [ ],
336 | "timeFrom": null,
337 | "timeShift": null,
338 | "title": "Overview",
339 | "tooltip": {
340 | "shared": true,
341 | "sort": 0,
342 | "value_type": "individual"
343 | },
344 | "transform": "table",
345 | "type": "table",
346 | "xaxis": {
347 | "buckets": null,
348 | "mode": "time",
349 | "name": null,
350 | "show": true,
351 | "values": [ ]
352 | },
353 | "yaxes": [
354 | {
355 | "format": "short",
356 | "label": null,
357 | "logBase": 1,
358 | "max": null,
359 | "min": 0,
360 | "show": true
361 | },
362 | {
363 | "format": "short",
364 | "label": null,
365 | "logBase": 1,
366 | "max": null,
367 | "min": null,
368 | "show": false
369 | }
370 | ]
371 | }
372 | ],
373 | "repeat": null,
374 | "repeatIteration": null,
375 | "repeatRowId": null,
376 | "showTitle": true,
377 | "title": "Torrents",
378 | "titleSize": "h6"
379 | }
380 | ],
381 | "schemaVersion": 14,
382 | "style": "dark",
383 | "tags": [ ],
384 | "templating": {
385 | "list": [
386 | {
387 | "current": {
388 | "text": "Prometheus",
389 | "value": "Prometheus"
390 | },
391 | "hide": 0,
392 | "label": null,
393 | "name": "datasource",
394 | "options": [ ],
395 | "query": "prometheus",
396 | "refresh": 1,
397 | "regex": "",
398 | "type": "datasource"
399 | },
400 | {
401 | "allValue": null,
402 | "current": {
403 | "selected": true,
404 | "text": "All",
405 | "value": "$__all"
406 | },
407 | "datasource": "$datasource",
408 | "hide": 0,
409 | "includeAll": true,
410 | "label": "torrent",
411 | "multi": true,
412 | "name": "torrent",
413 | "options": [ ],
414 | "query": "label_values(transmission_torrent_added, name)",
415 | "refresh": 1,
416 | "regex": "",
417 | "sort": 2,
418 | "tagValuesQuery": "",
419 | "tags": [ ],
420 | "tagsQuery": "",
421 | "type": "query",
422 | "useTags": false
423 | }
424 | ]
425 | },
426 | "time": {
427 | "from": "now-1h",
428 | "to": "now"
429 | },
430 | "timepicker": {
431 | "refresh_intervals": [
432 | "5s",
433 | "10s",
434 | "30s",
435 | "1m",
436 | "5m",
437 | "15m",
438 | "30m",
439 | "1h",
440 | "2h",
441 | "1d"
442 | ],
443 | "time_options": [
444 | "5m",
445 | "15m",
446 | "1h",
447 | "6h",
448 | "12h",
449 | "24h",
450 | "2d",
451 | "7d",
452 | "30d"
453 | ]
454 | },
455 | "timezone": "utc",
456 | "title": "Transmission",
457 | "uid": "",
458 | "version": 0
459 | }
460 |
--------------------------------------------------------------------------------
/dashboards/transmission.jsonnet:
--------------------------------------------------------------------------------
1 | local g = import 'grafana-builder/grafana.libsonnet';
2 |
3 | {
4 | grafanaDashboards+:: {
5 | 'transmission.json':
6 | g.dashboard(
7 | 'Transmission',
8 | )
9 | .addMultiTemplate('torrent', 'transmission_torrent_added', 'name')
10 | .addRow(
11 | g.row('Downloads')
12 | .addPanel(
13 | g.panel('Downloads (bytes/second)') +
14 | g.queryPanel('max(transmission_torrent_download_bytes{name=~"$torrent"}) by (name) > 0', '{{name}}') +
15 | g.stack +
16 | { yaxes: g.yaxes('bytes') },
17 | )
18 | )
19 | .addRow(
20 | g.row('Upload')
21 | .addPanel(
22 | g.panel('Uploads (bytes/second)') +
23 | g.queryPanel('max(transmission_torrent_upload_bytes{name=~"$torrent"}) by (name) > 0', '{{name}}') +
24 | g.stack +
25 | { yaxes: g.yaxes('bytes') },
26 | )
27 | )
28 | .addRow(
29 | g.row('Torrents')
30 | .addPanel(
31 | g.panel('Overview') +
32 | g.tablePanel([
33 | 'max(transmission_torrent_done{name=~"$torrent"}) by (name)',
34 | 'max(transmission_torrent_ratio{name=~"$torrent"}) by (name)',
35 | 'max(transmission_torrent_leechers{name=~"$torrent"}) by (name)',
36 | 'max(transmission_torrent_seeders{name=~"$torrent"}) by (name)',
37 | ], {
38 | 'Value #A': { alias: 'Progress', unit: 'percentunit' },
39 | 'Value #B': { alias: 'Ratio' },
40 | 'Value #C': { alias: 'Leechers' },
41 | 'Value #D': { alias: 'Seeders' },
42 | })
43 | )
44 | ),
45 | },
46 | }
47 |
--------------------------------------------------------------------------------
/dashboards/transmission2024.json:
--------------------------------------------------------------------------------
1 | {
2 | "__inputs": [
3 | {
4 | "name": "DS_PROMETHEUS",
5 | "label": "Prometheus",
6 | "description": "",
7 | "type": "datasource",
8 | "pluginId": "prometheus",
9 | "pluginName": "Prometheus"
10 | }
11 | ],
12 | "__elements": {},
13 | "__requires": [
14 | {
15 | "type": "grafana",
16 | "id": "grafana",
17 | "name": "Grafana",
18 | "version": "11.2.0"
19 | },
20 | {
21 | "type": "datasource",
22 | "id": "prometheus",
23 | "name": "Prometheus",
24 | "version": "1.0.0"
25 | },
26 | {
27 | "type": "panel",
28 | "id": "stat",
29 | "name": "Stat",
30 | "version": ""
31 | },
32 | {
33 | "type": "panel",
34 | "id": "table",
35 | "name": "Table",
36 | "version": ""
37 | },
38 | {
39 | "type": "panel",
40 | "id": "timeseries",
41 | "name": "Time series",
42 | "version": ""
43 | }
44 | ],
45 | "annotations": {
46 | "list": [
47 | {
48 | "builtIn": 1,
49 | "datasource": {
50 | "type": "datasource",
51 | "uid": "grafana"
52 | },
53 | "enable": true,
54 | "hide": true,
55 | "iconColor": "rgba(0, 211, 255, 1)",
56 | "name": "Annotations & Alerts",
57 | "type": "dashboard"
58 | }
59 | ]
60 | },
61 | "description": "Transmission statistics prometheus dashboard ",
62 | "editable": true,
63 | "fiscalYearStartMonth": 0,
64 | "gnetId": 8259,
65 | "graphTooltip": 0,
66 | "id": null,
67 | "links": [],
68 | "panels": [
69 | {
70 | "datasource": {
71 | "type": "prometheus",
72 | "uid": "${DS_PROMETHEUS}"
73 | },
74 | "fieldConfig": {
75 | "defaults": {
76 | "mappings": [
77 | {
78 | "options": {
79 | "match": "null",
80 | "result": {
81 | "text": "N/A"
82 | }
83 | },
84 | "type": "special"
85 | }
86 | ],
87 | "thresholds": {
88 | "mode": "absolute",
89 | "steps": [
90 | {
91 | "color": "green",
92 | "value": null
93 | },
94 | {
95 | "color": "red",
96 | "value": 80
97 | }
98 | ]
99 | },
100 | "unit": "none"
101 | },
102 | "overrides": []
103 | },
104 | "gridPos": {
105 | "h": 4,
106 | "w": 5,
107 | "x": 0,
108 | "y": 0
109 | },
110 | "id": 13,
111 | "maxDataPoints": 100,
112 | "options": {
113 | "colorMode": "none",
114 | "graphMode": "none",
115 | "justifyMode": "auto",
116 | "orientation": "horizontal",
117 | "percentChangeColorMode": "standard",
118 | "reduceOptions": {
119 | "calcs": [
120 | "mean"
121 | ],
122 | "fields": "",
123 | "values": false
124 | },
125 | "showPercentChange": false,
126 | "textMode": "auto",
127 | "wideLayout": true
128 | },
129 | "pluginVersion": "11.2.0",
130 | "targets": [
131 | {
132 | "datasource": {
133 | "type": "prometheus",
134 | "uid": "${DS_PROMETHEUS}"
135 | },
136 | "editorMode": "code",
137 | "exemplar": false,
138 | "expr": "count(transmission_torrent_done)",
139 | "format": "time_series",
140 | "instant": true,
141 | "intervalFactor": 1,
142 | "range": false,
143 | "refId": "A"
144 | }
145 | ],
146 | "title": "Number of torrents",
147 | "type": "stat"
148 | },
149 | {
150 | "datasource": {
151 | "type": "prometheus",
152 | "uid": "${DS_PROMETHEUS}"
153 | },
154 | "fieldConfig": {
155 | "defaults": {
156 | "color": {
157 | "fixedColor": "blue",
158 | "mode": "shades"
159 | },
160 | "mappings": [
161 | {
162 | "options": {
163 | "match": "null",
164 | "result": {
165 | "text": "N/A"
166 | }
167 | },
168 | "type": "special"
169 | }
170 | ],
171 | "thresholds": {
172 | "mode": "absolute",
173 | "steps": [
174 | {
175 | "color": "green",
176 | "value": null
177 | },
178 | {
179 | "color": "red",
180 | "value": 80
181 | }
182 | ]
183 | },
184 | "unit": "bytes"
185 | },
186 | "overrides": []
187 | },
188 | "gridPos": {
189 | "h": 4,
190 | "w": 2,
191 | "x": 5,
192 | "y": 0
193 | },
194 | "id": 6,
195 | "maxDataPoints": 100,
196 | "options": {
197 | "colorMode": "value",
198 | "graphMode": "none",
199 | "justifyMode": "auto",
200 | "orientation": "horizontal",
201 | "percentChangeColorMode": "standard",
202 | "reduceOptions": {
203 | "calcs": [
204 | "mean"
205 | ],
206 | "fields": "",
207 | "values": false
208 | },
209 | "showPercentChange": false,
210 | "textMode": "auto",
211 | "wideLayout": true
212 | },
213 | "pluginVersion": "11.2.0",
214 | "targets": [
215 | {
216 | "datasource": {
217 | "type": "prometheus",
218 | "uid": "${DS_PROMETHEUS}"
219 | },
220 | "editorMode": "code",
221 | "expr": "transmission_session_stats_uploaded_bytes{type=\"current\"}",
222 | "format": "time_series",
223 | "intervalFactor": 1,
224 | "range": true,
225 | "refId": "A"
226 | }
227 | ],
228 | "title": "Current upload",
229 | "type": "stat"
230 | },
231 | {
232 | "datasource": {
233 | "type": "prometheus",
234 | "uid": "${DS_PROMETHEUS}"
235 | },
236 | "fieldConfig": {
237 | "defaults": {
238 | "color": {
239 | "fixedColor": "blue",
240 | "mode": "fixed"
241 | },
242 | "mappings": [
243 | {
244 | "options": {
245 | "match": "null",
246 | "result": {
247 | "text": "N/A"
248 | }
249 | },
250 | "type": "special"
251 | }
252 | ],
253 | "thresholds": {
254 | "mode": "absolute",
255 | "steps": [
256 | {
257 | "color": "green",
258 | "value": null
259 | },
260 | {
261 | "color": "red",
262 | "value": 80
263 | }
264 | ]
265 | },
266 | "unit": "bytes"
267 | },
268 | "overrides": []
269 | },
270 | "gridPos": {
271 | "h": 4,
272 | "w": 3,
273 | "x": 7,
274 | "y": 0
275 | },
276 | "id": 22,
277 | "maxDataPoints": 100,
278 | "options": {
279 | "colorMode": "value",
280 | "graphMode": "area",
281 | "justifyMode": "auto",
282 | "orientation": "horizontal",
283 | "percentChangeColorMode": "standard",
284 | "reduceOptions": {
285 | "calcs": [
286 | "lastNotNull"
287 | ],
288 | "fields": "",
289 | "values": false
290 | },
291 | "showPercentChange": false,
292 | "textMode": "auto",
293 | "wideLayout": true
294 | },
295 | "pluginVersion": "11.2.0",
296 | "targets": [
297 | {
298 | "datasource": {
299 | "type": "prometheus",
300 | "uid": "${DS_PROMETHEUS}"
301 | },
302 | "editorMode": "code",
303 | "expr": "sum (increase(transmission_session_stats_uploaded_bytes{type=\"cumulative\"}[1d]))",
304 | "format": "time_series",
305 | "intervalFactor": 1,
306 | "legendFormat": "__auto",
307 | "range": true,
308 | "refId": "A"
309 | }
310 | ],
311 | "title": "1 day upload",
312 | "type": "stat"
313 | },
314 | {
315 | "datasource": {
316 | "type": "prometheus",
317 | "uid": "${DS_PROMETHEUS}"
318 | },
319 | "fieldConfig": {
320 | "defaults": {
321 | "color": {
322 | "fixedColor": "blue",
323 | "mode": "fixed"
324 | },
325 | "mappings": [
326 | {
327 | "options": {
328 | "match": "null",
329 | "result": {
330 | "text": "N/A"
331 | }
332 | },
333 | "type": "special"
334 | }
335 | ],
336 | "thresholds": {
337 | "mode": "absolute",
338 | "steps": [
339 | {
340 | "color": "green",
341 | "value": null
342 | },
343 | {
344 | "color": "red",
345 | "value": 80
346 | }
347 | ]
348 | },
349 | "unit": "bytes"
350 | },
351 | "overrides": []
352 | },
353 | "gridPos": {
354 | "h": 4,
355 | "w": 3,
356 | "x": 10,
357 | "y": 0
358 | },
359 | "id": 23,
360 | "maxDataPoints": 100,
361 | "options": {
362 | "colorMode": "value",
363 | "graphMode": "area",
364 | "justifyMode": "auto",
365 | "orientation": "horizontal",
366 | "percentChangeColorMode": "standard",
367 | "reduceOptions": {
368 | "calcs": [
369 | "lastNotNull"
370 | ],
371 | "fields": "",
372 | "values": false
373 | },
374 | "showPercentChange": false,
375 | "textMode": "auto",
376 | "wideLayout": true
377 | },
378 | "pluginVersion": "11.2.0",
379 | "targets": [
380 | {
381 | "datasource": {
382 | "type": "prometheus",
383 | "uid": "${DS_PROMETHEUS}"
384 | },
385 | "editorMode": "code",
386 | "expr": "sum (increase(transmission_session_stats_uploaded_bytes{type=\"cumulative\"}[7d]))",
387 | "format": "time_series",
388 | "intervalFactor": 1,
389 | "legendFormat": "__auto",
390 | "range": true,
391 | "refId": "A"
392 | }
393 | ],
394 | "title": "7 days upload",
395 | "type": "stat"
396 | },
397 | {
398 | "datasource": {
399 | "type": "prometheus",
400 | "uid": "${DS_PROMETHEUS}"
401 | },
402 | "fieldConfig": {
403 | "defaults": {
404 | "color": {
405 | "fixedColor": "blue",
406 | "mode": "fixed"
407 | },
408 | "mappings": [
409 | {
410 | "options": {
411 | "match": "null",
412 | "result": {
413 | "text": "N/A"
414 | }
415 | },
416 | "type": "special"
417 | }
418 | ],
419 | "thresholds": {
420 | "mode": "absolute",
421 | "steps": [
422 | {
423 | "color": "green",
424 | "value": null
425 | },
426 | {
427 | "color": "red",
428 | "value": 80
429 | }
430 | ]
431 | },
432 | "unit": "bytes"
433 | },
434 | "overrides": []
435 | },
436 | "gridPos": {
437 | "h": 4,
438 | "w": 5,
439 | "x": 13,
440 | "y": 0
441 | },
442 | "id": 5,
443 | "maxDataPoints": 100,
444 | "options": {
445 | "colorMode": "value",
446 | "graphMode": "area",
447 | "justifyMode": "auto",
448 | "orientation": "horizontal",
449 | "percentChangeColorMode": "standard",
450 | "reduceOptions": {
451 | "calcs": [
452 | "lastNotNull"
453 | ],
454 | "fields": "",
455 | "values": false
456 | },
457 | "showPercentChange": false,
458 | "textMode": "auto",
459 | "wideLayout": true
460 | },
461 | "pluginVersion": "11.2.0",
462 | "targets": [
463 | {
464 | "datasource": {
465 | "type": "prometheus",
466 | "uid": "${DS_PROMETHEUS}"
467 | },
468 | "editorMode": "code",
469 | "expr": "transmission_session_stats_uploaded_bytes{type=\"cumulative\"}",
470 | "format": "time_series",
471 | "intervalFactor": 1,
472 | "range": true,
473 | "refId": "A"
474 | }
475 | ],
476 | "title": "Total upload",
477 | "type": "stat"
478 | },
479 | {
480 | "datasource": {
481 | "type": "prometheus",
482 | "uid": "${DS_PROMETHEUS}"
483 | },
484 | "description": "",
485 | "fieldConfig": {
486 | "defaults": {
487 | "color": {
488 | "fixedColor": "blue",
489 | "mode": "fixed"
490 | },
491 | "mappings": [],
492 | "thresholds": {
493 | "mode": "absolute",
494 | "steps": [
495 | {
496 | "color": "green",
497 | "value": null
498 | },
499 | {
500 | "color": "red",
501 | "value": 80
502 | }
503 | ]
504 | },
505 | "unit": "binBps"
506 | },
507 | "overrides": []
508 | },
509 | "gridPos": {
510 | "h": 4,
511 | "w": 6,
512 | "x": 18,
513 | "y": 0
514 | },
515 | "id": 18,
516 | "options": {
517 | "colorMode": "value",
518 | "graphMode": "area",
519 | "justifyMode": "auto",
520 | "orientation": "auto",
521 | "percentChangeColorMode": "standard",
522 | "reduceOptions": {
523 | "calcs": [
524 | "lastNotNull"
525 | ],
526 | "fields": "",
527 | "values": false
528 | },
529 | "showPercentChange": false,
530 | "textMode": "auto",
531 | "wideLayout": true
532 | },
533 | "pluginVersion": "11.2.0",
534 | "targets": [
535 | {
536 | "datasource": {
537 | "type": "prometheus",
538 | "uid": "${DS_PROMETHEUS}"
539 | },
540 | "editorMode": "code",
541 | "exemplar": false,
542 | "expr": "sum (transmission_torrent_upload_bytes{name=~\"$Torrent\"})",
543 | "instant": false,
544 | "legendFormat": "__auto",
545 | "range": true,
546 | "refId": "A"
547 | }
548 | ],
549 | "title": "Current upload speed",
550 | "type": "stat"
551 | },
552 | {
553 | "datasource": {
554 | "type": "prometheus",
555 | "uid": "${DS_PROMETHEUS}"
556 | },
557 | "fieldConfig": {
558 | "defaults": {
559 | "color": {
560 | "fixedColor": "rgb(31, 120, 193)",
561 | "mode": "thresholds"
562 | },
563 | "mappings": [
564 | {
565 | "options": {
566 | "match": "null",
567 | "result": {
568 | "text": "N/A"
569 | }
570 | },
571 | "type": "special"
572 | }
573 | ],
574 | "thresholds": {
575 | "mode": "absolute",
576 | "steps": [
577 | {
578 | "color": "red",
579 | "value": null
580 | },
581 | {
582 | "color": "green",
583 | "value": 1
584 | }
585 | ]
586 | },
587 | "unit": "none"
588 | },
589 | "overrides": []
590 | },
591 | "gridPos": {
592 | "h": 4,
593 | "w": 2,
594 | "x": 0,
595 | "y": 4
596 | },
597 | "id": 10,
598 | "maxDataPoints": 100,
599 | "options": {
600 | "colorMode": "value",
601 | "graphMode": "area",
602 | "justifyMode": "auto",
603 | "orientation": "horizontal",
604 | "percentChangeColorMode": "standard",
605 | "reduceOptions": {
606 | "calcs": [
607 | "lastNotNull"
608 | ],
609 | "fields": "",
610 | "values": false
611 | },
612 | "showPercentChange": false,
613 | "textMode": "auto",
614 | "wideLayout": true
615 | },
616 | "pluginVersion": "11.2.0",
617 | "targets": [
618 | {
619 | "datasource": {
620 | "type": "prometheus",
621 | "uid": "${DS_PROMETHEUS}"
622 | },
623 | "expr": "transmission_session_stats_uploaded_bytes{type=\"current\"}/transmission_session_stats_downloaded_bytes{type=\"current\"}",
624 | "format": "time_series",
625 | "intervalFactor": 1,
626 | "refId": "A"
627 | }
628 | ],
629 | "title": "Current ratio",
630 | "type": "stat"
631 | },
632 | {
633 | "datasource": {
634 | "type": "prometheus",
635 | "uid": "${DS_PROMETHEUS}"
636 | },
637 | "description": "",
638 | "fieldConfig": {
639 | "defaults": {
640 | "mappings": [
641 | {
642 | "options": {
643 | "match": "null",
644 | "result": {
645 | "text": "N/A"
646 | }
647 | },
648 | "type": "special"
649 | }
650 | ],
651 | "thresholds": {
652 | "mode": "absolute",
653 | "steps": [
654 | {
655 | "color": "red",
656 | "value": null
657 | },
658 | {
659 | "color": "green",
660 | "value": 1
661 | }
662 | ]
663 | },
664 | "unit": "none"
665 | },
666 | "overrides": []
667 | },
668 | "gridPos": {
669 | "h": 4,
670 | "w": 3,
671 | "x": 2,
672 | "y": 4
673 | },
674 | "id": 11,
675 | "maxDataPoints": 100,
676 | "options": {
677 | "colorMode": "value",
678 | "graphMode": "area",
679 | "justifyMode": "auto",
680 | "orientation": "horizontal",
681 | "percentChangeColorMode": "standard",
682 | "reduceOptions": {
683 | "calcs": [
684 | "lastNotNull"
685 | ],
686 | "fields": "",
687 | "values": false
688 | },
689 | "showPercentChange": false,
690 | "textMode": "auto",
691 | "wideLayout": true
692 | },
693 | "pluginVersion": "11.2.0",
694 | "targets": [
695 | {
696 | "datasource": {
697 | "type": "prometheus",
698 | "uid": "${DS_PROMETHEUS}"
699 | },
700 | "expr": "transmission_session_stats_uploaded_bytes{type=\"cumulative\"}/transmission_session_stats_downloaded_bytes{type=\"cumulative\"}",
701 | "format": "time_series",
702 | "intervalFactor": 1,
703 | "refId": "A"
704 | }
705 | ],
706 | "title": "Cumulative ratio",
707 | "type": "stat"
708 | },
709 | {
710 | "datasource": {
711 | "type": "prometheus",
712 | "uid": "${DS_PROMETHEUS}"
713 | },
714 | "fieldConfig": {
715 | "defaults": {
716 | "color": {
717 | "fixedColor": "purple",
718 | "mode": "fixed"
719 | },
720 | "mappings": [
721 | {
722 | "options": {
723 | "match": "null",
724 | "result": {
725 | "text": "N/A"
726 | }
727 | },
728 | "type": "special"
729 | }
730 | ],
731 | "thresholds": {
732 | "mode": "absolute",
733 | "steps": [
734 | {
735 | "color": "green",
736 | "value": null
737 | },
738 | {
739 | "color": "red",
740 | "value": 80
741 | }
742 | ]
743 | },
744 | "unit": "bytes"
745 | },
746 | "overrides": []
747 | },
748 | "gridPos": {
749 | "h": 4,
750 | "w": 2,
751 | "x": 5,
752 | "y": 4
753 | },
754 | "id": 3,
755 | "maxDataPoints": 100,
756 | "options": {
757 | "colorMode": "value",
758 | "graphMode": "none",
759 | "justifyMode": "auto",
760 | "orientation": "horizontal",
761 | "percentChangeColorMode": "standard",
762 | "reduceOptions": {
763 | "calcs": [
764 | "mean"
765 | ],
766 | "fields": "",
767 | "values": false
768 | },
769 | "showPercentChange": false,
770 | "textMode": "auto",
771 | "wideLayout": true
772 | },
773 | "pluginVersion": "11.2.0",
774 | "targets": [
775 | {
776 | "datasource": {
777 | "type": "prometheus",
778 | "uid": "${DS_PROMETHEUS}"
779 | },
780 | "editorMode": "code",
781 | "expr": "transmission_session_stats_downloaded_bytes{type=\"current\"}",
782 | "format": "time_series",
783 | "intervalFactor": 1,
784 | "range": true,
785 | "refId": "A"
786 | }
787 | ],
788 | "title": "Current download",
789 | "type": "stat"
790 | },
791 | {
792 | "datasource": {
793 | "type": "prometheus",
794 | "uid": "${DS_PROMETHEUS}"
795 | },
796 | "fieldConfig": {
797 | "defaults": {
798 | "color": {
799 | "fixedColor": "purple",
800 | "mode": "fixed"
801 | },
802 | "mappings": [
803 | {
804 | "options": {
805 | "match": "null",
806 | "result": {
807 | "text": "N/A"
808 | }
809 | },
810 | "type": "special"
811 | }
812 | ],
813 | "thresholds": {
814 | "mode": "absolute",
815 | "steps": [
816 | {
817 | "color": "green",
818 | "value": null
819 | },
820 | {
821 | "color": "red",
822 | "value": 80
823 | }
824 | ]
825 | },
826 | "unit": "bytes"
827 | },
828 | "overrides": []
829 | },
830 | "gridPos": {
831 | "h": 4,
832 | "w": 3,
833 | "x": 7,
834 | "y": 4
835 | },
836 | "id": 24,
837 | "maxDataPoints": 100,
838 | "options": {
839 | "colorMode": "value",
840 | "graphMode": "area",
841 | "justifyMode": "auto",
842 | "orientation": "horizontal",
843 | "percentChangeColorMode": "standard",
844 | "reduceOptions": {
845 | "calcs": [
846 | "lastNotNull"
847 | ],
848 | "fields": "",
849 | "values": false
850 | },
851 | "showPercentChange": false,
852 | "textMode": "auto",
853 | "wideLayout": true
854 | },
855 | "pluginVersion": "11.2.0",
856 | "targets": [
857 | {
858 | "datasource": {
859 | "type": "prometheus",
860 | "uid": "${DS_PROMETHEUS}"
861 | },
862 | "editorMode": "code",
863 | "expr": "sum (increase(transmission_session_stats_downloaded_bytes{type=\"cumulative\"}[1d]))",
864 | "format": "time_series",
865 | "intervalFactor": 1,
866 | "legendFormat": "__auto",
867 | "range": true,
868 | "refId": "A"
869 | }
870 | ],
871 | "title": "1 day download",
872 | "type": "stat"
873 | },
874 | {
875 | "datasource": {
876 | "type": "prometheus",
877 | "uid": "${DS_PROMETHEUS}"
878 | },
879 | "description": "",
880 | "fieldConfig": {
881 | "defaults": {
882 | "color": {
883 | "fixedColor": "purple",
884 | "mode": "fixed"
885 | },
886 | "mappings": [
887 | {
888 | "options": {
889 | "match": "null",
890 | "result": {
891 | "text": "N/A"
892 | }
893 | },
894 | "type": "special"
895 | }
896 | ],
897 | "thresholds": {
898 | "mode": "absolute",
899 | "steps": [
900 | {
901 | "color": "green",
902 | "value": null
903 | },
904 | {
905 | "color": "red",
906 | "value": 80
907 | }
908 | ]
909 | },
910 | "unit": "bytes"
911 | },
912 | "overrides": []
913 | },
914 | "gridPos": {
915 | "h": 4,
916 | "w": 3,
917 | "x": 10,
918 | "y": 4
919 | },
920 | "id": 25,
921 | "maxDataPoints": 100,
922 | "options": {
923 | "colorMode": "value",
924 | "graphMode": "area",
925 | "justifyMode": "auto",
926 | "orientation": "horizontal",
927 | "percentChangeColorMode": "standard",
928 | "reduceOptions": {
929 | "calcs": [
930 | "lastNotNull"
931 | ],
932 | "fields": "",
933 | "values": false
934 | },
935 | "showPercentChange": false,
936 | "textMode": "auto",
937 | "wideLayout": true
938 | },
939 | "pluginVersion": "11.2.0",
940 | "targets": [
941 | {
942 | "datasource": {
943 | "type": "prometheus",
944 | "uid": "${DS_PROMETHEUS}"
945 | },
946 | "editorMode": "code",
947 | "expr": "sum (increase(transmission_session_stats_downloaded_bytes{type=\"cumulative\"}[7d]))",
948 | "format": "time_series",
949 | "intervalFactor": 1,
950 | "legendFormat": "__auto",
951 | "range": true,
952 | "refId": "A"
953 | }
954 | ],
955 | "title": "7 days download",
956 | "type": "stat"
957 | },
958 | {
959 | "datasource": {
960 | "type": "prometheus",
961 | "uid": "${DS_PROMETHEUS}"
962 | },
963 | "fieldConfig": {
964 | "defaults": {
965 | "color": {
966 | "fixedColor": "purple",
967 | "mode": "fixed"
968 | },
969 | "mappings": [
970 | {
971 | "options": {
972 | "match": "null",
973 | "result": {
974 | "text": "N/A"
975 | }
976 | },
977 | "type": "special"
978 | }
979 | ],
980 | "thresholds": {
981 | "mode": "absolute",
982 | "steps": [
983 | {
984 | "color": "green",
985 | "value": null
986 | },
987 | {
988 | "color": "red",
989 | "value": 80
990 | }
991 | ]
992 | },
993 | "unit": "bytes"
994 | },
995 | "overrides": []
996 | },
997 | "gridPos": {
998 | "h": 4,
999 | "w": 5,
1000 | "x": 13,
1001 | "y": 4
1002 | },
1003 | "id": 4,
1004 | "maxDataPoints": 100,
1005 | "options": {
1006 | "colorMode": "value",
1007 | "graphMode": "area",
1008 | "justifyMode": "auto",
1009 | "orientation": "horizontal",
1010 | "percentChangeColorMode": "standard",
1011 | "reduceOptions": {
1012 | "calcs": [
1013 | "lastNotNull"
1014 | ],
1015 | "fields": "",
1016 | "values": false
1017 | },
1018 | "showPercentChange": false,
1019 | "textMode": "auto",
1020 | "wideLayout": true
1021 | },
1022 | "pluginVersion": "11.2.0",
1023 | "targets": [
1024 | {
1025 | "datasource": {
1026 | "type": "prometheus",
1027 | "uid": "${DS_PROMETHEUS}"
1028 | },
1029 | "expr": "transmission_session_stats_downloaded_bytes{type=\"cumulative\"}",
1030 | "format": "time_series",
1031 | "intervalFactor": 1,
1032 | "refId": "A"
1033 | }
1034 | ],
1035 | "title": "Total download",
1036 | "type": "stat"
1037 | },
1038 | {
1039 | "datasource": {
1040 | "type": "prometheus",
1041 | "uid": "${DS_PROMETHEUS}"
1042 | },
1043 | "description": "",
1044 | "fieldConfig": {
1045 | "defaults": {
1046 | "color": {
1047 | "fixedColor": "purple",
1048 | "mode": "fixed"
1049 | },
1050 | "mappings": [],
1051 | "thresholds": {
1052 | "mode": "absolute",
1053 | "steps": [
1054 | {
1055 | "color": "green",
1056 | "value": null
1057 | },
1058 | {
1059 | "color": "red",
1060 | "value": 80
1061 | }
1062 | ]
1063 | },
1064 | "unit": "binBps"
1065 | },
1066 | "overrides": []
1067 | },
1068 | "gridPos": {
1069 | "h": 4,
1070 | "w": 6,
1071 | "x": 18,
1072 | "y": 4
1073 | },
1074 | "id": 21,
1075 | "options": {
1076 | "colorMode": "value",
1077 | "graphMode": "area",
1078 | "justifyMode": "auto",
1079 | "orientation": "auto",
1080 | "percentChangeColorMode": "standard",
1081 | "reduceOptions": {
1082 | "calcs": [
1083 | "lastNotNull"
1084 | ],
1085 | "fields": "",
1086 | "values": false
1087 | },
1088 | "showPercentChange": false,
1089 | "textMode": "auto",
1090 | "wideLayout": true
1091 | },
1092 | "pluginVersion": "11.2.0",
1093 | "targets": [
1094 | {
1095 | "datasource": {
1096 | "type": "prometheus",
1097 | "uid": "${DS_PROMETHEUS}"
1098 | },
1099 | "editorMode": "code",
1100 | "exemplar": false,
1101 | "expr": "sum (transmission_torrent_download_bytes{name=~\"$Torrent\"})",
1102 | "instant": false,
1103 | "legendFormat": "__auto",
1104 | "range": true,
1105 | "refId": "A"
1106 | }
1107 | ],
1108 | "title": "Current download speed",
1109 | "type": "stat"
1110 | },
1111 | {
1112 | "datasource": {
1113 | "type": "prometheus",
1114 | "uid": "${DS_PROMETHEUS}"
1115 | },
1116 | "fieldConfig": {
1117 | "defaults": {
1118 | "color": {
1119 | "mode": "palette-classic"
1120 | },
1121 | "custom": {
1122 | "axisBorderShow": false,
1123 | "axisCenteredZero": false,
1124 | "axisColorMode": "text",
1125 | "axisLabel": "",
1126 | "axisPlacement": "auto",
1127 | "barAlignment": 0,
1128 | "barWidthFactor": 0.6,
1129 | "drawStyle": "line",
1130 | "fillOpacity": 72,
1131 | "gradientMode": "none",
1132 | "hideFrom": {
1133 | "legend": false,
1134 | "tooltip": false,
1135 | "viz": false
1136 | },
1137 | "insertNulls": false,
1138 | "lineInterpolation": "linear",
1139 | "lineWidth": 1,
1140 | "pointSize": 5,
1141 | "scaleDistribution": {
1142 | "type": "linear"
1143 | },
1144 | "showPoints": "auto",
1145 | "spanNulls": false,
1146 | "stacking": {
1147 | "group": "A",
1148 | "mode": "normal"
1149 | },
1150 | "thresholdsStyle": {
1151 | "mode": "off"
1152 | }
1153 | },
1154 | "mappings": [],
1155 | "thresholds": {
1156 | "mode": "absolute",
1157 | "steps": [
1158 | {
1159 | "color": "green",
1160 | "value": null
1161 | },
1162 | {
1163 | "color": "red",
1164 | "value": 80
1165 | }
1166 | ]
1167 | },
1168 | "unit": "binBps"
1169 | },
1170 | "overrides": []
1171 | },
1172 | "gridPos": {
1173 | "h": 9,
1174 | "w": 24,
1175 | "x": 0,
1176 | "y": 8
1177 | },
1178 | "id": 14,
1179 | "options": {
1180 | "legend": {
1181 | "calcs": [
1182 | "lastNotNull",
1183 | "mean"
1184 | ],
1185 | "displayMode": "table",
1186 | "placement": "right",
1187 | "showLegend": true,
1188 | "sortBy": "Mean",
1189 | "sortDesc": true
1190 | },
1191 | "tooltip": {
1192 | "mode": "single",
1193 | "sort": "none"
1194 | }
1195 | },
1196 | "targets": [
1197 | {
1198 | "datasource": {
1199 | "type": "prometheus",
1200 | "uid": "${DS_PROMETHEUS}"
1201 | },
1202 | "editorMode": "code",
1203 | "expr": "transmission_torrent_upload_bytes{name=~\"$Torrent\"}",
1204 | "instant": false,
1205 | "legendFormat": "{{name}}",
1206 | "range": true,
1207 | "refId": "A"
1208 | }
1209 | ],
1210 | "title": "Upload rate / minute",
1211 | "type": "timeseries"
1212 | },
1213 | {
1214 | "datasource": {
1215 | "type": "prometheus",
1216 | "uid": "${DS_PROMETHEUS}"
1217 | },
1218 | "description": "",
1219 | "fieldConfig": {
1220 | "defaults": {
1221 | "color": {
1222 | "fixedColor": "text",
1223 | "mode": "fixed"
1224 | },
1225 | "custom": {
1226 | "align": "auto",
1227 | "cellOptions": {
1228 | "type": "color-text"
1229 | },
1230 | "inspect": false
1231 | },
1232 | "fieldMinMax": true,
1233 | "mappings": [],
1234 | "thresholds": {
1235 | "mode": "absolute",
1236 | "steps": [
1237 | {
1238 | "color": "red",
1239 | "value": null
1240 | },
1241 | {
1242 | "color": "yellow",
1243 | "value": 10000
1244 | },
1245 | {
1246 | "color": "green",
1247 | "value": 1000000
1248 | }
1249 | ]
1250 | }
1251 | },
1252 | "overrides": [
1253 | {
1254 | "matcher": {
1255 | "id": "byName",
1256 | "options": "Avg Upload 30 days"
1257 | },
1258 | "properties": [
1259 | {
1260 | "id": "custom.cellOptions",
1261 | "value": {
1262 | "mode": "lcd",
1263 | "type": "gauge"
1264 | }
1265 | },
1266 | {
1267 | "id": "unit",
1268 | "value": "bytes"
1269 | },
1270 | {
1271 | "id": "color"
1272 | }
1273 | ]
1274 | },
1275 | {
1276 | "matcher": {
1277 | "id": "byName",
1278 | "options": "Ratio"
1279 | },
1280 | "properties": [
1281 | {
1282 | "id": "custom.cellOptions",
1283 | "value": {
1284 | "mode": "gradient",
1285 | "type": "color-background"
1286 | }
1287 | },
1288 | {
1289 | "id": "decimals",
1290 | "value": 2
1291 | },
1292 | {
1293 | "id": "thresholds",
1294 | "value": {
1295 | "mode": "absolute",
1296 | "steps": [
1297 | {
1298 | "color": "red",
1299 | "value": null
1300 | },
1301 | {
1302 | "color": "#EAB839",
1303 | "value": 1
1304 | },
1305 | {
1306 | "color": "green",
1307 | "value": 2
1308 | }
1309 | ]
1310 | }
1311 | },
1312 | {
1313 | "id": "custom.width",
1314 | "value": 80
1315 | },
1316 | {
1317 | "id": "color"
1318 | }
1319 | ]
1320 | },
1321 | {
1322 | "matcher": {
1323 | "id": "byName",
1324 | "options": "Torrrent name"
1325 | },
1326 | "properties": [
1327 | {
1328 | "id": "custom.width",
1329 | "value": 300
1330 | }
1331 | ]
1332 | },
1333 | {
1334 | "matcher": {
1335 | "id": "byName",
1336 | "options": "id"
1337 | },
1338 | "properties": [
1339 | {
1340 | "id": "custom.width",
1341 | "value": 30
1342 | }
1343 | ]
1344 | },
1345 | {
1346 | "matcher": {
1347 | "id": "byName",
1348 | "options": "Files"
1349 | },
1350 | "properties": [
1351 | {
1352 | "id": "custom.width",
1353 | "value": 30
1354 | }
1355 | ]
1356 | },
1357 | {
1358 | "matcher": {
1359 | "id": "byName",
1360 | "options": "Seeders (avg)"
1361 | },
1362 | "properties": [
1363 | {
1364 | "id": "custom.width",
1365 | "value": 75
1366 | },
1367 | {
1368 | "id": "decimals",
1369 | "value": 0
1370 | },
1371 | {
1372 | "id": "color",
1373 | "value": {
1374 | "fixedColor": "green",
1375 | "mode": "fixed"
1376 | }
1377 | }
1378 | ]
1379 | },
1380 | {
1381 | "matcher": {
1382 | "id": "byName",
1383 | "options": "Leechers (avg)"
1384 | },
1385 | "properties": [
1386 | {
1387 | "id": "custom.width",
1388 | "value": 80
1389 | },
1390 | {
1391 | "id": "decimals",
1392 | "value": 0
1393 | },
1394 | {
1395 | "id": "color",
1396 | "value": {
1397 | "fixedColor": "red",
1398 | "mode": "shades"
1399 | }
1400 | }
1401 | ]
1402 | },
1403 | {
1404 | "matcher": {
1405 | "id": "byName",
1406 | "options": "Added"
1407 | },
1408 | "properties": [
1409 | {
1410 | "id": "custom.width",
1411 | "value": 100
1412 | },
1413 | {
1414 | "id": "unit",
1415 | "value": "dateTimeFromNow"
1416 | }
1417 | ]
1418 | },
1419 | {
1420 | "matcher": {
1421 | "id": "byName",
1422 | "options": "Downloads"
1423 | },
1424 | "properties": [
1425 | {
1426 | "id": "custom.width",
1427 | "value": 95
1428 | }
1429 | ]
1430 | },
1431 | {
1432 | "matcher": {
1433 | "id": "byName",
1434 | "options": "Current upload"
1435 | },
1436 | "properties": [
1437 | {
1438 | "id": "custom.cellOptions",
1439 | "value": {
1440 | "mode": "gradient",
1441 | "type": "gauge"
1442 | }
1443 | },
1444 | {
1445 | "id": "color",
1446 | "value": {
1447 | "mode": "continuous-RdYlGr"
1448 | }
1449 | },
1450 | {
1451 | "id": "unit",
1452 | "value": "binBps"
1453 | }
1454 | ]
1455 | },
1456 | {
1457 | "matcher": {
1458 | "id": "byName",
1459 | "options": "Avg upload 1 day"
1460 | },
1461 | "properties": [
1462 | {
1463 | "id": "custom.cellOptions",
1464 | "value": {
1465 | "mode": "lcd",
1466 | "type": "gauge"
1467 | }
1468 | },
1469 | {
1470 | "id": "unit",
1471 | "value": "binBps"
1472 | },
1473 | {
1474 | "id": "color"
1475 | }
1476 | ]
1477 | },
1478 | {
1479 | "matcher": {
1480 | "id": "byName",
1481 | "options": "Peers connected"
1482 | },
1483 | "properties": [
1484 | {
1485 | "id": "custom.width",
1486 | "value": 75
1487 | },
1488 | {
1489 | "id": "color"
1490 | },
1491 | {
1492 | "id": "thresholds",
1493 | "value": {
1494 | "mode": "absolute",
1495 | "steps": [
1496 | {
1497 | "color": "text",
1498 | "value": null
1499 | },
1500 | {
1501 | "color": "green",
1502 | "value": 1
1503 | }
1504 | ]
1505 | }
1506 | }
1507 | ]
1508 | },
1509 | {
1510 | "matcher": {
1511 | "id": "byName",
1512 | "options": "Peers DL (downloading from us)"
1513 | },
1514 | "properties": [
1515 | {
1516 | "id": "custom.width",
1517 | "value": 75
1518 | },
1519 | {
1520 | "id": "color"
1521 | },
1522 | {
1523 | "id": "thresholds",
1524 | "value": {
1525 | "mode": "absolute",
1526 | "steps": [
1527 | {
1528 | "color": "text",
1529 | "value": null
1530 | },
1531 | {
1532 | "color": "green",
1533 | "value": 1
1534 | }
1535 | ]
1536 | }
1537 | }
1538 | ]
1539 | },
1540 | {
1541 | "matcher": {
1542 | "id": "byName",
1543 | "options": "Size"
1544 | },
1545 | "properties": [
1546 | {
1547 | "id": "unit",
1548 | "value": "bytes"
1549 | },
1550 | {
1551 | "id": "custom.width",
1552 | "value": 75
1553 | }
1554 | ]
1555 | },
1556 | {
1557 | "matcher": {
1558 | "id": "byName",
1559 | "options": "Uploaded"
1560 | },
1561 | "properties": [
1562 | {
1563 | "id": "unit",
1564 | "value": "bytes"
1565 | },
1566 | {
1567 | "id": "custom.width",
1568 | "value": 80
1569 | }
1570 | ]
1571 | }
1572 | ]
1573 | },
1574 | "gridPos": {
1575 | "h": 22,
1576 | "w": 24,
1577 | "x": 0,
1578 | "y": 17
1579 | },
1580 | "id": 15,
1581 | "options": {
1582 | "cellHeight": "sm",
1583 | "footer": {
1584 | "countRows": false,
1585 | "fields": "",
1586 | "reducer": [
1587 | "sum"
1588 | ],
1589 | "show": false
1590 | },
1591 | "showHeader": true,
1592 | "sortBy": [
1593 | {
1594 | "desc": true,
1595 | "displayName": "Avg upload 1 day"
1596 | }
1597 | ]
1598 | },
1599 | "pluginVersion": "11.2.0",
1600 | "targets": [
1601 | {
1602 | "datasource": {
1603 | "type": "prometheus",
1604 | "uid": "${DS_PROMETHEUS}"
1605 | },
1606 | "editorMode": "code",
1607 | "exemplar": false,
1608 | "expr": "avg_over_time (transmission_torrent_upload_bytes{name=~\"$Torrent\"}[30d])",
1609 | "format": "table",
1610 | "instant": true,
1611 | "legendFormat": "{{name}}",
1612 | "range": false,
1613 | "refId": "A"
1614 | },
1615 | {
1616 | "datasource": {
1617 | "type": "prometheus",
1618 | "uid": "${DS_PROMETHEUS}"
1619 | },
1620 | "editorMode": "code",
1621 | "exemplar": false,
1622 | "expr": "transmission_torrent_ratio{name=~\"$Torrent\"}",
1623 | "format": "table",
1624 | "hide": false,
1625 | "instant": true,
1626 | "legendFormat": "{{name}}",
1627 | "range": false,
1628 | "refId": "B"
1629 | },
1630 | {
1631 | "datasource": {
1632 | "type": "prometheus",
1633 | "uid": "${DS_PROMETHEUS}"
1634 | },
1635 | "editorMode": "code",
1636 | "exemplar": false,
1637 | "expr": "transmission_torrent_files_total{name=~\"$Torrent\"}",
1638 | "format": "table",
1639 | "hide": false,
1640 | "instant": true,
1641 | "legendFormat": "__auto",
1642 | "range": false,
1643 | "refId": "C"
1644 | },
1645 | {
1646 | "datasource": {
1647 | "type": "prometheus",
1648 | "uid": "${DS_PROMETHEUS}"
1649 | },
1650 | "editorMode": "code",
1651 | "exemplar": false,
1652 | "expr": "avg_over_time (transmission_torrent_seeders{name=~\"$Torrent\"}[30d])",
1653 | "format": "table",
1654 | "hide": false,
1655 | "instant": true,
1656 | "legendFormat": "{{name}}",
1657 | "range": false,
1658 | "refId": "D"
1659 | },
1660 | {
1661 | "datasource": {
1662 | "type": "prometheus",
1663 | "uid": "${DS_PROMETHEUS}"
1664 | },
1665 | "editorMode": "code",
1666 | "exemplar": false,
1667 | "expr": "avg_over_time (transmission_torrent_leechers{name=~\"$Torrent\"}[30d])",
1668 | "format": "table",
1669 | "hide": false,
1670 | "instant": true,
1671 | "legendFormat": "{{name}}",
1672 | "range": false,
1673 | "refId": "E"
1674 | },
1675 | {
1676 | "datasource": {
1677 | "type": "prometheus",
1678 | "uid": "${DS_PROMETHEUS}"
1679 | },
1680 | "editorMode": "code",
1681 | "exemplar": false,
1682 | "expr": "transmission_torrent_added{name=~\"$Torrent\"} * 1000",
1683 | "format": "table",
1684 | "hide": false,
1685 | "instant": true,
1686 | "legendFormat": "{{name}}",
1687 | "range": false,
1688 | "refId": "F"
1689 | },
1690 | {
1691 | "datasource": {
1692 | "type": "prometheus",
1693 | "uid": "${DS_PROMETHEUS}"
1694 | },
1695 | "editorMode": "code",
1696 | "exemplar": false,
1697 | "expr": "transmission_torrent_downloads_total{name=~\"$Torrent\"}",
1698 | "format": "table",
1699 | "hide": false,
1700 | "instant": true,
1701 | "legendFormat": "{{name}}",
1702 | "range": false,
1703 | "refId": "G"
1704 | },
1705 | {
1706 | "datasource": {
1707 | "type": "prometheus",
1708 | "uid": "${DS_PROMETHEUS}"
1709 | },
1710 | "editorMode": "code",
1711 | "exemplar": false,
1712 | "expr": "transmission_torrent_upload_bytes{name=~\"$Torrent\"}",
1713 | "format": "table",
1714 | "hide": false,
1715 | "instant": true,
1716 | "legendFormat": "{{name}}",
1717 | "range": false,
1718 | "refId": "H"
1719 | },
1720 | {
1721 | "datasource": {
1722 | "type": "prometheus",
1723 | "uid": "${DS_PROMETHEUS}"
1724 | },
1725 | "editorMode": "code",
1726 | "exemplar": false,
1727 | "expr": "avg_over_time (transmission_torrent_upload_bytes{name=~\"$Torrent\"}[1d])",
1728 | "format": "table",
1729 | "hide": false,
1730 | "instant": true,
1731 | "legendFormat": "{{name}}",
1732 | "range": false,
1733 | "refId": "I"
1734 | },
1735 | {
1736 | "datasource": {
1737 | "type": "prometheus",
1738 | "uid": "${DS_PROMETHEUS}"
1739 | },
1740 | "editorMode": "code",
1741 | "exemplar": false,
1742 | "expr": "transmission_torrent_peers_connected{name=~\"$Torrent\"}",
1743 | "format": "table",
1744 | "hide": false,
1745 | "instant": true,
1746 | "legendFormat": "{{name}}",
1747 | "range": false,
1748 | "refId": "J"
1749 | },
1750 | {
1751 | "datasource": {
1752 | "type": "prometheus",
1753 | "uid": "${DS_PROMETHEUS}"
1754 | },
1755 | "editorMode": "code",
1756 | "exemplar": false,
1757 | "expr": "transmission_torrent_peers_getting_from_us{name=~\"$Torrent\"}",
1758 | "format": "table",
1759 | "hide": false,
1760 | "instant": true,
1761 | "legendFormat": "{{name}}",
1762 | "range": false,
1763 | "refId": "K"
1764 | },
1765 | {
1766 | "datasource": {
1767 | "type": "prometheus",
1768 | "uid": "${DS_PROMETHEUS}"
1769 | },
1770 | "editorMode": "code",
1771 | "exemplar": false,
1772 | "expr": "transmission_torrent_total_size{name=~\"$Torrent\"}",
1773 | "format": "table",
1774 | "hide": false,
1775 | "instant": true,
1776 | "legendFormat": "{{name}}",
1777 | "range": false,
1778 | "refId": "L"
1779 | },
1780 | {
1781 | "datasource": {
1782 | "type": "prometheus",
1783 | "uid": "${DS_PROMETHEUS}"
1784 | },
1785 | "editorMode": "code",
1786 | "exemplar": false,
1787 | "expr": "transmission_torrent_uploaded_ever{name=~\"$Torrent\"}",
1788 | "format": "table",
1789 | "hide": false,
1790 | "instant": true,
1791 | "legendFormat": "{{name}}",
1792 | "range": false,
1793 | "refId": "M"
1794 | }
1795 | ],
1796 | "title": "Torrents stats",
1797 | "transformations": [
1798 | {
1799 | "id": "joinByField",
1800 | "options": {
1801 | "byField": "id",
1802 | "mode": "outer"
1803 | }
1804 | },
1805 | {
1806 | "id": "sortBy",
1807 | "options": {
1808 | "fields": {},
1809 | "sort": [
1810 | {
1811 | "desc": true,
1812 | "field": "Value #A"
1813 | }
1814 | ]
1815 | }
1816 | },
1817 | {
1818 | "id": "organize",
1819 | "options": {
1820 | "excludeByName": {
1821 | "Time 1": true,
1822 | "Time 10": true,
1823 | "Time 11": true,
1824 | "Time 12": true,
1825 | "Time 13": true,
1826 | "Time 2": true,
1827 | "Time 3": true,
1828 | "Time 4": true,
1829 | "Time 5": true,
1830 | "Time 6": true,
1831 | "Time 7": true,
1832 | "Time 8": true,
1833 | "Time 9": true,
1834 | "Value #C": true,
1835 | "Value #G": true,
1836 | "__name__": true,
1837 | "__name__ 1": true,
1838 | "__name__ 2": true,
1839 | "__name__ 3": true,
1840 | "__name__ 4": true,
1841 | "__name__ 5": true,
1842 | "__name__ 6": true,
1843 | "__name__ 7": true,
1844 | "__name__ 8": true,
1845 | "chain 1": true,
1846 | "chain 10": true,
1847 | "chain 11": true,
1848 | "chain 12": true,
1849 | "chain 13": true,
1850 | "chain 2": true,
1851 | "chain 3": true,
1852 | "chain 4": true,
1853 | "chain 5": true,
1854 | "chain 6": true,
1855 | "chain 7": true,
1856 | "chain 8": true,
1857 | "chain 9": true,
1858 | "id 1": true,
1859 | "id 2": true,
1860 | "instance 1": true,
1861 | "instance 10": true,
1862 | "instance 11": true,
1863 | "instance 12": true,
1864 | "instance 13": true,
1865 | "instance 2": true,
1866 | "instance 3": true,
1867 | "instance 4": true,
1868 | "instance 5": true,
1869 | "instance 6": true,
1870 | "instance 7": true,
1871 | "instance 8": true,
1872 | "instance 9": true,
1873 | "job 1": true,
1874 | "job 10": true,
1875 | "job 11": true,
1876 | "job 12": true,
1877 | "job 13": true,
1878 | "job 2": true,
1879 | "job 3": true,
1880 | "job 4": true,
1881 | "job 5": true,
1882 | "job 6": true,
1883 | "job 7": true,
1884 | "job 8": true,
1885 | "job 9": true,
1886 | "name 1": false,
1887 | "name 10": true,
1888 | "name 11": true,
1889 | "name 12": true,
1890 | "name 13": true,
1891 | "name 2": true,
1892 | "name 3": true,
1893 | "name 4": true,
1894 | "name 5": true,
1895 | "name 6": true,
1896 | "name 7": true,
1897 | "name 8": true,
1898 | "name 9": true,
1899 | "tracker": true,
1900 | "tracker 1": true,
1901 | "tracker 2": true,
1902 | "tracker 3": true
1903 | },
1904 | "includeByName": {},
1905 | "indexByName": {
1906 | "Time 1": 15,
1907 | "Time 10": 66,
1908 | "Time 11": 72,
1909 | "Time 12": 78,
1910 | "Time 13": 84,
1911 | "Time 2": 19,
1912 | "Time 3": 25,
1913 | "Time 4": 31,
1914 | "Time 5": 37,
1915 | "Time 6": 43,
1916 | "Time 7": 48,
1917 | "Time 8": 55,
1918 | "Time 9": 61,
1919 | "Value #A": 14,
1920 | "Value #B": 8,
1921 | "Value #C": 4,
1922 | "Value #D": 5,
1923 | "Value #E": 6,
1924 | "Value #F": 2,
1925 | "Value #G": 7,
1926 | "Value #H": 12,
1927 | "Value #I": 13,
1928 | "Value #J": 10,
1929 | "Value #K": 11,
1930 | "Value #L": 3,
1931 | "Value #M": 9,
1932 | "__name__ 1": 24,
1933 | "__name__ 2": 26,
1934 | "__name__ 3": 49,
1935 | "__name__ 4": 56,
1936 | "__name__ 5": 67,
1937 | "__name__ 6": 73,
1938 | "__name__ 7": 79,
1939 | "__name__ 8": 85,
1940 | "chain 1": 16,
1941 | "chain 10": 68,
1942 | "chain 11": 74,
1943 | "chain 12": 80,
1944 | "chain 13": 86,
1945 | "chain 2": 20,
1946 | "chain 3": 27,
1947 | "chain 4": 32,
1948 | "chain 5": 38,
1949 | "chain 6": 44,
1950 | "chain 7": 50,
1951 | "chain 8": 57,
1952 | "chain 9": 62,
1953 | "id": 0,
1954 | "instance 1": 17,
1955 | "instance 10": 69,
1956 | "instance 11": 75,
1957 | "instance 12": 81,
1958 | "instance 13": 87,
1959 | "instance 2": 21,
1960 | "instance 3": 28,
1961 | "instance 4": 33,
1962 | "instance 5": 39,
1963 | "instance 6": 45,
1964 | "instance 7": 51,
1965 | "instance 8": 58,
1966 | "instance 9": 63,
1967 | "job 1": 18,
1968 | "job 10": 70,
1969 | "job 11": 76,
1970 | "job 12": 82,
1971 | "job 13": 88,
1972 | "job 2": 22,
1973 | "job 3": 29,
1974 | "job 4": 34,
1975 | "job 5": 40,
1976 | "job 6": 46,
1977 | "job 7": 52,
1978 | "job 8": 59,
1979 | "job 9": 64,
1980 | "name 1": 1,
1981 | "name 10": 71,
1982 | "name 11": 77,
1983 | "name 12": 83,
1984 | "name 13": 89,
1985 | "name 2": 23,
1986 | "name 3": 30,
1987 | "name 4": 35,
1988 | "name 5": 41,
1989 | "name 6": 47,
1990 | "name 7": 53,
1991 | "name 8": 60,
1992 | "name 9": 65,
1993 | "tracker 1": 36,
1994 | "tracker 2": 42,
1995 | "tracker 3": 54
1996 | },
1997 | "renameByName": {
1998 | "Time 2": "",
1999 | "Value #A": "Avg Upload 30 days",
2000 | "Value #B": "Ratio",
2001 | "Value #C": "Files",
2002 | "Value #D": "Seeders (avg)",
2003 | "Value #E": "Leechers (avg)",
2004 | "Value #F": "Added",
2005 | "Value #G": "Downloads",
2006 | "Value #H": "Current upload",
2007 | "Value #I": "Avg upload 1 day",
2008 | "Value #J": "Peers connected",
2009 | "Value #K": "Peers DL (downloading from us)",
2010 | "Value #L": "Size",
2011 | "Value #M": "Uploaded",
2012 | "name": "Torrent",
2013 | "name 1": "Torrrent name",
2014 | "name 10": "",
2015 | "tracker": "",
2016 | "tracker 3": ""
2017 | }
2018 | }
2019 | },
2020 | {
2021 | "id": "convertFieldType",
2022 | "options": {
2023 | "conversions": [
2024 | {
2025 | "dateFormat": "$(UNIX)",
2026 | "destinationType": "time",
2027 | "targetField": "Added"
2028 | }
2029 | ],
2030 | "fields": {}
2031 | }
2032 | }
2033 | ],
2034 | "type": "table"
2035 | }
2036 | ],
2037 | "refresh": "10s",
2038 | "schemaVersion": 39,
2039 | "tags": [
2040 | "prometheus",
2041 | "transmission"
2042 | ],
2043 | "templating": {
2044 | "list": [
2045 | {
2046 | "current": {},
2047 | "datasource": {
2048 | "type": "prometheus",
2049 | "uid": "${DS_PROMETHEUS}"
2050 | },
2051 | "definition": "label_values(transmission_torrent_ratio,name)",
2052 | "hide": 0,
2053 | "includeAll": true,
2054 | "multi": true,
2055 | "name": "Torrent",
2056 | "options": [],
2057 | "query": {
2058 | "qryType": 1,
2059 | "query": "label_values(transmission_torrent_ratio,name)",
2060 | "refId": "PrometheusVariableQueryEditor-VariableQuery"
2061 | },
2062 | "refresh": 1,
2063 | "regex": "",
2064 | "skipUrlSync": false,
2065 | "sort": 0,
2066 | "tagValuesQuery": "",
2067 | "tagsQuery": "",
2068 | "type": "query",
2069 | "useTags": false
2070 | }
2071 | ]
2072 | },
2073 | "time": {
2074 | "from": "now-1h",
2075 | "to": "now"
2076 | },
2077 | "timepicker": {
2078 | "refresh_intervals": [
2079 | "5s",
2080 | "10s",
2081 | "30s",
2082 | "1m",
2083 | "5m",
2084 | "15m",
2085 | "30m",
2086 | "1h",
2087 | "2h",
2088 | "1d"
2089 | ],
2090 | "time_options": [
2091 | "5m",
2092 | "15m",
2093 | "1h",
2094 | "6h",
2095 | "12h",
2096 | "24h",
2097 | "2d",
2098 | "7d",
2099 | "30d"
2100 | ]
2101 | },
2102 | "timezone": "",
2103 | "title": "Transmission",
2104 | "uid": "y_TlWHJiz",
2105 | "version": 25,
2106 | "weekStart": ""
2107 | }
--------------------------------------------------------------------------------
/examples/docker-compose.yml:
--------------------------------------------------------------------------------
1 | transmission:
2 | image: linuxserver/transmission
3 | restart: always
4 | ports:
5 | - "127.0.0.1:9091:9091"
6 | - "51413:51413"
7 | - "51413:51413/udp"
8 |
9 | transmission-exporter:
10 | image: metalmatze/transmission-exporter
11 | restart: always
12 | links:
13 | - transmission
14 | ports:
15 | - "127.0.0.1:19091:19091"
16 | environment:
17 | TRANSMISSION_ADDR: http://transmission:9091
18 |
19 | prometheus:
20 | image: quay.io/prometheus/prometheus
21 | command: "-config.file=/etc/prometheus/prometheus.yml"
22 | links:
23 | - transmission-exporter
24 | ports:
25 | - "127.0.0.1:9090:9090"
26 | volumes:
27 | - "./prometheus:/etc/prometheus/"
28 |
--------------------------------------------------------------------------------
/examples/kubernetes/transmission.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: transmission
6 | ---
7 | apiVersion: extensions/v1beta1
8 | kind: Deployment
9 | metadata:
10 | name: transmission
11 | namespace: transmission
12 | spec:
13 | replicas: 1
14 | selector:
15 | matchLabels:
16 | name: transmission
17 | template:
18 | metadata:
19 | labels:
20 | name: transmission
21 | annotations:
22 | prometheus.io/scrape: 'true'
23 | prometheus.io/port: '9190'
24 | spec:
25 | containers:
26 | - image: linuxserver/transmission
27 | imagePullPolicy: Always
28 | name: transmission
29 | env:
30 | - name: PGID
31 | value: "1000"
32 | - name: "PUID"
33 | value: "1000"
34 | - name: "TZ"
35 | value: "Europe/London"
36 | resources:
37 | limits:
38 | cpu: 2000m
39 | memory: 2000Mi
40 | requests:
41 | cpu: 1000m
42 | memory: 1000Mi
43 | ports:
44 | - name: default-http
45 | containerPort: 9091
46 | - name: dht
47 | containerPort: 51413
48 | - name: dht-udp
49 | containerPort: 51413
50 | protocol: UDP
51 | # You should assign these to some real volumes
52 | # volumeMounts:
53 | # - name: downloads
54 | # mountPath: "/downloads"
55 | # - name: config
56 | # mountPath: "/config"
57 | - image: metalmatze/transmission-exporter
58 | name: transmission-exporter
59 | imagePullPolicy: Always
60 | resources:
61 | limits:
62 | cpu: 100m
63 | memory: 100Mi
64 | requests:
65 | cpu: 50m
66 | memory: 50Mi
67 | ports:
68 | - name: prom-scrape
69 | containerPort: 9190
70 | env:
71 | - name: TRANSMISSION_ADDR
72 | value: "http://localhost:9091"
73 | # Uncomment these once you add authentication to transmission
74 | # - name: TRANSMISSION_USERNAME
75 | # value: "transmission"
76 | # You can use a tool like `kontemplate` + `pass` to avoid hardcoding this in your repo
77 | # - name: TRANSMISSION_PASSWORD
78 | # value: "hunter2"
79 | - name: WEB_PATH
80 | value: "/metrics"
81 | - name: WEB_ADDR
82 | value: ":9190"
83 | # You should create some real PVCs for this
84 | #
85 | # volumes:
86 | # - name: downloads
87 | # persistentVolumeClaim:
88 | # claimName: transmission-downloads
89 | # - name: config
90 | # persistentVolumeClaim:
91 | # claimName: transmission-config
92 | ---
93 | apiVersion: v1
94 | kind: Service
95 | metadata:
96 | namespace: transmission
97 | name: transmission
98 | spec:
99 | selector:
100 | name: transmission
101 | ports:
102 | - name: default-http
103 | protocol: TCP
104 | port: 80
105 | targetPort: 9091
106 | - name: dht
107 | protocol: TCP
108 | port: 51413
109 | targetPort: 51413
110 | - name: dht-udp
111 | protocol: UDP
112 | port: 51413
113 | targetPort: 51413
114 | ---
115 |
--------------------------------------------------------------------------------
/examples/prometheus/prometheus.yml:
--------------------------------------------------------------------------------
1 | global:
2 | scrape_interval: 15s
3 | evaluation_interval: 15s
4 |
5 | scrape_configs:
6 | - job_name: 'transmission-exporter'
7 | static_configs:
8 | - targets:
9 | - 'transmission-exporter:19091'
10 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/metalmatze/transmission-exporter
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/alexflint/go-arg v0.0.0-20180516182405-f7c0423bd11e
7 | github.com/alexflint/go-scalar v0.0.0-20170216020425-e80c3b7ed292 // indirect
8 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect
9 | github.com/davecgh/go-spew v1.1.1 // indirect
10 | github.com/gogo/protobuf v1.1.1 // indirect
11 | github.com/golang/protobuf v1.2.0 // indirect
12 | github.com/joho/godotenv v1.3.0
13 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
14 | github.com/pmezard/go-difflib v1.0.0 // indirect
15 | github.com/prometheus/client_golang v0.9.0-pre1.0.20181010161331-7866eead363e
16 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect
17 | github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e // indirect
18 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d // indirect
19 | github.com/stretchr/testify v1.2.2 // indirect
20 | golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 // indirect
21 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect
22 | )
23 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/alexflint/go-arg v0.0.0-20180516182405-f7c0423bd11e h1:dzrBxLIjiq17Da9DhY3svGRhptiUg1LUzdkOuFYjAzA=
2 | github.com/alexflint/go-arg v0.0.0-20180516182405-f7c0423bd11e/go.mod h1:PHxo6ZWOLVMZZgWSAqBynb/KhIqoGO6WKwOVX7rM9dg=
3 | github.com/alexflint/go-scalar v0.0.0-20170216020425-e80c3b7ed292 h1:0YTMOir1UPjebSvNmIrEKO9FFd+RZc1wwZHUrxfn4BI=
4 | github.com/alexflint/go-scalar v0.0.0-20170216020425-e80c3b7ed292/go.mod h1:dgifnFPveotJNpwJdl1hDPu5vSuqVVUPIr3isfcvgBA=
5 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
6 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
7 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
8 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9 | github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
10 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
11 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
12 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
13 | github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
14 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
15 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
16 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
17 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
18 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
19 | github.com/prometheus/client_golang v0.9.0-pre1.0.20181010161331-7866eead363e h1:mwBXwBO7Hj6zVWKUlmaUibcQvPZn6eiTiV1ijb9BYs0=
20 | github.com/prometheus/client_golang v0.9.0-pre1.0.20181010161331-7866eead363e/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
21 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
22 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
23 | github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54=
24 | github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
25 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ=
26 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
27 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
28 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
29 | golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 h1:Y/KGZSOdz/2r0WJ9Mkmz6NJBusp0kiNx1Cn82lzJQ6w=
30 | golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
31 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
32 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
33 |
--------------------------------------------------------------------------------
/session.go:
--------------------------------------------------------------------------------
1 | package transmission
2 |
3 | type (
4 | // SessionCommand is the root command to interact with Transmission via RPC
5 | SessionCommand struct {
6 | Method string `json:"method,omitempty"`
7 | Session Session `json:"arguments,omitempty"`
8 | Result string `json:"result,omitempty"`
9 | }
10 |
11 | // Session information about the current transmission session
12 | Session struct {
13 | AltSpeedDown int `json:"alt-speed-down"`
14 | AltSpeedEnabled bool `json:"alt-speed-enabled"`
15 | //Alt_speed_time_begin int `json:"alt-speed-time-begin"`
16 | //Alt_speed_time_day int `json:"alt-speed-time-day"`
17 | //Alt_speed_time_enabled bool `json:"alt-speed-time-enabled"`
18 | //Alt_speed_time_end int `json:"alt-speed-time-end"`
19 | AltSpeedUp int `json:"alt-speed-up"`
20 | //Blocklist_enabled bool `json:"blocklist-enabled"`
21 | //Blocklist_size int `json:"blocklist-size"`
22 | //Blocklist_url string `json:"blocklist-url"`
23 | CacheSizeMB int `json:"cache-size-mb"`
24 | //Config_dir string `json:"config-dir"`
25 | //Dht_enabled bool `json:"dht-enabled"`
26 | DownloadDir string `json:"download-dir"`
27 | DownloadDirFreeSpace int64 `json:"download-dir-free-space"`
28 | DownloadQueueEnabled bool `json:"download-queue-enabled"`
29 | DownloadQueueSize int `json:"download-queue-size"`
30 | //Encryption string `json:"encryption"`
31 | //Idle_seeding_limit int `json:"idle-seeding-limit"`
32 | //Idle_seeding_limit_enabled bool `json:"idle-seeding-limit-enabled"`
33 | IncompleteDir string `json:"incomplete-dir"`
34 | //Incomplete_dir_enabled bool `json:"incomplete-dir-enabled"`
35 | //Lpd_enabled bool `json:"lpd-enabled"`
36 | PeerLimitGlobal int `json:"peer-limit-global"`
37 | PeerLimitPerTorrent int `json:"peer-limit-per-torrent"`
38 | //Peer_port int `json:"peer-port"`
39 | //Peer_port_random_on_start bool `json:"peer-port-random-on-start"`
40 | //Pex_enabled bool `json:"pex-enabled"`
41 | //Port_forwarding_enabled bool `json:"port-forwarding-enabled"`
42 | //Queue_stalled_enabled bool `json:"queue-stalled-enabled"`
43 | //Queue_stalled_minutes int `json:"queue-stalled-minutes"`
44 | //Rename_partial_files bool `json:"rename-partial-files"`
45 | //RPC_version int `json:"rpc-version"`
46 | //RPC_version_minimum int `json:"rpc-version-minimum"`
47 | //Script_torrent_done_enabled bool `json:"script-torrent-done-enabled"`
48 | //Script_torrent_done_filename string `json:"script-torrent-done-filename"`
49 | SeedQueueEnabled bool `json:"seed-queue-enabled"`
50 | SeedQueueSize int `json:"seed-queue-size"`
51 | SeedRatioLimit float64 `json:"seedRatioLimit"`
52 | SeedRatioLimited bool `json:"seedRatioLimited"`
53 | SpeedLimitDown int `json:"speed-limit-down"`
54 | SpeedLimitDownEnabled bool `json:"speed-limit-down-enabled"`
55 | SpeedLimitUp int `json:"speed-limit-up"`
56 | SpeedLimitUpEnabled bool `json:"speed-limit-up-enabled"`
57 | //Start_added_torrents bool `json:"start-added-torrents"`
58 | //Trash_original_torrent_files bool `json:"trash-original-torrent-files"`
59 | //Utp_enabled bool `json:"utp-enabled"`
60 | Version string `json:"version"`
61 | }
62 | )
63 |
--------------------------------------------------------------------------------
/session_stats.go:
--------------------------------------------------------------------------------
1 | package transmission
2 |
3 | type (
4 | // SessionStatsCmd is the root command to interact with Transmission via RPC
5 | SessionStatsCmd struct {
6 | SessionStats `json:"arguments"`
7 | Result string `json:"result"`
8 | }
9 |
10 | // SessionStats contains information about the current & cumulative session
11 | SessionStats struct {
12 | DownloadSpeed int64 `json:"downloadSpeed"`
13 | UploadSpeed int64 `json:"uploadSpeed"`
14 | ActiveTorrentCount int `json:"activeTorrentCount"`
15 | PausedTorrentCount int `json:"pausedTorrentCount"`
16 | TorrentCount int `json:"torrentCount"`
17 | CumulativeStats SessionStateStats `json:"cumulative-stats"`
18 | CurrentStats SessionStateStats `json:"current-stats"`
19 | }
20 | // SessionStateStats contains current or cumulative session stats
21 | SessionStateStats struct {
22 | DownloadedBytes int64 `json:"downloadedBytes"`
23 | UploadedBytes int64 `json:"uploadedBytes"`
24 | FilesAdded int64 `json:"filesAdded"`
25 | SecondsActive int64 `json:"secondsActive"`
26 | SessionCount int64 `json:"sessionCount"`
27 | }
28 | )
29 |
--------------------------------------------------------------------------------
/torrent.go:
--------------------------------------------------------------------------------
1 | package transmission
2 |
3 | type (
4 | // TorrentCommand is the root command to interact with Transmission via RPC
5 | TorrentCommand struct {
6 | Method string `json:"method,omitempty"`
7 | Arguments TorrentArguments `json:"arguments,omitempty"`
8 | Result string `json:"result,omitempty"`
9 | }
10 | // TorrentArguments specifies the TorrentCommand in more detail
11 | TorrentArguments struct {
12 | Fields []string `json:"fields,omitempty"`
13 | Torrents []Torrent `json:"torrents,omitempty"`
14 | Ids []int `json:"ids,omitempty"`
15 | DeleteData bool `json:"delete-local-data,omitempty"`
16 | DownloadDir string `json:"download-dir,omitempty"`
17 | MetaInfo string `json:"metainfo,omitempty"`
18 | Filename string `json:"filename,omitempty"`
19 | TorrentAdded TorrentArgumentsAdded `json:"torrent-added"`
20 | }
21 | // TorrentArgumentsAdded specifies the torrent to get added data from
22 | TorrentArgumentsAdded struct {
23 | HashString string `json:"hashString"`
24 | ID int64 `json:"id"`
25 | Name string `json:"name"`
26 | }
27 |
28 | // Torrent represents a transmission torrent
29 | Torrent struct {
30 | ID int `json:"id"`
31 | Name string `json:"name"`
32 | Status int `json:"status"`
33 | Added int `json:"addedDate"`
34 | LeftUntilDone int64 `json:"leftUntilDone"`
35 | Eta int `json:"eta"`
36 | UploadRatio float64 `json:"uploadRatio"`
37 | RateDownload int `json:"rateDownload"`
38 | RateUpload int `json:"rateUpload"`
39 | DownloadDir string `json:"downloadDir"`
40 | IsFinished bool `json:"isFinished"`
41 | PercentDone float64 `json:"percentDone"`
42 | SeedRatioMode int `json:"seedRatioMode"`
43 | HashString string `json:"hashString"`
44 | Error int `json:"error"`
45 | ErrorString string `json:"errorString"`
46 | Files []File `json:"files"`
47 | FilesStats []FileStat `json:"fileStats"`
48 | TrackerStats []TrackerStat `json:"trackerStats"`
49 | Peers []Peer `json:"peers"`
50 | PeersConnected int `json:"peersConnected"`
51 | PeersGettingFromUs int `json:"peersGettingFromUs"`
52 | TotalSize int `json:"totalSize"`
53 | UploadedEver int `json:"uploadedEver"`
54 | }
55 |
56 | // ByID implements the sort Interface to sort by ID
57 | ByID []Torrent
58 | // ByName implements the sort Interface to sort by Name
59 | ByName []Torrent
60 | // ByDate implements the sort Interface to sort by Date
61 | ByDate []Torrent
62 | // ByRatio implements the sort Interface to sort by Ratio
63 | ByRatio []Torrent
64 |
65 | // File is a file contained inside a torrent
66 | File struct {
67 | BytesCompleted int64 `json:"bytesCompleted"`
68 | Length int64 `json:"length"`
69 | Name string `json:"name"`
70 | }
71 |
72 | // FileStat describe a file's priority & if it's wanted
73 | FileStat struct {
74 | BytesCompleted int64 `json:"bytesCompleted"`
75 | Priority int `json:"priority"`
76 | Wanted bool `json:"wanted"`
77 | }
78 |
79 | // TrackerStat has stats about the torrent's tracker
80 | TrackerStat struct {
81 | Announce string `json:"announce"`
82 | AnnounceState int `json:"announceState"`
83 | DownloadCount int `json:"downloadCount"`
84 | HasAnnounced bool `json:"hasAnnounced"`
85 | HasScraped bool `json:"hasScraped"`
86 | Host string `json:"host"`
87 | ID int `json:"id"`
88 | IsBackup bool `json:"isBackup"`
89 | LastAnnouncePeerCount int `json:"lastAnnouncePeerCount"`
90 | LastAnnounceResult string `json:"lastAnnounceResult"`
91 | LastAnnounceStartTime int `json:"lastAnnounceStartTime"`
92 | LastAnnounceSucceeded bool `json:"lastAnnounceSucceeded"`
93 | LastAnnounceTime int `json:"lastAnnounceTime"`
94 | LastAnnounceTimedOut bool `json:"lastAnnounceTimedOut"`
95 | LastScrapeResult string `json:"lastScrapeResult"`
96 | LastScrapeStartTime int `json:"lastScrapeStartTime"`
97 | LastScrapeSucceeded bool `json:"lastScrapeSucceeded"`
98 | LastScrapeTime int `json:"lastScrapeTime"`
99 | LastScrapeTimedOut bool `json:"lastScrapeTimedOut"`
100 | LeecherCount int `json:"leecherCount"`
101 | NextAnnounceTime int `json:"nextAnnounceTime"`
102 | NextScrapeTime int `json:"nextScrapeTime"`
103 | Scrape string `json:"scrape"`
104 | ScrapeState int `json:"scrapeState"`
105 | SeederCount int `json:"seederCount"`
106 | Tier int `json:"tier"`
107 | }
108 |
109 | // Peer of a torrent
110 | Peer struct {
111 | Address string `json:"address"`
112 | ClientIsChoked bool `json:"clientIsChoked"`
113 | ClientIsInterested bool `json:"clientIsInterested"`
114 | ClientName string `json:"clientName"`
115 | FlagStr string `json:"flagStr"`
116 | IsDownloadingFrom bool `json:"isDownloadingFrom"`
117 | IsEncrypted bool `json:"isEncrypted"`
118 | IsIncoming bool `json:"isIncoming"`
119 | IsUTP bool `json:"isUTP"`
120 | IsUploadingTo bool `json:"isUploadingTo"`
121 | PeerIsChoked bool `json:"peerIsChoked"`
122 | PeerIsInterested bool `json:"peerIsInterested"`
123 | Port int `json:"port"`
124 | Progress float64 `json:"progress"`
125 | RateToClient int `json:"rateToClient"`
126 | RateToPeer int `json:"rateToPeer"`
127 | }
128 | )
129 |
130 | func (t ByID) Len() int { return len(t) }
131 | func (t ByID) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
132 | func (t ByID) Less(i, j int) bool { return t[i].ID < t[j].ID }
133 |
134 | func (t ByName) Len() int { return len(t) }
135 | func (t ByName) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
136 | func (t ByName) Less(i, j int) bool { return t[i].Name < t[j].Name }
137 |
138 | func (t ByDate) Len() int { return len(t) }
139 | func (t ByDate) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
140 | func (t ByDate) Less(i, j int) bool { return t[i].Added < t[j].Added }
141 |
142 | func (t ByRatio) Len() int { return len(t) }
143 | func (t ByRatio) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
144 | func (t ByRatio) Less(i, j int) bool { return t[i].UploadRatio < t[j].UploadRatio }
145 |
--------------------------------------------------------------------------------
/transmission.go:
--------------------------------------------------------------------------------
1 | package transmission
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "errors"
7 | "io/ioutil"
8 | "net/http"
9 | "strings"
10 | )
11 |
12 | const endpoint = "/transmission/rpc/"
13 |
14 | type (
15 | // User to authenticate with Transmission
16 | User struct {
17 | Username string
18 | Password string
19 | }
20 | // Client connects to transmission via HTTP
21 | Client struct {
22 | URL string
23 | token string
24 |
25 | User *User
26 | client http.Client
27 | }
28 | )
29 |
30 | // New create new transmission torrent
31 | func New(url string, user *User) *Client {
32 | return &Client{
33 | URL: url + endpoint,
34 | User: user,
35 | }
36 | }
37 |
38 | func (c *Client) post(body []byte) ([]byte, error) {
39 | authRequest, err := c.authRequest("POST", body)
40 | if err != nil {
41 | return make([]byte, 0), err
42 | }
43 |
44 | res, err := c.client.Do(authRequest)
45 | if err != nil {
46 | return make([]byte, 0), err
47 | }
48 | defer res.Body.Close()
49 |
50 | if res.StatusCode == http.StatusUnauthorized {
51 | return make([]byte, 0), errors.New("authorization failed, check your username and password and make sure the ip is whitelisted")
52 | }
53 |
54 | if res.StatusCode == http.StatusConflict {
55 | c.getToken()
56 | authRequest, err := c.authRequest("POST", body)
57 | if err != nil {
58 | return make([]byte, 0), err
59 | }
60 | res, err = c.client.Do(authRequest)
61 | if err != nil {
62 | return make([]byte, 0), err
63 | }
64 | }
65 |
66 | resBody, err := ioutil.ReadAll(res.Body)
67 | if err != nil {
68 | return make([]byte, 0), err
69 | }
70 | return resBody, nil
71 | }
72 |
73 | func (c *Client) getToken() error {
74 | req, err := http.NewRequest("POST", c.URL, strings.NewReader(""))
75 | if err != nil {
76 | return err
77 | }
78 |
79 | if c.User != nil {
80 | req.SetBasicAuth(c.User.Username, c.User.Password)
81 | }
82 |
83 | res, err := c.client.Do(req)
84 | if err != nil {
85 | return err
86 | }
87 | defer res.Body.Close()
88 | c.token = res.Header.Get("X-Transmission-Session-Id")
89 | return nil
90 | }
91 |
92 | func (c *Client) authRequest(method string, body []byte) (*http.Request, error) {
93 | if c.token == "" {
94 | err := c.getToken()
95 | if err != nil {
96 | return nil, err
97 | }
98 | }
99 | req, err := http.NewRequest(method, c.URL, bytes.NewReader(body))
100 | if err != nil {
101 | return nil, err
102 | }
103 | req.Header.Add("X-Transmission-Session-Id", c.token)
104 |
105 | if c.User != nil {
106 | req.SetBasicAuth(c.User.Username, c.User.Password)
107 | }
108 |
109 | return req, nil
110 | }
111 |
112 | // GetTorrents get a list of torrents
113 | func (c *Client) GetTorrents() ([]Torrent, error) {
114 | cmd := TorrentCommand{
115 | Method: "torrent-get",
116 | Arguments: TorrentArguments{
117 | Fields: []string{
118 | "id",
119 | "name",
120 | "hashString",
121 | "status",
122 | "addedDate",
123 | "leftUntilDone",
124 | "eta",
125 | "uploadRatio",
126 | "rateDownload",
127 | "rateUpload",
128 | "downloadDir",
129 | "isFinished",
130 | "percentDone",
131 | "seedRatioMode",
132 | "error",
133 | "errorString",
134 | "files",
135 | "fileStats",
136 | "peers",
137 | "trackers",
138 | "trackerStats",
139 | "peersConnected",
140 | "peersGettingFromUs",
141 | "totalSize",
142 | "uploadedEver",
143 | },
144 | },
145 | }
146 |
147 | req, err := json.Marshal(&cmd)
148 | if err != nil {
149 | return nil, err
150 | }
151 |
152 | resp, err := c.post(req)
153 | if err != nil {
154 | return nil, err
155 | }
156 |
157 | var out TorrentCommand
158 | if err := json.Unmarshal(resp, &out); err != nil {
159 | return nil, err
160 | }
161 |
162 | return out.Arguments.Torrents, nil
163 | }
164 |
165 | // GetSession gets the current session from transmission
166 | func (c *Client) GetSession() (*Session, error) {
167 | req, err := json.Marshal(SessionCommand{Method: "session-get"})
168 | if err != nil {
169 | return nil, err
170 | }
171 |
172 | resp, err := c.post(req)
173 | if err != nil {
174 | return nil, err
175 | }
176 |
177 | var cmd SessionCommand
178 | if err := json.Unmarshal(resp, &cmd); err != nil {
179 | return nil, err
180 | }
181 |
182 | return &cmd.Session, nil
183 | }
184 |
185 | // GetSessionStats gets stats on the current & cumulative session
186 | func (c *Client) GetSessionStats() (*SessionStats, error) {
187 | req, err := json.Marshal(SessionCommand{Method: "session-stats"})
188 | if err != nil {
189 | return nil, err
190 | }
191 |
192 | resp, err := c.post(req)
193 | if err != nil {
194 | return nil, err
195 | }
196 |
197 | var cmd SessionStatsCmd
198 | if err := json.Unmarshal(resp, &cmd); err != nil {
199 | return nil, err
200 | }
201 |
202 | return &cmd.SessionStats, nil
203 | }
204 |
--------------------------------------------------------------------------------