Compare commits
4 Commits
v0.1.0
...
d4cecb1352
| Author | SHA1 | Date | |
|---|---|---|---|
| d4cecb1352 | |||
| 360360f3ea | |||
| 65eed04b5e | |||
| 4d7e15d719 |
21
README.md
Normal file
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Prusa Connect Prometheus Exporter
|
||||
|
||||
Version v0.1.0 of this exporter supports the pre-4.4.0 changes to the Prusa Connect API (non-API-key version).
|
||||
|
||||
Current master branch supports the new, 4.4.0-beta2 release of Prusa Connect as well as the older API.
|
||||
|
||||
## Usage
|
||||
|
||||
`./prusa-connect-exporter -h`
|
||||
|
||||
* `apikey`
|
||||
Prusa Connect API key (see Main Menu -> Settings -> Network on the printer).
|
||||
If no key is provided, exporter assumes the older API layout when querying the printer.
|
||||
* `hostname`
|
||||
Hostname the Prusa Connect API is available at (assumes http) (default "localhost")
|
||||
* `interval`
|
||||
How often, in seconds, to query the API (default 2)
|
||||
* `path`
|
||||
Local path to export metrics on (default "metrics")
|
||||
* `port`
|
||||
Local port to export metrics on (default "2112")
|
||||
12
go.mod
12
go.mod
@@ -2,16 +2,16 @@ module git.yetaga.in/alazyreader/prusa-connect-exporter
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/prometheus/client_golang v1.12.1
|
||||
require github.com/prometheus/client_golang v1.14.0
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
||||
google.golang.org/protobuf v1.26.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
)
|
||||
|
||||
21
go.sum
21
go.sum
@@ -63,9 +63,11 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
@@ -159,22 +161,30 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
|
||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
@@ -257,12 +267,15 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -307,15 +320,21 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -440,6 +459,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
321
main.go
321
main.go
@@ -15,7 +15,8 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
type Metrics struct {
|
||||
// original /api/telemetry type struct
|
||||
type MetricsV1 struct {
|
||||
TempNozzle int `json:"temp_nozzle"`
|
||||
TempBed int `json:"temp_bed"`
|
||||
Material string `json:"material"`
|
||||
@@ -29,68 +30,135 @@ type Metrics struct {
|
||||
ProjectName string `json:"project_name"`
|
||||
}
|
||||
|
||||
// new 4.4.0+ /api/printer struct
|
||||
type MetricsV2 struct {
|
||||
Telemetry Telemetry `json:"telemetry"`
|
||||
Temperature Temperature `json:"temperature"`
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
type Telemetry struct {
|
||||
TempBed float64 `json:"temp-bed"`
|
||||
TempNozzle float64 `json:"temp-nozzle"`
|
||||
PrintSpeed int `json:"print-speed"`
|
||||
ZHeight float64 `json:"z-height"`
|
||||
Material string `json:"material"`
|
||||
}
|
||||
|
||||
type Temperature struct {
|
||||
Tool0 Tempatures `json:"tool0"`
|
||||
Bed Tempatures `json:"bed"`
|
||||
}
|
||||
|
||||
type Tempatures struct {
|
||||
Actual float64 `json:"actual"`
|
||||
Target float64 `json:"target"`
|
||||
Display float64 `json:"display"`
|
||||
Offset float64 `json:"offset"`
|
||||
}
|
||||
|
||||
type State struct {
|
||||
Text string `json:"text"`
|
||||
Flags Flags `json:"flags"`
|
||||
}
|
||||
|
||||
type Flags struct {
|
||||
Operational bool `json:"operational"`
|
||||
Paused bool `json:"paused"`
|
||||
Printing bool `json:"printing"`
|
||||
Cancelling bool `json:"cancelling"`
|
||||
Pausing bool `json:"pausing"`
|
||||
SdReady bool `json:"sdReady"`
|
||||
Error bool `json:"error"`
|
||||
ClosedOnError bool `json:"closedOnError"`
|
||||
Ready bool `json:"ready"`
|
||||
Busy bool `json:"busy"`
|
||||
}
|
||||
|
||||
// /api/job struct
|
||||
type JobV2 struct {
|
||||
State string `json:"state"`
|
||||
Job Job `json:"job"`
|
||||
Progress Progress `json:"progress"`
|
||||
}
|
||||
|
||||
type File struct {
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Display string `json:"display"`
|
||||
}
|
||||
|
||||
type Job struct {
|
||||
EstimatedPrintTime int `json:"estimatedPrintTime"`
|
||||
File File `json:"file"`
|
||||
}
|
||||
|
||||
type Progress struct {
|
||||
Completion float64 `json:"completion"`
|
||||
PrintTime int `json:"printTime"`
|
||||
PrintTimeLeft int `json:"printTimeLeft"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
QueryHostname string
|
||||
QueryInterval int
|
||||
Port string
|
||||
Path string
|
||||
APIKey string
|
||||
}
|
||||
|
||||
var (
|
||||
opsFlowFactor = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "flow_factor",
|
||||
Help: "Current flow factor, as a unitless number",
|
||||
})
|
||||
opsPrintSpeed = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "printing_speed",
|
||||
Help: "Current print speed, as a percentage",
|
||||
})
|
||||
opsZPosition = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "z_position",
|
||||
Help: "Vertical depth, in mm, of the Z head",
|
||||
})
|
||||
opsBed = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "temp_bed",
|
||||
Help: "Temperature, in celsius, of the print bed",
|
||||
})
|
||||
opsNozzle = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "temp_nozzle",
|
||||
Help: "Temperature, in celsius, of the print nozzle",
|
||||
})
|
||||
opsProgress = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "progress",
|
||||
Help: "Current print completeness, as a percentage",
|
||||
})
|
||||
opsDuration = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "duration",
|
||||
Help: "Duration of current print job, as seconds since start",
|
||||
})
|
||||
opsRemaining = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "remaining",
|
||||
Help: "Estimated remaining time of current print job, as seconds",
|
||||
})
|
||||
errCount = 0
|
||||
gauges = map[string]prometheus.Gauge{
|
||||
"flow_factor": prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "flow_factor",
|
||||
Help: "Current flow factor, as a unitless number",
|
||||
}),
|
||||
"printing_speed": prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "printing_speed",
|
||||
Help: "Current print speed, as a percentage",
|
||||
}),
|
||||
"z_position": prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "z_position",
|
||||
Help: "Vertical depth, in mm, of the Z head",
|
||||
}),
|
||||
"temp_bed": prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "temp_bed",
|
||||
Help: "Temperature, in celsius, of the print bed",
|
||||
}),
|
||||
"temp_nozzle": prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "temp_nozzle",
|
||||
Help: "Temperature, in celsius, of the print nozzle",
|
||||
}),
|
||||
"progress": prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "progress",
|
||||
Help: "Current print completeness, as a percentage",
|
||||
}),
|
||||
"duration": prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "duration",
|
||||
Help: "Duration of current print job, as seconds since start",
|
||||
}),
|
||||
"remaining": prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "prusa_connect",
|
||||
Name: "remaining",
|
||||
Help: "Estimated remaining time of current print job, as seconds",
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
func errLog(err error) {
|
||||
errCount++
|
||||
// reset metrics
|
||||
opsFlowFactor.Set(0)
|
||||
opsPrintSpeed.Set(0)
|
||||
opsZPosition.Set(0)
|
||||
opsBed.Set(0)
|
||||
opsNozzle.Set(0)
|
||||
opsProgress.Set(0)
|
||||
opsDuration.Set(0)
|
||||
opsRemaining.Set(0)
|
||||
for _, g := range gauges {
|
||||
g.Set(0)
|
||||
}
|
||||
if errCount == 5 {
|
||||
log.Printf("suppressing further error logging")
|
||||
return
|
||||
@@ -109,42 +177,124 @@ func recordMetrics(ctx context.Context, config Config) {
|
||||
return
|
||||
default:
|
||||
time.Sleep(time.Second * time.Duration(config.QueryInterval))
|
||||
res, err := http.Get(config.QueryHostname + "/api/telemetry")
|
||||
if err != nil {
|
||||
errLog(err)
|
||||
if config.APIKey == "" {
|
||||
parseMetricsV1(ctx, config)
|
||||
break
|
||||
}
|
||||
b, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
errLog(err)
|
||||
break
|
||||
}
|
||||
t := &Metrics{}
|
||||
err = json.Unmarshal(b, t)
|
||||
if err != nil {
|
||||
errLog(err)
|
||||
break
|
||||
}
|
||||
if errCount != 0 {
|
||||
log.Printf("connection established")
|
||||
}
|
||||
errCount = 0
|
||||
opsFlowFactor.Set(float64(t.FlowFactor))
|
||||
opsPrintSpeed.Set(float64(t.PrintingSpeed))
|
||||
opsZPosition.Set(t.ZPosition)
|
||||
opsBed.Set(float64(t.TempBed))
|
||||
opsNozzle.Set(float64(t.TempNozzle))
|
||||
opsProgress.Set(float64(t.Progress))
|
||||
opsDuration.Set(float64(parseDuration(t.PrintDur) / time.Second))
|
||||
estimatedTimeRemaining, err := strconv.ParseFloat(t.TimeEst, 64)
|
||||
if err == nil {
|
||||
opsRemaining.Set(float64(estimatedTimeRemaining))
|
||||
}
|
||||
parseMetricsV2(ctx, config)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func parseMetricsV1(ctx context.Context, config Config) {
|
||||
t, err := getTelemetry(config.QueryHostname)
|
||||
if err != nil {
|
||||
errLog(err)
|
||||
return
|
||||
}
|
||||
if errCount != 0 {
|
||||
errCount = 0
|
||||
log.Printf("connection established")
|
||||
}
|
||||
gauges["flow_factor"].Set(float64(t.FlowFactor))
|
||||
gauges["printing_speed"].Set(float64(t.PrintingSpeed))
|
||||
gauges["z_position"].Set(t.ZPosition)
|
||||
gauges["temp_bed"].Set(float64(t.TempBed))
|
||||
gauges["temp_nozzle"].Set(float64(t.TempNozzle))
|
||||
gauges["progress"].Set(float64(t.Progress))
|
||||
gauges["duration"].Set(float64(parseDuration(t.PrintDur) / time.Second))
|
||||
estimatedTimeRemaining, err := strconv.ParseFloat(t.TimeEst, 64)
|
||||
if err == nil {
|
||||
gauges["remaining"].Set(float64(estimatedTimeRemaining))
|
||||
}
|
||||
}
|
||||
|
||||
func parseMetricsV2(ctx context.Context, config Config) {
|
||||
t, err := getPrinter(config.Port, config.APIKey)
|
||||
if err != nil {
|
||||
errLog(err)
|
||||
return
|
||||
}
|
||||
j, err := getJob(config.Port, config.APIKey)
|
||||
if err != nil {
|
||||
errLog(err)
|
||||
return
|
||||
}
|
||||
if errCount != 0 {
|
||||
errCount = 0
|
||||
log.Printf("connection established")
|
||||
}
|
||||
gauges["printing_speed"].Set(float64(t.Telemetry.PrintSpeed))
|
||||
gauges["z_position"].Set(t.Telemetry.ZHeight)
|
||||
gauges["temp_bed"].Set(float64(t.Telemetry.TempBed))
|
||||
gauges["temp_nozzle"].Set(float64(t.Telemetry.TempNozzle))
|
||||
gauges["progress"].Set(float64(j.Progress.Completion) * 100)
|
||||
gauges["duration"].Set(float64(j.Progress.PrintTime))
|
||||
gauges["remaining"].Set(float64(j.Progress.PrintTimeLeft))
|
||||
}
|
||||
|
||||
func getJob(hostname, apiKey string) (*JobV2, error) {
|
||||
r, err := http.NewRequest(http.MethodGet, hostname+"/api/job", nil)
|
||||
if err != nil {
|
||||
return &JobV2{}, err
|
||||
}
|
||||
r.Header.Set("X-Api-Key", apiKey)
|
||||
res, err := http.DefaultClient.Do(r)
|
||||
if err != nil {
|
||||
return &JobV2{}, err
|
||||
}
|
||||
b, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return &JobV2{}, err
|
||||
}
|
||||
j := &JobV2{}
|
||||
err = json.Unmarshal(b, j)
|
||||
if err != nil {
|
||||
return &JobV2{}, err
|
||||
}
|
||||
return j, nil
|
||||
}
|
||||
|
||||
func getPrinter(hostname, apiKey string) (*MetricsV2, error) {
|
||||
r, err := http.NewRequest(http.MethodGet, hostname+"/api/printer", nil)
|
||||
if err != nil {
|
||||
return &MetricsV2{}, err
|
||||
}
|
||||
r.Header.Set("X-Api-Key", apiKey)
|
||||
res, err := http.DefaultClient.Do(r)
|
||||
if err != nil {
|
||||
return &MetricsV2{}, err
|
||||
}
|
||||
b, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return &MetricsV2{}, err
|
||||
}
|
||||
j := &MetricsV2{}
|
||||
err = json.Unmarshal(b, j)
|
||||
if err != nil {
|
||||
return &MetricsV2{}, err
|
||||
}
|
||||
return j, nil
|
||||
}
|
||||
|
||||
func getTelemetry(hostname string) (*MetricsV1, error) {
|
||||
res, err := http.Get(hostname + "/api/telemetry")
|
||||
if err != nil {
|
||||
return &MetricsV1{}, err
|
||||
}
|
||||
b, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return &MetricsV1{}, err
|
||||
}
|
||||
t := &MetricsV1{}
|
||||
err = json.Unmarshal(b, t)
|
||||
if err != nil {
|
||||
return &MetricsV1{}, err
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// taking a guess on proper parsing here...
|
||||
func parseDuration(d string) time.Duration {
|
||||
dur := 0
|
||||
@@ -187,6 +337,8 @@ func main() {
|
||||
flag.StringVar(&port, "port", "2112", "Local port to export metrics on")
|
||||
var path string
|
||||
flag.StringVar(&path, "path", "metrics", "Local path to export metrics on")
|
||||
var apiKey string
|
||||
flag.StringVar(&apiKey, "apikey", "", "Prusa Connect API key (see Main Menu -> Settings -> Network on the printer)")
|
||||
flag.Parse()
|
||||
|
||||
if queryInterval < 1 {
|
||||
@@ -198,18 +350,13 @@ func main() {
|
||||
QueryInterval: queryInterval,
|
||||
Port: port,
|
||||
Path: path,
|
||||
APIKey: apiKey,
|
||||
}
|
||||
|
||||
r := prometheus.NewRegistry()
|
||||
r.MustRegister(opsNozzle)
|
||||
r.MustRegister(opsBed)
|
||||
r.MustRegister(opsZPosition)
|
||||
r.MustRegister(opsPrintSpeed)
|
||||
r.MustRegister(opsFlowFactor)
|
||||
r.MustRegister(opsProgress)
|
||||
r.MustRegister(opsDuration)
|
||||
r.MustRegister(opsRemaining)
|
||||
|
||||
for _, g := range gauges {
|
||||
r.MustRegister(g)
|
||||
}
|
||||
recordMetrics(context.Background(), config)
|
||||
|
||||
log.Printf("starting exporter on :%v", config.Port)
|
||||
|
||||
3
renovate.json
Normal file
3
renovate.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||
}
|
||||
Reference in New Issue
Block a user