Compare commits

..

No commits in common. "0c832c4deceec6a8fab0c008f84b20ed4234ca41" and "6fb59dd7beeb4a753cd9f9737e28992dabc46d96" have entirely different histories.

14 changed files with 152 additions and 162 deletions

View file

@ -2,10 +2,11 @@ name: Build
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: ["main"] branches: [ "main" ]
pull_request: pull_request:
branches: ["main"] branches: [ "main" ]
jobs: jobs:
build: build:
name: Run build name: Run build
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -13,4 +14,4 @@ jobs:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Build - name: Build
run: make build run: go build -o ./immich.out ./src

View file

@ -3,9 +3,9 @@ name: CodeQL
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: ["main"] branches: [ "main" ]
pull_request: pull_request:
branches: ["main"] branches: [ "main" ]
jobs: jobs:
analyze: analyze:
@ -19,21 +19,16 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
language: ["go"] language: [ 'go' ]
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@v2
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
- name: Autobuild - name: CodeQL Analysis
uses: github/codeql-action/autobuild@v3 uses: github/codeql-action/analyze@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

View file

@ -1,4 +1,4 @@
name: Docker Build name: Publish Release
on: on:
workflow_dispatch: workflow_dispatch:
@ -16,7 +16,7 @@ on:
branches: ["main"] branches: ["main"]
jobs: jobs:
build_and_push: build_docker_release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
@ -25,6 +25,16 @@ jobs:
ref: "main" ref: "main"
fetch-depth: 0 fetch-depth: 0
- name: Release tag
id: releasetag
run: |
if [ -z "${{ inputs.tag }}" ]; then
latest_release_tag=$(curl -s "https://api.github.com/repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/releases/latest" | jq -r .tag_name)
echo "release_tag=${latest_release_tag}" >> $GITHUB_ENV
else
echo "release_tag=${{ inputs.tag }}" >> $GITHUB_ENV
fi
- name: Docker meta - name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
@ -32,11 +42,9 @@ jobs:
images: | images: |
ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }} ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}
tags: | tags: |
type=raw,value=latest,enable=${{ github.event_name == 'release' }} type=raw,value=latest,enable=true
type=ref,event=branch type=sha
type=ref,event=pr type=raw,value=${{ steps.releasetag.outputs.release_tag }},enable=true
type=ref,event=tag
type=raw,value=${{ inputs.tags }},enable=${{ github.event_name == 'workflow_dispatch' }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v3
@ -50,6 +58,7 @@ jobs:
with: with:
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }}
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
@ -57,13 +66,13 @@ jobs:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GH_TOKEN }} password: ${{ secrets.GH_TOKEN }}
if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
with: with:
context: ./ context: ./
platforms: linux/arm/v7,linux/amd64,linux/arm64 platforms: linux/arm/v7,linux/amd64,linux/arm64
push: ${{ !github.event.pull_request.head.repo.fork }} push: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }}
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
build-args: BUILD_VERSION=${{ github.event.release.name }}

View file

@ -1,4 +1,4 @@
name: Tests name: Test
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
@ -13,15 +13,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Run unit tests - name: Run unit tests
run: make test run: go test -v ./src/tests
- name: Run formatter - name: Run formatter
run: cd src && test -z $(gofmt -l .) run: test -z $(gofmt -l ./src)
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.55.2
working-directory: src

View file

@ -1,22 +1,17 @@
FROM golang:1.21-alpine3.19 AS builder FROM golang:1.21-alpine3.18 AS builder
ARG BUILD_VERSION
WORKDIR /app WORKDIR /app
COPY src src COPY . .
RUN cd src && \ RUN go build -o /go/bin/immich-exporter ./src
if [ -n "${BUILD_VERSION}" ]; then \
go build -o /go/bin/immich-exporter -ldflags="-X 'main.Version=${BUILD_VERSION}'" . ; \
else \
go build -o /go/bin/immich-exporter . ; \
fi
FROM alpine:3.19
FROM alpine:3.18
COPY --from=builder /go/bin/immich-exporter /go/bin/immich-exporter COPY --from=builder /go/bin/immich-exporter /go/bin/immich-exporter
COPY package.json /go/bin/
WORKDIR /go/bin WORKDIR /go/bin
CMD ["/go/bin/immich-exporter"] CMD ["/go/bin/immich-exporter"]

View file

@ -1,20 +0,0 @@
build:
cd src && go build -o ../immich-exporter.out .
dev :
cd src && go run .
dev-env :
cd src && go run . -e
format :
cd src && test -z $(gofmt -l .)
lint:
docker run --rm -v ./src:/app -w /app golangci/golangci-lint:latest golangci-lint run -v
test:
cd src && go test -v ./tests
update:
cd src && go get -u . && go mod tidy

View file

@ -22,7 +22,7 @@ docker run --name=immich-exporter \
-e IMMICH_BASE_URL=http://192.168.1.10:8080 \ -e IMMICH_BASE_URL=http://192.168.1.10:8080 \
-e IMMICH_API_KEY=<your_api_key> \ -e IMMICH_API_KEY=<your_api_key> \
-p 8090:8090 \ -p 8090:8090 \
ghcr.io/martabal/immich-exporter martabal/immich-exporter
``` ```
### Docker-compose ### Docker-compose
@ -31,7 +31,7 @@ docker run --name=immich-exporter \
version: "2.1" version: "2.1"
services: services:
immich: immich:
image: ghcr.io/martabal/immich-exporter:latest image: martabal/immich-exporter:latest
container_name: immich-exporter container_name: immich-exporter
environment: environment:
- IMMICH_BASE_URL=http://192.168.1.10:8080 - IMMICH_BASE_URL=http://192.168.1.10:8080

View file

@ -4,16 +4,17 @@ go 1.21
require ( require (
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/prometheus/client_golang v1.18.0 github.com/prometheus/client_golang v1.17.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
) )
require ( require (
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.46.0 // indirect github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
golang.org/x/sys v0.16.0 // indirect golang.org/x/sys v0.14.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect google.golang.org/protobuf v1.31.0 // indirect
) )

View file

@ -5,18 +5,22 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
@ -25,10 +29,12 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

24
package.json Normal file
View file

@ -0,0 +1,24 @@
{
"name": "immich-exporter",
"version": "1.2.0",
"description": "exporter for immich",
"main": "src/main.go",
"scripts": {
"build" : "go build -o ./immich-exporter.out ./src && ./immich-exporter.out",
"build:env" : "go build -o ./immich-exporter.out ./src && ./immich-exporter.out -e",
"dev" : "go run ./src",
"dev:env" : "go run ./src -e",
"test": "go test -v ./src/tests",
"update": "go get -u ./src && go mod tidy"
},
"keywords": [
"exporter",
"immich",
"grafana",
"dashboard",
"metrics",
"prometheus"
],
"author": "martabal",
"license": "MIT"
}

View file

@ -3,13 +3,13 @@ package immich
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"immich-exp/models" "immich-exp/src/models"
"io" "io/ioutil"
"net/http" "net/http"
"sync" "sync"
prom "immich-exp/prometheus" prom "immich-exp/src/prometheus"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -18,32 +18,6 @@ import (
var wg sync.WaitGroup var wg sync.WaitGroup
var (
mutex sync.Mutex
)
type Data struct {
URL string
HTTPMethod string
}
var httpGetUsers = Data{
URL: "/api/user?isAll=true",
HTTPMethod: http.MethodGet,
}
var httpServerVersion = Data{
URL: "/api/server-info/version",
HTTPMethod: http.MethodGet,
}
var httpStatistics = Data{
URL: "/api/server-info/statistics",
HTTPMethod: http.MethodGet,
}
var httpGetJobs = Data{
URL: "/api/jobs",
HTTPMethod: http.MethodGet,
}
var unmarshalError = "Can not unmarshal JSON" var unmarshalError = "Can not unmarshal JSON"
func Allrequests(r *prometheus.Registry) { func Allrequests(r *prometheus.Registry) {
@ -78,45 +52,48 @@ func Analyze(r *prometheus.Registry) {
res3, err3 := (<-serverinfo)() res3, err3 := (<-serverinfo)()
if err == nil && err2 == nil && err3 == nil { if err != nil && err2 != nil && err3 != nil {
} else {
prom.SendBackMessagePreference(res3, res2, res1, r) prom.SendBackMessagePreference(res3, res2, res1, r)
} }
} }
func GetAllUsers(c chan func() (*models.StructAllUsers, error)) { func GetAllUsers(c chan func() (*models.StructAllUsers, error)) {
defer wg.Done() defer wg.Done()
resp, err := Apirequest(httpGetUsers.URL, httpGetUsers.HTTPMethod) resp, err := Apirequest("/api/user?isAll=true", "GET")
if err == nil { if err == nil {
if models.GetPromptError() == true {
body, err := io.ReadAll(resp.Body) models.SetPromptError(false)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} else { } else {
result := new(models.StructAllUsers) result := new(models.StructAllUsers)
if err := json.Unmarshal(body, &result); err != nil { if err := json.Unmarshal(body, &result); err != nil { // Parse []byte to go struct pointer
log.Error(unmarshalError) log.Error(unmarshalError)
} }
c <- (func() (*models.StructAllUsers, error) { return result, nil }) c <- (func() (*models.StructAllUsers, error) { return result, nil })
return
} }
} }
c <- (func() (*models.StructAllUsers, error) { return new(models.StructAllUsers), err })
} }
func ServerVersion(r *prometheus.Registry) { func ServerVersion(r *prometheus.Registry) {
defer wg.Done() defer wg.Done()
resp, err := Apirequest(httpServerVersion.URL, httpServerVersion.HTTPMethod) resp, err := Apirequest("/api/server-info/version", "GET")
if err == nil { if err == nil {
if models.GetPromptError() == true {
body, err := io.ReadAll(resp.Body) models.SetPromptError(false)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} else { } else {
var result models.StructServerVersion var result models.StructServerVersion
if err := json.Unmarshal(body, &result); err != nil { if err := json.Unmarshal(body, &result); err != nil { // Parse []byte to go struct pointer
log.Error(unmarshalError) log.Error(unmarshalError)
} }
@ -127,44 +104,48 @@ func ServerVersion(r *prometheus.Registry) {
func ServerInfo(c chan func() (*models.StructServerInfo, error)) { func ServerInfo(c chan func() (*models.StructServerInfo, error)) {
defer wg.Done() defer wg.Done()
resp, err := Apirequest(httpStatistics.URL, httpStatistics.HTTPMethod) resp, err := Apirequest("/api/server-info/statistics", "GET")
if err == nil { if err == nil {
body, err := io.ReadAll(resp.Body) if models.GetPromptError() == true {
models.SetPromptError(false)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} else { } else {
result := new(models.StructServerInfo) result := new(models.StructServerInfo)
if err := json.Unmarshal(body, &result); err != nil { if err := json.Unmarshal(body, &result); err != nil { // Parse []byte to go struct pointer
log.Println(unmarshalError) log.Println(unmarshalError)
} }
c <- (func() (*models.StructServerInfo, error) { return result, nil }) c <- (func() (*models.StructServerInfo, error) { return result, nil })
return
} }
} }
c <- (func() (*models.StructServerInfo, error) { return new(models.StructServerInfo), err })
} }
func GetAllJobsStatus(c chan func() (*models.StructAllJobsStatus, error)) { func GetAllJobsStatus(c chan func() (*models.StructAllJobsStatus, error)) {
defer wg.Done() defer wg.Done()
resp, err := Apirequest(httpGetJobs.URL, httpGetJobs.HTTPMethod) resp, err := Apirequest("/api/jobs", "GET")
if err == nil { if err == nil {
body, err := io.ReadAll(resp.Body) if models.GetPromptError() == true {
models.SetPromptError(false)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} else { } else {
result := new(models.StructAllJobsStatus) result := new(models.StructAllJobsStatus)
if err := json.Unmarshal(body, &result); err != nil { if err := json.Unmarshal(body, &result); err != nil { // Parse []byte to go struct pointer
log.Println(unmarshalError) log.Println(unmarshalError)
} }
c <- (func() (*models.StructAllJobsStatus, error) { return result, nil }) c <- (func() (*models.StructAllJobsStatus, error) { return result, nil })
return
} }
} }
c <- (func() (*models.StructAllJobsStatus, error) { return new(models.StructAllJobsStatus), err })
} }
func Apirequest(uri string, method string) (*http.Response, error) { func Apirequest(uri string, method string) (*http.Response, error) {
@ -179,41 +160,38 @@ func Apirequest(uri string, method string) (*http.Response, error) {
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
err := fmt.Errorf("Can't connect to server") err := fmt.Errorf("Can't connect to server")
mutex.Lock() if models.GetPromptError() == false {
if !models.GetPromptError() {
log.Error(err.Error()) log.Error(err.Error())
models.SetPromptError(true) models.SetPromptError(true)
} }
mutex.Unlock()
return resp, err return resp, err
} }
switch resp.StatusCode { switch resp.StatusCode {
case http.StatusOK: case http.StatusOK:
mutex.Lock()
if models.GetPromptError() { if models.GetPromptError() {
models.SetPromptError(false) models.SetPromptError(false)
} }
mutex.Unlock()
return resp, nil return resp, nil
case http.StatusNotFound: case http.StatusNotFound:
err := fmt.Errorf("%d", resp.StatusCode)
log.Fatal("Error code ", resp.StatusCode, " for ", models.Getbaseurl()+uri) log.Fatal("Error code ", resp.StatusCode, " for ", models.Getbaseurl()+uri)
return resp, fmt.Errorf("%d", resp.StatusCode) return resp, err
case http.StatusUnauthorized, http.StatusForbidden: case http.StatusUnauthorized, http.StatusForbidden:
err := fmt.Errorf("%d", resp.StatusCode)
log.Fatal("Api key unauthorized") log.Fatal("Api key unauthorized")
return resp, fmt.Errorf("%d", resp.StatusCode) return resp, err
default: default:
err := fmt.Errorf("%d", resp.StatusCode) err := fmt.Errorf("%d", resp.StatusCode)
mutex.Lock()
if !models.GetPromptError() { if !models.GetPromptError() {
models.SetPromptError(true) models.SetPromptError(true)
log.Debug("Error code ", resp.StatusCode) log.Debug("Error code ", resp.StatusCode)
} }
mutex.Unlock()
return resp, err return resp, err
} }

View file

@ -1,10 +1,11 @@
package main package main
import ( import (
"encoding/json"
"flag" "flag"
"fmt" "fmt"
immich "immich-exp/immich" immich "immich-exp/src/immich"
"immich-exp/models" "immich-exp/src/models"
"net/http" "net/http"
"strconv" "strconv"
@ -20,26 +21,15 @@ import (
const DEFAULTPORT = 8090 const DEFAULTPORT = 8090
var (
Version = "dev"
Author = "martabal"
ProjectName = "immich-exporter"
)
func main() { func main() {
loadenv() loadenv()
fmt.Printf("%s (version %s)\n", ProjectName, Version) projectinfo()
fmt.Println("Author: ", Author)
fmt.Println("Using log level: ", log.GetLevel())
log.Info("Immich URL: ", models.Getbaseurl()) log.Info("Immich URL: ", models.Getbaseurl())
log.Info("Started") log.Info("Started")
http.HandleFunc("/metrics", metrics) http.HandleFunc("/metrics", metrics)
addr := ":" + strconv.Itoa(models.GetPort()) addr := ":" + strconv.Itoa(models.GetPort())
log.Info("Listening on port ", models.GetPort()) log.Info("Listening on port ", models.GetPort())
err := http.ListenAndServe(addr, nil) http.ListenAndServe(addr, nil)
if err != nil {
log.Fatalln(err)
}
} }
func metrics(w http.ResponseWriter, r *http.Request) { func metrics(w http.ResponseWriter, r *http.Request) {
@ -50,6 +40,25 @@ func metrics(w http.ResponseWriter, r *http.Request) {
h.ServeHTTP(w, r) h.ServeHTTP(w, r)
} }
func projectinfo() {
fileContent, err := os.ReadFile("./package.json")
if err != nil {
log.Fatal(err)
return
}
var res map[string]interface{}
err = json.Unmarshal(fileContent, &res)
if err != nil {
log.Fatal(err)
return
}
fmt.Print(res["name"], " (version ", res["version"], ")\n")
fmt.Print("Author: ", res["author"], "\n")
fmt.Print("Using log level: ", log.GetLevel(), "\n")
}
func loadenv() { func loadenv() {
var envfile bool var envfile bool
flag.BoolVar(&envfile, "e", false, "Use .env file") flag.BoolVar(&envfile, "e", false, "Use .env file")

View file

@ -1,7 +1,7 @@
package prom package prom
import ( import (
"immich-exp/models" "immich-exp/src/models"
"strconv" "strconv"
"strings" "strings"

View file

@ -1,8 +1,8 @@
package prom package prom
import ( import (
"immich-exp/models" "immich-exp/src/models"
prom "immich-exp/prometheus" prom "immich-exp/src/prometheus"
"reflect" "reflect"
"testing" "testing"
) )