Commit bfca0f21 authored by Robert Jacob's avatar Robert Jacob

Import project.

parent 6619f8a9
package main
import (
type nextcloudCollector struct {
infoURL *url.URL
username string
password string
client *http.Client
upMetric prometheus.Gauge
authErrorsMetric prometheus.Counter
scrapeErrorsMetric prometheus.Counter
func newCollector(infoURL *url.URL, username, password string) *nextcloudCollector {
return &nextcloudCollector{
infoURL: infoURL,
username: username,
password: password,
client: &http.Client{},
upMetric: prometheus.NewGauge(prometheus.GaugeOpts{
Name: "nextcloud_up",
Help: "Shows if nextcloud is deemed up by the collector.",
authErrorsMetric: prometheus.NewCounter(prometheus.CounterOpts{
Name: "nextcloud_auth_errors_total",
Help: "Counts number of authentication errors encountered by the collector.",
scrapeErrorsMetric: prometheus.NewCounter(prometheus.CounterOpts{
Name: "nextcloud_scrape_errors_total",
Help: "Counts the number of scrape errors by this collector.",
func (c *nextcloudCollector) Describe(ch chan<- *prometheus.Desc) {
func (c *nextcloudCollector) Collect(ch chan<- prometheus.Metric) {
if err := c.collectNextcloud(ch); err != nil {
log.Printf("Error during scrape: %s", err)
func (c *nextcloudCollector) collectNextcloud(ch chan<- prometheus.Metric) error {
req, err := http.NewRequest(http.MethodGet, c.infoURL.String(), nil)
if err != nil {
return err
res, err := c.client.Do(req)
if err != nil {
return err
defer res.Body.Close()
if res.StatusCode == http.StatusUnauthorized {
return fmt.Errorf("wrong credentials")
if res.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", res.StatusCode)
return nil
package main
import (
type config struct {
ListenAddr string
InfoURL *url.URL
Username string
Password string
func parseConfig() (config, error) {
result := config{
ListenAddr: ":8080",
var rawURL string
pflag.StringVarP(&result.ListenAddr, "addr", "a", result.ListenAddr, "Address to listen on for connections.")
pflag.StringVarP(&rawURL, "url", "l", "", "URL to nextcloud serverinfo page.")
pflag.StringVarP(&result.Username, "username", "u", "", "Username for connecting to nextcloud.")
pflag.StringVarP(&result.Password, "password", "p", "", "Password for connecting to nextcloud.")
if len(rawURL) == 0 {
return result, errors.New("need to provide an info URL")
infoURL, err := url.Parse(rawURL)
if err != nil {
return result, fmt.Errorf("info URL is not valid: %s", err)
result.InfoURL = infoURL
if len(result.Username) == 0 {
return result, errors.New("need to provide a username")
if len(result.Password) == 0 {
return result, errors.New("need to provide a password")
return result, nil
func main() {
config, err := parseConfig()
if err != nil {
log.Fatalf("Error in configuration: %s", err)
log.Printf("Nextcloud server: %s User: %s", config.InfoURL.Hostname(), config.Username)
collector := newCollector(config.InfoURL, config.Username, config.Password)
if err := prometheus.Register(collector); err != nil {
log.Fatalf("Failed to register collector: %s", err)
http.Handle("/metrics", prometheus.UninstrumentedHandler())
http.Handle("/", http.RedirectHandler("/metrics", http.StatusFound))
log.Printf("Listen on %s...", config.ListenAddr)
log.Fatal(http.ListenAndServe(config.ListenAddr, nil))
package serverinfo
// ServerInfo contains the complete data received from the server.
type ServerInfo struct {
Meta Meta `xml:"meta"`
Data Data `xml:"data"`
// Meta contains meta information about the result.
type Meta struct {
Status string `xml:"status"`
StatusCode int `xml:"statuscode"`
Message string `xml:"message"`
// Data contains the status information about the instance.
type Data struct {
Nextcloud Nextcloud `xml:"nextcloud"`
Server Server `xml:"server"`
ActiveUsers ActiveUsers `xml:"activeUsers"`
// Nextcloud contains information about the nextcloud installation.
type Nextcloud struct {
System System `xml:"system"`
Storage Storage `xml:"storage"`
Shares Shares `xml:"shares"`
// System contains nextcloud configuration and system information.
type System struct {
Version string `xml:"version"`
Theme string `xml:"theme"`
EnableAvatars bool `xml:"enable_avatars"`
EnablePreviews bool `xml:"enable_previews"`
MemcacheLocal string `xml:"memcache.local"`
MemcacheDistributed string `xml:"memcache.distributed"`
MemcacheLocking string `xml:"memcache.locking"`
FilelockingEnabled bool `xml:"filelocking.enabled"`
Debug bool `xml:"debug"`
FreeSpace int `xml:"freespace"`
CPULoad []float64 `xml:"cpuload"`
MemoryTotal int `xml:"mem_total"`
MemoryFree int `xml:"mem_free"`
// Storage contains information about the nextcloud storage system.
type Storage struct {
Users int `xml:"num_users"`
Files int `xml:"num_files"`
Storages int `xml:"num_storages"`
StoragesLocal int `xml:"num_storages_local"`
StoragesHome int `xml:"num_storages_home"`
StoragesOther int `xml:"num_storages_other"`
// Shares contains information about nextcloud shares.
type Shares struct {
SharesTotal int `xml:"num_shares"`
SharesUser int `xml:"num_shares_user"`
SharesGroups int `xml:"num_shares_groups"`
SharesLink int `xml:"num_shares_link"`
SharesLinkNoPassword int `xml:"num_shares_link_no_password"`
FedSent int `xml:"num_fed_shares_sent"`
FedReceived int `xml:"num_fed_shares_received"`
// <permissions_0_1>2</permissions_0_1>
// <permissions_3_1>4</permissions_3_1>
// <permissions_0_15>2</permissions_0_15>
// <permissions_3_15>2</permissions_3_15>
// <permissions_0_31>3</permissions_0_31>
// <permissions_1_31>1</permissions_1_31>
// Server contains information about the servers running nextcloud.
type Server struct {
Webserver string `xml:"webserver"`
PHP PHP `xml:"php"`
Database Database `xml:"database"`
// PHP contains information about the PHP installation.
type PHP struct {
Version string `xml:"version"`
MemoryLimit int `xml:"memory_limit"`
MaxExecutionTime int `xml:"max_execution_time"`
UploadMaxFilesize int `xml:"upload_max_filesize"`
// Database contains information about the database used by nextcloud.
type Database struct {
Type string `xml:"type"`
Version string `xml:"version"`
Size int `xml:"size"`
// ActiveUsers contains statistics about the active users.
type ActiveUsers struct {
Last5Minutes int `xml:"last5minutes"`
LastHour int `xml:"last1hour"`
LastDay int `xml:"last24hours"`
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment