first commit

This commit is contained in:
usbharu 2025-02-01 16:26:12 +09:00
commit c0d87f1c0c
Signed by: usbharu
GPG Key ID: 95CBCF7046307B77
13 changed files with 414 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/test.env

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# デフォルトの無視対象ファイル
/shelf/
/workspace.xml
# エディターベースの HTTP クライアントリクエスト
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

1
.idea/.name Normal file
View File

@ -0,0 +1 @@
misskey-exporter

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/misskey-exporter.iml" filepath="$PROJECT_DIR$/.idea/misskey-exporter.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

13
Dockerfile Normal file
View File

@ -0,0 +1,13 @@
# ステージ1
FROM golang:1.23.5-alpine3.21 AS go
WORKDIR /app
COPY go.mod go.sum main.go collector.go ./
RUN go mod download \
&& go build -o main .
# ステージ2
FROM alpine:3.21
WORKDIR /app
COPY --from=go /app/main .
USER 1001
CMD [ "/app/main" ]

114
collector.go Normal file
View File

@ -0,0 +1,114 @@
package main
import (
"bytes"
"github.com/sirupsen/logrus"
"github.com/yitsushi/go-misskey/services/notes/timeline"
"net/http"
"time"
)
func collectJobqueue() {
for {
time.Sleep(1 * time.Second)
stats, err := client.Admin().Queue().Stats()
if err != nil {
logrus.Warning(err)
continue
}
misskeyJobQueueJobsCount.WithLabelValues("deliver", "waiting").Set(float64(stats.Deliver.Waiting))
misskeyJobQueueJobsCount.WithLabelValues("deliver", "active").Set(float64(stats.Deliver.Active))
misskeyJobQueueJobsCount.WithLabelValues("deliver", "completed").Set(float64(stats.Deliver.Completed))
misskeyJobQueueJobsCount.WithLabelValues("deliver", "failed").Set(float64(stats.Deliver.Failed))
misskeyJobQueueJobsCount.WithLabelValues("deliver", "delayed").Set(float64(stats.Deliver.Delayed))
misskeyJobQueueJobsCount.WithLabelValues("deliver", "paused").Set(float64(stats.Deliver.Paused))
misskeyJobQueueJobsCount.WithLabelValues("inbox", "waiting").Set(float64(stats.Inbox.Waiting))
misskeyJobQueueJobsCount.WithLabelValues("inbox", "active").Set(float64(stats.Inbox.Active))
misskeyJobQueueJobsCount.WithLabelValues("inbox", "completed").Set(float64(stats.Inbox.Completed))
misskeyJobQueueJobsCount.WithLabelValues("inbox", "failed").Set(float64(stats.Inbox.Failed))
misskeyJobQueueJobsCount.WithLabelValues("inbox", "delayed").Set(float64(stats.Inbox.Delayed))
misskeyJobQueueJobsCount.WithLabelValues("inbox", "paused").Set(float64(stats.Inbox.Paused))
misskeyJobQueueJobsCount.WithLabelValues("db", "waiting").Set(float64(stats.DB.Waiting))
misskeyJobQueueJobsCount.WithLabelValues("db", "active").Set(float64(stats.DB.Active))
misskeyJobQueueJobsCount.WithLabelValues("db", "completed").Set(float64(stats.DB.Completed))
misskeyJobQueueJobsCount.WithLabelValues("db", "failed").Set(float64(stats.DB.Failed))
misskeyJobQueueJobsCount.WithLabelValues("db", "delayed").Set(float64(stats.DB.Delayed))
misskeyJobQueueJobsCount.WithLabelValues("db", "paused").Set(float64(stats.DB.Paused))
misskeyJobQueueJobsCount.WithLabelValues("objectstorage", "waiting").Set(float64(stats.ObjectStorage.Waiting))
misskeyJobQueueJobsCount.WithLabelValues("objectstorage", "active").Set(float64(stats.ObjectStorage.Active))
misskeyJobQueueJobsCount.WithLabelValues("objectstorage", "completed").Set(float64(stats.ObjectStorage.Completed))
misskeyJobQueueJobsCount.WithLabelValues("objectstorage", "failed").Set(float64(stats.ObjectStorage.Failed))
misskeyJobQueueJobsCount.WithLabelValues("objectstorage", "delayed").Set(float64(stats.ObjectStorage.Delayed))
misskeyJobQueueJobsCount.WithLabelValues("objectstorage", "paused").Set(float64(stats.ObjectStorage.Paused))
}
}
func collectPing() {
for {
time.Sleep(5 * time.Second)
var buf = bytes.NewBuffer([]byte(`{}`))
start := time.Now()
resp, err := http.Post("https://"+endpoint+"/api/ping", "application/json", buf)
if err != nil {
logrus.Warning(err)
continue
}
err = resp.Body.Close()
if err != nil {
logrus.Warning(err)
continue
}
misskeyPingResponseCode.Set(float64(resp.StatusCode))
misskeyPingResponseTime.Observe(float64(time.Since(start).Milliseconds()) / 1000)
misskeyPingResponseTimeRaw.Set(float64(time.Since(start).Milliseconds()) / 1000)
}
}
func collectStats() {
for {
time.Sleep(30 * time.Second)
stats, err := client.Meta().Stats()
if err != nil {
continue
}
misskeyNotesCount.Set(float64(stats.NotesCount))
misskeyUsersCount.Set(float64(stats.UsersCount))
misskeyOriginalNotesCount.Set(float64(stats.OriginalNotesCount))
misskeyOriginalUsersCount.Set(float64(stats.OriginalUsersCount))
}
}
func collectTimeline() {
for {
time.Sleep(30 * time.Second)
go func() {
start := time.Now()
global, err := client.Notes().Timeline().Global(timeline.GlobalRequest{Limit: 10})
if err != nil {
logrus.Warning(err)
return
}
misskeyGlobalTimelineResponseTime.Observe(float64(time.Since(start).Milliseconds()) / 1000)
misskeyGlobalTimelineResponseTimeRaw.Set(float64(time.Since(start).Milliseconds()) / 1000)
if len(global) != 0 {
misskeyGlobalTimelineLastNotePublished.Set(float64(global[0].CreatedAt.UnixMilli()))
}
}()
go func() {
start := time.Now()
global, err := client.Notes().Timeline().Local(timeline.LocalRequest{Limit: 10})
if err != nil {
logrus.Warning(err)
return
}
misskeyLocalTimelineResponseTime.Observe(float64(time.Since(start).Milliseconds()) / 1000)
misskeyLocalTimelineResponseTimeRaw.Set(float64(time.Since(start).Milliseconds()) / 1000)
if len(global) != 0 {
misskeyLocalTimelineLastNotePublished.Set(float64(global[0].CreatedAt.UnixMilli()))
}
}()
}
}

22
docker-compose.yaml Normal file
View File

@ -0,0 +1,22 @@
services:
misskey-exporter:
env_file:
- test.env
build: .
ports:
- "8080:8080"
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- 9090:9090
grafana:
image: grafana/grafana-enterprise
ports:
- '3011:3000'
volumes:
- 'grafana_storage:/var/lib/grafana'
volumes:
grafana_storage: { }

22
go.mod Normal file
View File

@ -0,0 +1,22 @@
module misskey-exporter
go 1.23
require (
github.com/sirupsen/logrus v1.7.0
github.com/yitsushi/go-misskey v1.1.6
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/sys v0.22.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
)

40
go.sum Normal file
View File

@ -0,0 +1,40 @@
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yitsushi/go-misskey v1.1.6 h1:aMfu7N9RzS2JO2QP9TPBXQyvudwU7NTr6jiOeUcho3Q=
github.com/yitsushi/go-misskey v1.1.6/go.mod h1:FeLNMTVebkWTbjRt5X1YqkKc61dOjgTy2hyUDaOC+zc=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

163
main.go Normal file
View File

@ -0,0 +1,163 @@
package main
import (
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
"github.com/yitsushi/go-misskey"
"net/http"
"os"
)
//TIP <p>To run your code, right-click the code and select <b>Run</b>.</p> <p>Alternatively, click
// the <icon src="AllIcons.Actions.Execute"/> icon in the gutter and select the <b>Run</b> menu item from here.</p>
//var now = time.Now()
var client *misskey.Client
var endpoint = os.Getenv("MISSKEY_ENDPOINT")
var apiKey = os.Getenv("MISSKEY_API_TOKEN")
var (
misskeyJobQueueJobsCount = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "misskey_jobqueue_jobs",
Help: "misskey job queue jobs",
},
[]string{"type", "status"},
)
misskeyNotesCount = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "misskey_notes_count",
Help: "Notes Coount",
},
)
misskeyUsersCount = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "misskey_users_count",
Help: "Users Coount",
},
)
misskeyOriginalNotesCount = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "misskey_original_notes_count",
Help: "Original Notes Coount",
},
)
misskeyOriginalUsersCount = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "misskey_original_users_count",
Help: "Original Users Coount",
},
)
misskeyPingResponseTimeRaw = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "misskey_ping_response_time_raw",
Help: "Response Time for misskey Ping",
},
)
misskeyPingResponseTime = prometheus.NewHistogram(
prometheus.HistogramOpts{
Name: "misskey_ping_response_time",
Help: "Response Time for misskey Ping",
Buckets: prometheus.DefBuckets,
},
)
misskeyPingResponseCode = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "misskey_ping_response_code",
Help: "Response Code for misskey Ping",
},
)
misskeyGlobalTimelineResponseTime = prometheus.NewHistogram(
prometheus.HistogramOpts{
Name: "misskey_global_timeline_response_time",
Help: "Response Time for misskey Global Timeline",
})
misskeyLocalTimelineResponseTime = prometheus.NewHistogram(
prometheus.HistogramOpts{
Name: "misskey_local_timeline_response_time",
Help: "Response Time for misskey Local Timeline",
})
misskeyGlobalTimelineLastNotePublished = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "misskey_global_timeline_last_note_published",
Help: "Last Note Published on Global Timeline",
})
misskeyLocalTimelineLastNotePublished = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "misskey_local_timeline_last_note_published",
Help: "Last Note Published on Local Timeline",
})
misskeyGlobalTimelineResponseTimeRaw = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "misskey_global_timeline_response_time_raw",
Help: "Response Time for misskey Global Timeline",
})
misskeyLocalTimelineResponseTimeRaw = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "misskey_local_timeline_response_time_raw",
Help: "Response Time for misskey Local Timeline",
})
)
type MetricGroup struct {
Basename string
Help string
Type string
Value []Metric
}
type Metric struct {
Label map[string]string
Value string
}
func main() {
options, err := misskey.NewClientWithOptions(
misskey.WithAPIToken(apiKey),
misskey.WithBaseURL("https", endpoint, ""),
misskey.WithLogLevel(logrus.DebugLevel),
)
client = options
if err != nil {
return
}
stats, err := client.Admin().Queue().Stats()
if err != nil {
return
}
fmt.Println(stats)
prometheus.MustRegister(misskeyJobQueueJobsCount)
prometheus.MustRegister(misskeyNotesCount)
prometheus.MustRegister(misskeyUsersCount)
prometheus.MustRegister(misskeyOriginalNotesCount)
prometheus.MustRegister(misskeyOriginalUsersCount)
prometheus.MustRegister(misskeyPingResponseTime)
prometheus.MustRegister(misskeyPingResponseTimeRaw)
prometheus.MustRegister(misskeyPingResponseCode)
prometheus.MustRegister(misskeyGlobalTimelineResponseTime)
prometheus.MustRegister(misskeyLocalTimelineResponseTime)
prometheus.MustRegister(misskeyGlobalTimelineLastNotePublished)
prometheus.MustRegister(misskeyLocalTimelineLastNotePublished)
prometheus.MustRegister(misskeyGlobalTimelineResponseTimeRaw)
prometheus.MustRegister(misskeyLocalTimelineResponseTimeRaw)
handler := promhttp.Handler()
server := http.Server{
Addr: ":8080",
Handler: handler,
}
go func() {
go collectJobqueue()
go collectPing()
go collectStats()
go collectTimeline()
}()
server.ListenAndServe()
}

7
prometheus.yml Normal file
View File

@ -0,0 +1,7 @@
global:
scrape_interval: 1s
evaluation_interval: 1s
scrape_configs:
- job_name: 'process_exporter'
static_configs:
- targets: ['misskey-exporter:8080']