-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 3818062
Showing
26 changed files
with
2,873 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
ARG APP_VERSION=0.0.0-SNAPSHOT | ||
ARG APP_GID=5000 | ||
ARG APP_UID=5000 | ||
|
||
## Build stage | ||
FROM golang:1.16-alpine AS build | ||
ENV CGO_ENABLED=0 | ||
WORKDIR /app | ||
|
||
# Download deps | ||
COPY go.mod ./ | ||
COPY go.sum ./ | ||
RUN go mod download | ||
|
||
# Build app | ||
ARG APP_VERSION | ||
COPY cmd cmd | ||
COPY util util | ||
RUN go build -v \ | ||
-ldflags="-X 'main.appVersion=${APP_VERSION}'" \ | ||
-o prometheus-luxor-exporter \ | ||
cmd/prometheus-luxor-exporter/*.go | ||
|
||
# Test | ||
#RUN go test -v . | ||
|
||
## Runtime stage | ||
FROM alpine:3 AS runtime | ||
WORKDIR /app | ||
|
||
ARG APP_GID | ||
ARG APP_UID | ||
RUN addgroup -g $APP_GID -S app && adduser -G app -u $APP_UID -S app | ||
|
||
COPY --from=build /app/prometheus-luxor-exporter ./ | ||
RUN chown app:app prometheus-luxor-exporter | ||
|
||
USER app | ||
ENTRYPOINT ["./prometheus-luxor-exporter"] | ||
CMD [""] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Prometheus Luxor Exporter | ||
|
||
![](examples/luxordash.png) | ||
![](examples/luxordash2.png) | ||
Fork of this repo [prometheus-ethermine-exporter](https://github.com/HON95/prometheus-ethermine-exporter). | ||
|
||
The original is an exporter for the following cryptocurrency mining pools: | ||
Ethermine, Ethermine ETC, Ethpool, Zcash Flypool, Ravencoin Flypool, BEAM Flypool. | ||
The exporter uses a unified API structure for all the listed pools, so we create a fork | ||
to be used with our graphql api. | ||
|
||
## Usage | ||
Information on how to use it can be seen [here](dev/how-to.md). | ||
|
||
## Grafana | ||
|
||
Example dashboards: | ||
|
||
[Miner dashboard](dashboard.json) | ||
|
||
## Configuration | ||
Docker Image can be found [here](https://hub.docker.com/repository/docker/luxorlabs/prometheus-luxor-exporter) | ||
|
||
## Metrics | ||
See the miner example output [here](examples/output-miner.txt) | ||
|
||
## Development | ||
Build: go build -o prometheus-luxor-exporter cmd/prometheus-luxor-exporter/*.go | ||
Lint: golint ./... | ||
|
||
# Changelog | ||
|
||
## [1.0.0] - 2022-06-24 | ||
|
||
Initial release. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package main | ||
|
||
// CurrencySymbolEthereum is a list of currency symbols. | ||
const ( | ||
CurrencySymbolEthereum = "ETH" | ||
) | ||
|
||
const namespace = "luxor" | ||
|
||
const defaultDebug = false | ||
const defaultEndpoint = ":8080" | ||
|
||
const appVersion = "0.1.0-alabama" | ||
|
||
var enableDebug = false | ||
var endpoint = defaultEndpoint |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"gitlab.com/luxorlabs/prometheus-luxor-exporter/util" | ||
"io/ioutil" | ||
"net/http" | ||
"time" | ||
) | ||
|
||
func getMinersInfo(response http.ResponseWriter, apikey string) MinerInfo { | ||
jsonData := map[string]string{ | ||
"query": ` | ||
{ | ||
miners (first: 20000 filter: {miningProfileName: {equalTo: ETH}} orderBy: ID_ASC) { | ||
nodes { | ||
workerName | ||
user { username } | ||
details1H { badShares duplicateShares efficiency hashrate lowDiffShares invalidShares revenue staleShares status updatedAt validShares } | ||
details24H { hashrate } | ||
} | ||
} | ||
} | ||
`, | ||
} | ||
jsonValue, _ := json.Marshal(jsonData) | ||
request, err := http.NewRequest("POST", "https://api.beta.luxor.tech/graphql", bytes.NewBuffer(jsonValue)) | ||
request.Header.Set("X-Lux-Api-Key", apikey) | ||
request.Header.Set("Content-Type", "application/json") | ||
|
||
client := &http.Client{Timeout: time.Second * 100} | ||
resp, err := client.Do(request) | ||
defer resp.Body.Close() | ||
if err != nil { | ||
fmt.Printf("The HTTP request failed with error %s\n", err) | ||
} | ||
rawdata, _ := ioutil.ReadAll(resp.Body) | ||
fmt.Println(string(rawdata)) | ||
|
||
var data MinerInfo | ||
util.ParseJSON(&data, response, rawdata, false, enableDebug) | ||
|
||
return data | ||
} | ||
|
||
func getPendingBalance(response http.ResponseWriter, user, apikey string) Wallet { | ||
jsonData := map[string]string{ | ||
"query": fmt.Sprintf(` | ||
{ | ||
getWallets(first: 100 uname:"%s" filter: {currencyProfileName: {equalTo: ETH}}) { | ||
nodes { | ||
pendingBalance | ||
} | ||
} | ||
}`, user), | ||
} | ||
jsonValue, _ := json.Marshal(jsonData) | ||
request, err := http.NewRequest("POST", "https://api.beta.luxor.tech/graphql", bytes.NewBuffer(jsonValue)) | ||
request.Header.Set("X-Lux-Api-Key", apikey) | ||
request.Header.Set("Content-Type", "application/json") | ||
|
||
client := &http.Client{Timeout: time.Second * 100} | ||
resp, err := client.Do(request) | ||
defer resp.Body.Close() | ||
if err != nil { | ||
fmt.Printf("The HTTP request failed with error %s\n", err) | ||
} | ||
rawdata, _ := ioutil.ReadAll(resp.Body) | ||
|
||
var wallet Wallet | ||
util.ParseJSON(&wallet, response, rawdata, false, enableDebug) | ||
|
||
return wallet | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
) | ||
|
||
func main() { | ||
parseCliArgs() | ||
if enableDebug { | ||
fmt.Printf("[DEBUG] Debug mode enabled.\n") | ||
} | ||
|
||
if err := runServer(); err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err) | ||
return | ||
} | ||
} | ||
|
||
func parseCliArgs() { | ||
flag.BoolVar(&enableDebug, "debug", defaultDebug, "Show debug messages.") | ||
flag.StringVar(&endpoint, "endpoint", defaultEndpoint, "The address-port endpoint to bind to.") | ||
|
||
// Exits on error | ||
flag.Parse() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/prometheus/client_golang/prometheus" | ||
"gitlab.com/luxorlabs/prometheus-luxor-exporter/util" | ||
"net/http" | ||
) | ||
|
||
// Builds a new registry for the miner endpoint, adds scraped data to it and returns it if successful or nil if not. | ||
func buildMinerRegistry(response http.ResponseWriter, pool *Pool, username string, statsData *minerStatsAPIData, workersData *minerWorkersAPIData) *prometheus.Registry { | ||
registry := prometheus.NewRegistry() | ||
registry.MustRegister(prometheus.NewGoCollector()) | ||
|
||
util.NewExporterMetric(registry, namespace, appVersion) | ||
|
||
// Note: Miner address isn't needed as it's the instance/target of the scrape. | ||
constLabels := prometheus.Labels{ | ||
"pool": pool.ID, | ||
"subaccount": username, | ||
} | ||
constLabelsWithCurrency := util.MergeLabels(constLabels, prometheus.Labels{ | ||
"currency": string(pool.Currency), | ||
}) | ||
|
||
// Miner info | ||
util.NewGauge(registry, namespace, "miner", "info", "Metadata about the miner.", util.MergeLabels(constLabels, prometheus.Labels{ | ||
"pool_name": pool.Name, | ||
"pool_currency": string(pool.Currency), | ||
})).Set(1) | ||
|
||
// Miner stats | ||
util.NewGauge(registry, namespace, "miner", "last_seen_seconds", "Delta between time of last statistics entry and when any workers from the miner was last seen (s).", constLabels).Set(statsData.Data.Timestamp - statsData.Data.LastSeenTimestamp) | ||
util.NewGauge(registry, namespace, "miner", "hashrate_current_hps", "Total current hash rate for a miner (H/s).", constLabels).Set(statsData.Data.CurrentHashRate) | ||
util.NewGauge(registry, namespace, "miner", "hashrate_average_hps", "Total average hash rate for a miner (H/s).", constLabels).Set(statsData.Data.AverageHashRate) | ||
util.NewGauge(registry, namespace, "miner", "shares_valid", "Total number of valid shares for a miner.", constLabels).Set(statsData.Data.ValidShares) | ||
util.NewGauge(registry, namespace, "miner", "shares_invalid", "Total number of invalid shares for a miner.", constLabels).Set(statsData.Data.InvalidShares) | ||
util.NewGauge(registry, namespace, "miner", "shares_stale", "Total number of stale shares for a miner.", constLabels).Set(statsData.Data.StaleShares) | ||
util.NewGauge(registry, namespace, "miner", "workers_active", "Number of active workers.", constLabels).Set(statsData.Data.ActiveWorkers) | ||
util.NewGauge(registry, namespace, "miner", "income_coins", "Mined coins per second.", constLabelsWithCurrency).Set(statsData.Data.CoinsPerMinute / 60) | ||
util.NewGauge(registry, namespace, "miner", "income_usd", "Mined coins per second (converted to USD).", constLabels).Set(statsData.Data.USDPerMinute / 60) | ||
util.NewGauge(registry, namespace, "miner", "income_btc", "Mined coins per second (converted to BTC).", constLabels).Set(statsData.Data.BTCPerMinute / 60) | ||
util.NewGauge(registry, namespace, "miner", "balance_unpaid_coins", "Unpaid balance for a miner.", constLabelsWithCurrency).Set(statsData.Data.UnpaidBalanceBaseUnits) | ||
util.NewGauge(registry, namespace, "miner", "balance_unpaid_usd", "Unpaid balance for a miner.", constLabels).Set(statsData.Data.UnpaidBalanceBaseUnits) | ||
// Deprecated | ||
util.NewGauge(registry, namespace, "miner", "income_minute_coins", "(Deprecated) Mined coins per minute.", constLabelsWithCurrency).Set(statsData.Data.CoinsPerMinute) | ||
util.NewGauge(registry, namespace, "miner", "income_minute_usd", "(Deprecated) Mined coins per minute (converted to USD).", constLabels).Set(statsData.Data.USDPerMinute) | ||
util.NewGauge(registry, namespace, "miner", "income_minute_btc", "(Deprecated) Mined coins per minute (converted to BTC).", constLabels).Set(statsData.Data.BTCPerMinute) | ||
|
||
// Worker stats | ||
workerLabels := make(prometheus.Labels) | ||
workerLabels["worker"] = "" | ||
workerLastSeenMetric := util.NewGaugeVec(registry, namespace, "worker", "last_seen_seconds", "Delta between time of last statistics entry and when the miner was last seen (s).", constLabels, workerLabels) | ||
workerCurrentHashRateMetric := util.NewGaugeVec(registry, namespace, "worker", "hashrate_current_hps", "Current hash rate for a worker (H/s).", constLabels, workerLabels) | ||
workerValidSharesMetric := util.NewGaugeVec(registry, namespace, "worker", "shares_valid", "Number of valid shared for a worker.", constLabels, workerLabels) | ||
workerInvalidSharesMetric := util.NewGaugeVec(registry, namespace, "worker", "shares_invalid", "Number of invalid shared for a worker.", constLabels, workerLabels) | ||
workerStaleSharesMetric := util.NewGaugeVec(registry, namespace, "worker", "shares_stale", "Number of stale shared for a worker.", constLabels, workerLabels) | ||
for _, element := range workersData.Data { | ||
labels := make(prometheus.Labels) | ||
labels["worker"] = element.Name | ||
workerLastSeenMetric.With(labels).Set(element.Timestamp - element.LastSeenTimestamp) | ||
workerCurrentHashRateMetric.With(labels).Set(element.CurrentHashRate) | ||
workerValidSharesMetric.With(labels).Set(element.ValidShares) | ||
workerInvalidSharesMetric.With(labels).Set(element.InvalidShares) | ||
workerStaleSharesMetric.With(labels).Set(element.StaleShares) | ||
} | ||
|
||
return registry | ||
} |
Oops, something went wrong.