File squid-exporter-1.13.0.obscpio of Package golang-github-boynux-squid_exporter

07070100000000000081A40000000000000000000000016819A1F700000042000000000000000000000000000000000000002400000000squid-exporter-1.13.0/.dockerignore.git
.github
dashboards
helm
prometheus
vendor
Makefile
Dockerfile07070100000001000081A40000000000000000000000016819A1F70000011F000000000000000000000000000000000000002400000000squid-exporter-1.13.0/.golangci.ymllinters:
  enable:
    - errorlint
    - goimports
    - misspell
    - perfsprint
    - testifylint
    - usestdlibvars

issues:
  exclude-rules:
    - path: _test.go
      linters:
        - errcheck

linters-settings:
  goimports:
    local-prefixes: github.com/boynux/squid-exporter
07070100000002000081A40000000000000000000000016819A1F70000010E000000000000000000000000000000000000002200000000squid-exporter-1.13.0/.travis.ymllanguage: go
services:
  - docker
arch:
  - amd64
os: linux
dist: xenial
go:
- 1.16.x
deploy:
- provider: script
  on:
    tags: true
  script: bash ./deploy.sh
- provider: releases
  skip_cleanup: true
  token: $GH_TOKEN
  file: bin/squid-exporter
  on:
    tags: true
07070100000003000081A40000000000000000000000016819A1F700000C8D000000000000000000000000000000000000002900000000squid-exporter-1.13.0/CODE_OF_CONDUCT.md# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at boynux@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
07070100000004000081A40000000000000000000000016819A1F70000034F000000000000000000000000000000000000002100000000squid-exporter-1.13.0/DockerfileFROM golang:1.20-alpine as build

ARG TARGETPLATFORM
RUN echo "Building for ${TARGETPLATFORM}"

WORKDIR /go/src

COPY go.mod go.sum ./
RUN go mod download

COPY . .

RUN CGO_ENABLED=0 go build -a -ldflags '-extldflags "-s -w -static"' -o /squid-exporter .


FROM gcr.io/distroless/static:nonroot as final

LABEL org.opencontainers.image.title="Squid Exporter"
LABEL org.opencontainers.image.description="This is a Docker image for Squid Prometheus Exporter."
LABEL org.opencontainers.image.source="https://github.com/boynux/squid-exporter/"
LABEL org.opencontainers.image.licenses="MIT"

ENV SQUID_EXPORTER_LISTEN="0.0.0.0:9301"

COPY --from=build /squid-exporter /usr/local/bin/squid-exporter
# Allow /etc/hosts to be used for DNS
COPY --from=build /etc/nsswitch.conf /etc/nsswitch.conf

EXPOSE 9301

ENTRYPOINT ["/usr/local/bin/squid-exporter"]
07070100000005000081A40000000000000000000000016819A1F70000042E000000000000000000000000000000000000001E00000000squid-exporter-1.13.0/LICENSEMIT License

Copyright (c) 2017 Mohammad Arab

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
07070100000006000081A40000000000000000000000016819A1F7000002D8000000000000000000000000000000000000001F00000000squid-exporter-1.13.0/Makefile.PHONY: all fmt vet test build docker clean

all: fmt vet test build

EXE = ./bin/squid-exporter
SRC = $(shell find . -type f -name '*.go')
VERSION ?= $(shell cat VERSION)
REVISION = $(shell git rev-parse HEAD)
BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
LDFLAGS = -extldflags "-s -w -static" \
		  -X github.com/prometheus/common/version.Version=$(VERSION) \
		  -X github.com/prometheus/common/version.Revision=$(REVISION) \
		  -X github.com/prometheus/common/version.Branch=$(BRANCH)

$(EXE): $(SRC)
	CGO_ENABLED=0 GOOS=linux go build -a -ldflags '$(LDFLAGS)' -o $(EXE) .

fmt:
	go fmt ./...

vet:
	go vet ./...

test:
	go test -v ./...

build: $(EXE)

docker:
	docker build -t squid-exporter .

clean:
	rm -f $(EXE)

07070100000007000081A40000000000000000000000016819A1F700001588000000000000000000000000000000000000002000000000squid-exporter-1.13.0/README.md[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/boynux/squid-exporter)

[![Github Actions](https://github.com/boynux/squid-exporter/actions/workflows/release.yml/badge.svg)](https://github.com/boynux/squid-exporter/actions/workflows/release.yml)
[![Github Docker](https://github.com/boynux/squid-exporter/actions/workflows/docker.yml/badge.svg)](https://github.com/boynux/squid-exporter/actions/workflows/docker.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/boynux/squid-exporter)](https://goreportcard.com/report/github.com/boynux/squid-exporter)
[![Maintainability](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](https://codeclimate.com/github/boynux/squid-exporter)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3TH7YAMMEC5L4&source=url)

**Note: I've been very busy on the past couple of months with my personal life and work. Thanks for filing issues and feature requests. I'll start to go through them and provide updates very soon.**


Squid Prometheus exporter
--------------------------

Exports squid metrics in Prometheus format

**NOTE**: From release 1.0 metric names and some parameters has changed. Make sure you check the docs and update your deployments accordingly!

New
-----

* Using environment variables to configure the exporter
* Adding custom labels to metrics
* Enabling TLS for exporter via [WebConfig](https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md)

Usage:
------
Simple usage:

    squid-exporter -squid-hostname "localhost" -squid-port 3128

[Configure Prometheus](https://github.com/boynux/squid-exporter/blob/master/prometheus/prometheus.yml) to scrape metrics from `localhost:9301/metrics`

    - job_name: squid
      # squid-exporter is installed, grab stats about the local
      # squid instance.
      target_groups:
        - targets: ['localhost:9301']

To get all the parameteres, command line arguments always override default and environment variables configs:

    squid-exporter -help

The following environment variables can be used to override default parameters:

```
SQUID_EXPORTER_LISTEN
SQUID_EXPORTER_WEB_CONFIG_PATH
SQUID_EXPORTER_METRICS_PATH
SQUID_HOSTNAME
SQUID_PORT
SQUID_LOGIN
SQUID_PASSWORD
SQUID_EXTRACTSERVICETIMES
```

Usage with docker:
------
Basic setup assuming Squid is running on the same machine:

    docker run --net=host -d boynux/squid-exporter

Setup with Squid running on a different host

    docker run -p 9301:9301 -d boynux/squid-exporter -squid-hostname "192.168.0.2" -squid-port 3128 -listen ":9301"

With environment variables

    docker run -p 9301:9301 -d -e SQUID_PORT="3128" -e SQUID_HOSTNAME="192.168.0.2" -e SQUID_EXPORTER_LISTEN=":9301" boynux/squid-exporter


Build:
--------

This project is written in Go, so all the usual methods for building (or cross compiling) a Go application would work.

If you are not very familiar with Go you can download the binary from [releases](https://github.com/boynux/squid-exporter/releases).

Or build it for your OS:

`go install https://github.com/boynux/squid-exporter`

then you can find the binary in: `$GOPATH/bin/squid-exporter`

Features:
---------

- [ ] Expose Squid counters
  -  [x] Client HTTP
  -  [x] Server HTTP
  -  [x] Server ALL
  -  [x] Server FTP
  -  [x] Server Other
  -  [ ] ICP
  -  [ ] CD
  -  [x] Swap
  -  [ ] Page Faults
  -  [ ] Others
- [ ] Expose Squid service times
  - [x] HTTP requests
  - [x] Cache misses
  - [x] Cache hits
  - [x] Near hits
  - [ ] Not-Modified replies
  - [x] DNS lookups
  - [ ] ICP queries
- [ ] Expose squid Info
  - [x] Squid service info (as label)
  - [x] Connection information for squid
  - [x] Cache information for squid
  - [ ] Median Service Times (seconds)  5 min
  - [x] Resource usage for squid
  - [x] Memory accounted for
  - [x] File descriptor usage for squid
  - [x] Internal Data Structures
- [ ] Histograms
- [ ] Other metrics
- [x] Squid Authentication (Basic Auth)

FAQ:
--------

- Q: Metrics are not reported by exporter
- A: That usually means the exporter cannot reach squid server or the config manager permissions are not set corretly. To debug and mitigate:
  - First make sure the exporter service can reach to squid server IP Address (you can use telnet to test that)
  - Make sure you allow exporter to query the squid server in config you will need something like this (`172.20.0.0/16` is the network for exporter, you can also use a single IP if needed):
  ```
  #http_access allow manager localhost
  acl prometheus src 172.20.0.0/16
  http_access allow manager prometheus
  ```

- Q: Why `process_open_fds` metric is not exported?
- A: This usualy means exporter don't have permission to read `/proc/<squid_proc_id>/fd` folder. You can either

1. _[recommended]_ Set `CAP_DAC_READ_SEARCH` capability for squid exporter process (or docker). (eg. `sudo setcap 'cap_dac_read_search+ep' ./bin/squid-exporter`)
2. _[not recommended]_ Run the exporter as root.

Contribution:
-------------

Pull request and issues are very welcome.

If you found this program useful please consider donations [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3TH7YAMMEC5L4&source=url)

Copyright:
----------

[MIT License](https://opensource.org/licenses/MIT)


07070100000008000081A40000000000000000000000016819A1F700000007000000000000000000000000000000000000001E00000000squid-exporter-1.13.0/VERSION1.13.0
07070100000009000081A40000000000000000000000016819A1F70000001B000000000000000000000000000000000000002200000000squid-exporter-1.13.0/_config.ymltheme: jekyll-theme-minimal0707010000000A000041ED0000000000000000000000026819A1F700000000000000000000000000000000000000000000002000000000squid-exporter-1.13.0/collector0707010000000B000081A40000000000000000000000016819A1F700002326000000000000000000000000000000000000002A00000000squid-exporter-1.13.0/collector/client.gopackage collector

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"strings"

	"github.com/boynux/squid-exporter/types"
)

// CacheObjectClient holds information about Squid manager.
type CacheObjectClient struct {
	baseURL     string
	username    string
	password    string
	proxyHeader string
}

// SquidClient provides functionality to fetch Squid metrics.
type SquidClient interface {
	GetCounters() (types.Counters, error)
	GetServiceTimes() (types.Counters, error)
	GetInfos() (types.Counters, error)
}

/*NewCacheObjectClient initializes a new cache client */
func NewCacheObjectClient(hostname string, port int, username, password, proxyHeader string) *CacheObjectClient {
	return &CacheObjectClient{
		fmt.Sprintf("http://%s:%d/squid-internal-mgr/", hostname, port),
		username,
		password,
		proxyHeader,
	}
}

func (c *CacheObjectClient) readFromSquid(endpoint string) (*bufio.Reader, error) {
	req, err := http.NewRequest(http.MethodGet, c.baseURL+endpoint, nil)
	if err != nil {
		return nil, err
	}

	if c.username != "" && c.password != "" {
		req.SetBasicAuth(c.username, c.password)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("non-success code %d while fetching metrics", resp.StatusCode)
	}

	return bufio.NewReader(resp.Body), err
}

// GetCounters fetches counters from Squid cache manager.
func (c *CacheObjectClient) GetCounters() (types.Counters, error) {
	var counters types.Counters

	reader, err := c.readFromSquid("counters")
	if err != nil {
		return nil, fmt.Errorf("error getting counters: %w", err)
	}

	scanner := bufio.NewScanner(reader)
	for scanner.Scan() {
		if c, err := decodeCounterStrings(scanner.Text()); err != nil {
			log.Println(err)
		} else {
			counters = append(counters, c)
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return counters, err
}

// GetServiceTimes fetches service times from Squid cache manager.
func (c *CacheObjectClient) GetServiceTimes() (types.Counters, error) {
	var serviceTimes types.Counters

	reader, err := c.readFromSquid("service_times")
	if err != nil {
		return nil, fmt.Errorf("error getting service times: %w", err)
	}

	scanner := bufio.NewScanner(reader)
	for scanner.Scan() {
		if s, err := decodeServiceTimeStrings(scanner.Text()); err != nil {
			log.Println(err)
		} else if s.Key != "" {
			serviceTimes = append(serviceTimes, s)
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return serviceTimes, err
}

// GetInfos fetches info from Squid cache manager.
func (c *CacheObjectClient) GetInfos() (types.Counters, error) {
	var infos types.Counters

	reader, err := c.readFromSquid("info")
	if err != nil {
		return nil, fmt.Errorf("error getting info: %w", err)
	}

	infoVarLabels := types.Counter{Key: "squid_info", Value: 1}

	scanner := bufio.NewScanner(reader)
	for scanner.Scan() {
		if dis, err := decodeInfoStrings(scanner.Text()); err != nil {
			log.Println(err)
		} else {
			if len(dis.VarLabels) > 0 {
				if dis.VarLabels[0].Key == "5min" {
					var infoAvg5, infoAvg60 types.Counter

					infoAvg5.Key = dis.Key + "_" + dis.VarLabels[0].Key
					infoAvg60.Key = dis.Key + "_" + dis.VarLabels[1].Key

					if value, err := strconv.ParseFloat(dis.VarLabels[0].Value, 64); err == nil {
						infoAvg5.Value = value
						infos = append(infos, infoAvg5)
					}
					if value, err := strconv.ParseFloat(dis.VarLabels[1].Value, 64); err == nil {
						infoAvg60.Value = value
						infos = append(infos, infoAvg60)
					}
				} else {
					infoVarLabels.VarLabels = append(infoVarLabels.VarLabels, dis.VarLabels[0])
				}
			} else if dis.Key != "" {
				infos = append(infos, dis)
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	infos = append(infos, infoVarLabels)
	return infos, err
}

func decodeCounterStrings(line string) (types.Counter, error) {
	if equal := strings.Index(line, "="); equal >= 0 {
		if key := strings.TrimSpace(line[:equal]); len(key) > 0 {
			value := ""
			if len(line) > equal {
				value = strings.TrimSpace(line[equal+1:])
			}

			// Remove additional formating string from `sample_time`
			if slices := strings.Split(value, " "); len(slices) > 0 {
				value = slices[0]
			}

			if i, err := strconv.ParseFloat(value, 64); err == nil {
				return types.Counter{Key: key, Value: i}, nil
			}
		}
	}

	return types.Counter{}, errors.New("counter - could not parse line: " + line)
}

func decodeServiceTimeStrings(line string) (types.Counter, error) {
	if strings.HasSuffix(line, ":") { // A header line isn't a metric
		return types.Counter{}, nil
	}
	if equal := strings.Index(line, ":"); equal >= 0 {
		if key := strings.TrimSpace(line[:equal]); len(key) > 0 {
			value := ""
			if len(line) > equal {
				value = strings.TrimSpace(line[equal+1:])
			}
			key = strings.Replace(key, " ", "_", -1)
			key = strings.Replace(key, "(", "", -1)
			key = strings.Replace(key, ")", "", -1)

			if equalTwo := strings.Index(value, "%"); equalTwo >= 0 {
				if keyTwo := strings.TrimSpace(value[:equalTwo]); len(keyTwo) > 0 {
					if len(value) > equalTwo {
						value = strings.Split(strings.TrimSpace(value[equalTwo+1:]), " ")[0]
					}
					key = key + "_" + keyTwo
				}
			}

			if value, err := strconv.ParseFloat(value, 64); err == nil {
				return types.Counter{Key: key, Value: value}, nil
			}
		}
	}

	return types.Counter{}, errors.New("service times - could not parse line: " + line)
}

func decodeInfoStrings(line string) (types.Counter, error) {
	if strings.HasSuffix(line, ":") { // A header line isn't a metric
		return types.Counter{}, nil
	}

	if idx := strings.Index(line, ":"); idx >= 0 { // detect if line contain metric format like "metricName: value"
		if key := strings.TrimSpace(line[:idx]); len(key) > 0 {
			value := ""
			if len(line) > idx {
				value = strings.TrimSpace(line[idx+1:])
			}
			key = strings.Replace(key, " ", "_", -1)
			key = strings.Replace(key, "(", "", -1)
			key = strings.Replace(key, ")", "", -1)
			key = strings.Replace(key, ",", "", -1)
			key = strings.Replace(key, "/", "", -1)

			// metrics with value as string need to save as label, format like "Squid Object Cache: Version 6.1" (the 3 first metrics)
			if key == "Squid_Object_Cache" || key == "Build_Info" || key == "Service_Name" {
				if key == "Squid_Object_Cache" { // To clarify that the value is the squid version.
					key += "_Version"
					if slices := strings.Split(value, " "); len(slices) > 0 {
						value = slices[1]
					}
				}
				var infoVarLabel types.VarLabel
				infoVarLabel.Key = key
				infoVarLabel.Value = value

				var infoCounter types.Counter
				infoCounter.Key = key
				infoCounter.VarLabels = append(infoCounter.VarLabels, infoVarLabel)
				return infoCounter, nil
			} else if key == "Start_Time" || key == "Current_Time" { // discart this metrics
				return types.Counter{}, nil
			}

			// Remove additional information in value metric
			if slices := strings.Split(value, " "); len(slices) > 0 {
				if slices[0] == "5min:" && slices[2] == "60min:" { // catch metrics with avg in 5min and 60min format like "Hits as % of bytes sent: 5min: -0.0%, 60min: -0.0%"
					var infoAvg5mVarLabel types.VarLabel
					infoAvg5mVarLabel.Key = slices[0]
					infoAvg5mVarLabel.Value = slices[1]

					infoAvg5mVarLabel.Key = strings.Replace(infoAvg5mVarLabel.Key, ":", "", -1)
					infoAvg5mVarLabel.Value = strings.Replace(infoAvg5mVarLabel.Value, "%", "", -1)
					infoAvg5mVarLabel.Value = strings.Replace(infoAvg5mVarLabel.Value, ",", "", -1)

					var infoAvg60mVarLabel types.VarLabel
					infoAvg60mVarLabel.Key = slices[2]
					infoAvg60mVarLabel.Value = slices[3]

					infoAvg60mVarLabel.Key = strings.Replace(infoAvg60mVarLabel.Key, ":", "", -1)
					infoAvg60mVarLabel.Value = strings.Replace(infoAvg60mVarLabel.Value, "%", "", -1)
					infoAvg60mVarLabel.Value = strings.Replace(infoAvg60mVarLabel.Value, ",", "", -1)

					var infoAvgCounter types.Counter
					infoAvgCounter.Key = key
					infoAvgCounter.VarLabels = append(infoAvgCounter.VarLabels, infoAvg5mVarLabel, infoAvg60mVarLabel)

					return infoAvgCounter, nil
				}

				value = slices[0]
			}

			value = strings.Replace(value, "%", "", -1)
			value = strings.Replace(value, ",", "", -1)

			if i, err := strconv.ParseFloat(value, 64); err == nil {
				return types.Counter{Key: key, Value: i}, nil
			}
		}
	} else {
		// this catch the last 4 metrics format like "value metricName"
		lineTrimed := strings.TrimSpace(line)

		if idx := strings.Index(lineTrimed, " "); idx >= 0 {
			key := strings.TrimSpace(lineTrimed[idx+1:])
			key = strings.Replace(key, " ", "_", -1)
			key = strings.Replace(key, "-", "_", -1)

			value := strings.TrimSpace(lineTrimed[:idx])

			if i, err := strconv.ParseFloat(value, 64); err == nil {
				return types.Counter{Key: key, Value: i}, nil
			}
		}
	}

	return types.Counter{}, errors.New("Info - could not parse line: " + line)
}
0707010000000C000081A40000000000000000000000016819A1F700000672000000000000000000000000000000000000002F00000000squid-exporter-1.13.0/collector/client_test.gopackage collector

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/boynux/squid-exporter/types"
)

func TestReadFromSquid(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, r.RequestURI, "/squid-internal-mgr/test")
	}))
	defer ts.Close()

	coc := &CacheObjectClient{
		ts.URL + "/squid-internal-mgr/",
		"",
		"",
		"",
	}

	_, err := coc.readFromSquid("test")
	if err != nil {
		t.Fatal(err)
	}
}

func TestDecodeMetricStrings(t *testing.T) {
	tests := []struct {
		s string
		c types.Counter
		e string
		d func(string) (types.Counter, error)
	}{
		{"swap.files_cleaned=1", types.Counter{Key: "swap.files_cleaned", Value: 1}, "", decodeCounterStrings},
		{"client.http_requests=1", types.Counter{Key: "client.http_requests", Value: 1}, "", decodeCounterStrings},
		{"# test for invalid metric line", types.Counter{}, "counter - could not parse line: # test for invalid metric line", decodeCounterStrings},

		{"	HTTP Requests (All):  70%   10.00000  9.50000\n", types.Counter{Key: "HTTP_Requests_All_70", Value: 10}, "", decodeServiceTimeStrings},
		{"	Not-Modified Replies:  5%   12.00000  10.00000\n", types.Counter{Key: "Not-Modified_Replies_5", Value: 12}, "", decodeServiceTimeStrings},
		{"	ICP Queries:          85%   900.00000  1200.00000\n", types.Counter{Key: "ICP_Queries_85", Value: 900}, "", decodeServiceTimeStrings},
	}

	for _, tc := range tests {
		c, err := tc.d(tc.s)

		if tc.e != "" {
			require.EqualError(t, err, tc.e)
		}
		assert.Equal(t, tc.c, c)
	}
}
0707010000000D000081A40000000000000000000000016819A1F700000B54000000000000000000000000000000000000002C00000000squid-exporter-1.13.0/collector/counters.gopackage collector

import (
	"fmt"
	"strings"

	"github.com/prometheus/client_golang/prometheus"
)

type squidCounter struct {
	Section     string
	Counter     string
	Suffix      string
	Description string
}

var squidCounters = []squidCounter{
	{"client_http", "requests", "total", "The total number of client requests"},
	{"client_http", "hits", "total", "The total number of client cache hits"},
	{"client_http", "errors", "total", "The total number of client http errors"},
	{"client_http", "kbytes_in", "kbytes_total", "The total number of client kbytes received"},
	{"client_http", "kbytes_out", "kbytes_total", "The total number of client kbytes transferred"},
	{"client_http", "hit_kbytes_out", "bytes_total", "The total number of client kbytes cache hit"},

	{"server.http", "requests", "total", "The total number of server http requests"},
	{"server.http", "errors", "total", "The total number of server http errors"},
	{"server.http", "kbytes_in", "kbytes_total", "The total number of server http kbytes received"},
	{"server.http", "kbytes_out", "kbytes_total", "The total number of server http kbytes transferred"},

	{"server.all", "requests", "total", "The total number of server all requests"},
	{"server.all", "errors", "total", "The total number of server all errors"},
	{"server.all", "kbytes_in", "kbytes_total", "The total number of server kbytes received"},
	{"server.all", "kbytes_out", "kbytes_total", "The total number of server kbytes transferred"},

	{"server.ftp", "requests", "total", "The total number of server ftp requests"},
	{"server.ftp", "errors", "total", "The total number of server ftp errors"},
	{"server.ftp", "kbytes_in", "kbytes_total", "The total number of server ftp kbytes received"},
	{"server.ftp", "kbytes_out", "kbytes_total", "The total number of server ftp kbytes transferred"},

	{"server.other", "requests", "total", "The total number of server other requests"},
	{"server.other", "errors", "total", "The total number of server other errors"},
	{"server.other", "kbytes_in", "kbytes_total", "The total number of server other kbytes received"},
	{"server.other", "kbytes_out", "kbytes_total", "The total number of server other kbytes transferred"},

	{"swap", "ins", "total", "The number of objects read from disk"},
	{"swap", "outs", "total", "The number of objects saved to disk"},
	{"swap", "files_cleaned", "total", "The number of orphaned cache files removed by the periodic cleanup procedure"},
}

func generateSquidCounters(labels []string) descMap {
	counters := descMap{}

	for i := range squidCounters {
		counter := squidCounters[i]

		counters[fmt.Sprintf("%s.%s", counter.Section, counter.Counter)] = prometheus.NewDesc(
			prometheus.BuildFQName(namespace, strings.Replace(counter.Section, ".", "_", -1),
				fmt.Sprintf("%s_%s", counter.Counter, counter.Suffix)),
			counter.Description,
			labels, nil,
		)
	}

	return counters
}
0707010000000E000081A40000000000000000000000016819A1F700000B6C000000000000000000000000000000000000002900000000squid-exporter-1.13.0/collector/infos.gopackage collector

import (
	"strings"

	"github.com/prometheus/client_golang/prometheus"
)

type squidInfos struct {
	Section     string
	Description string
	Unit        string
}

var squidInfoss = []squidInfos{
	{"Number_of_clients_accessing_cache", "", "number"},
	{"Number_of_HTTP_requests_received", "", "number"},
	{"Number_of_ICP_messages_received", "", "number"},
	{"Number_of_ICP_messages_sent", "", "number"},
	{"Number_of_queued_ICP_replies", "", "number"},
	{"Number_of_HTCP_messages_received", "", "number"},
	{"Number_of_HTCP_messages_sent", "", "number"},
	{"Request_failure_ratio", "", "%"},
	{"Average_HTTP_requests_per_minute_since_start", "", "%"},
	{"Average_ICP_messages_per_minute_since_start", "", "%"},
	{"Select_loop_called", "", "number"},
	{"Hits_as_%_of_all_requests_5min", "", "%"},
	{"Hits_as_%_of_bytes_sent_5min", "", "%"},
	{"Memory_hits_as_%_of_hit_requests_5min", "", "%"},
	{"Disk_hits_as_%_of_hit_requests_5min", "", "%"},
	{"Hits_as_%_of_all_requests_60min", "", "%"},
	{"Hits_as_%_of_bytes_sent_60min", "", "%"},
	{"Memory_hits_as_%_of_hit_requests_60min", "", "%"},
	{"Disk_hits_as_%_of_hit_requests_60min", "", "%"},
	{"Storage_Swap_size", "", "KB"},
	{"Storage_Swap_capacity", "", "% use"},
	{"Storage_Mem_size", "", "KB"},
	{"Storage_Mem_capacity", "", "% used"},
	{"Mean_Object_Size", "", "KB"},
	{"Requests_given_to_unlinkd", "", "number"},
	{"UP_Time", "time squid is up", "seconds"},
	{"CPU_Time", "", "seconds"},
	{"CPU_Usage", "of cpu usage", "%"},
	{"CPU_Usage_5_minute_avg", "of cpu usage", "%"},
	{"CPU_Usage_60_minute_avg", "of cpu usage", "%"},
	{"Maximum_Resident_Size", "", "KB"},
	{"Page_faults_with_physical_i_o", "", "number"},
	{"Total_accounted", "", "KB"},
	{"memPoolAlloc_calls", "", "number"},
	{"memPoolFree_calls", "", "number"},
	{"Maximum_number_of_file_descriptors", "", "number"},
	{"Largest_file_desc_currently_in_use", "", "number"},
	{"Number_of_file_desc_currently_in_use", "", "number"},
	{"Files_queued_for_open", "", "number"},
	{"Available_number_of_file_descriptors", "", "number"},
	{"Reserved_number_of_file_descriptors", "", "number"},
	{"Store_Disk_files_open", "", "number"},
	{"StoreEntries", "", "number"},
	{"StoreEntries_with_MemObjects", "", "number"},
	{"Hot_Object_Cache_Items", "", "number"},
	{"on_disk_objects", "", "number"},
}

func generateSquidInfos(labels []string) descMap {
	infos := descMap{}

	for i := range squidInfoss {
		info := squidInfoss[i]

		var key string
		var name string
		var description string

		key = info.Section
		name = prometheus.BuildFQName(namespace, "info", strings.Replace(info.Section, "%", "pct", -1))

		if info.Description == "" {
			description = strings.Replace(info.Section, "_", " ", -1)
		} else {
			description = info.Description
		}

		description = description + " in " + info.Unit

		infos[key] = prometheus.NewDesc(
			name,
			description,
			labels, nil,
		)
	}

	return infos
}
0707010000000F000081A40000000000000000000000016819A1F700000E03000000000000000000000000000000000000002B00000000squid-exporter-1.13.0/collector/metrics.gopackage collector

import (
	"log"
	"time"

	"github.com/prometheus/client_golang/prometheus"

	"github.com/boynux/squid-exporter/config"
)

type descMap map[string]*prometheus.Desc

const (
	namespace = "squid"
	timeout   = 10 * time.Second
)

var (
	counters            descMap
	serviceTimes        descMap // ExtractServiceTimes decides if we want to extract service times
	ExtractServiceTimes bool
	infos               descMap
)

// Exporter entry point to Squid exporter.
type Exporter struct {
	client SquidClient

	hostname string
	port     int

	labels config.Labels
	up     *prometheus.GaugeVec
}

type CollectorConfig struct {
	Hostname    string
	Port        int
	Login       string
	Password    string
	Labels      config.Labels
	ProxyHeader string
}

// New initializes a new exporter.
func New(c *CollectorConfig) *Exporter {
	counters = generateSquidCounters(c.Labels.Keys)
	if ExtractServiceTimes {
		serviceTimes = generateSquidServiceTimes(c.Labels.Keys)
	}

	infos = generateSquidInfos(c.Labels.Keys)

	return &Exporter{
		NewCacheObjectClient(c.Hostname, c.Port, c.Login, c.Password, c.ProxyHeader),

		c.Hostname,
		c.Port,

		c.Labels,
		prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "up",
			Help:      "Was the last query of squid successful?",
		}, []string{"host"}),
	}
}

// Describe describes all the metrics ever exported by the ECS exporter. It
// implements prometheus.Collector.
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
	e.up.Describe(ch)

	for _, v := range counters {
		ch <- v
	}

	if ExtractServiceTimes {
		for _, v := range serviceTimes {
			ch <- v
		}
	}

	for _, v := range infos {
		ch <- v
	}
}

// Collect fetches metrics from Squid manager and expose them to Prometheus.
func (e *Exporter) Collect(c chan<- prometheus.Metric) {
	insts, err := e.client.GetCounters()

	if err == nil {
		e.up.With(prometheus.Labels{"host": e.hostname}).Set(1)
		for i := range insts {
			if d, ok := counters[insts[i].Key]; ok {
				c <- prometheus.MustNewConstMetric(d, prometheus.CounterValue, insts[i].Value, e.labels.Values...)
			}
		}
	} else {
		e.up.With(prometheus.Labels{"host": e.hostname}).Set(0)
		log.Println("Could not fetch counter metrics from squid instance: ", err)
	}

	if ExtractServiceTimes {
		insts, err = e.client.GetServiceTimes()

		if err == nil {
			for i := range insts {
				if d, ok := serviceTimes[insts[i].Key]; ok {
					c <- prometheus.MustNewConstMetric(d, prometheus.GaugeValue, insts[i].Value, e.labels.Values...)
				}
			}
		} else {
			log.Println("Could not fetch service times metrics from squid instance: ", err)
		}
	}

	insts, err = e.client.GetInfos()
	if err == nil {
		for i := range insts {
			if d, ok := infos[insts[i].Key]; ok {
				c <- prometheus.MustNewConstMetric(d, prometheus.GaugeValue, insts[i].Value, e.labels.Values...)
			} else if insts[i].Key == "squid_info" {
				infoMetricName := prometheus.BuildFQName(namespace, "info", "service")
				var labelsKeys []string
				var labelsValues []string

				for z := range insts[i].VarLabels {
					labelsKeys = append(labelsKeys, insts[i].VarLabels[z].Key)
					labelsValues = append(labelsValues, insts[i].VarLabels[z].Value)
				}

				infoDesc := prometheus.NewDesc(
					infoMetricName,
					"Metrics as string from info on cache_object",
					labelsKeys,
					nil,
				)
				c <- prometheus.MustNewConstMetric(infoDesc, prometheus.GaugeValue, insts[i].Value, labelsValues...)
			}
		}
	} else {
		log.Println("Could not fetch info metrics from squid instance: ", err)
	}

	e.up.Collect(c)
}
07070100000010000081A40000000000000000000000016819A1F700001B4D000000000000000000000000000000000000003100000000squid-exporter-1.13.0/collector/service_times.gopackage collector

import (
	"fmt"
	"strings"

	"github.com/prometheus/client_golang/prometheus"
)

type squidServiceTimes struct {
	Section     string
	Counter     string
	Suffix      string
	Description string
}

var squidServiceTimess = []squidServiceTimes{
	{"HTTP_Requests", "All", "5", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "10", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "15", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "20", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "25", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "30", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "35", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "40", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "45", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "50", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "55", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "60", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "65", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "70", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "75", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "80", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "85", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "90", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "95", "Service Time Percentiles 5min"},
	{"HTTP_Requests", "All", "100", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "5", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "10", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "15", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "20", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "25", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "30", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "35", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "40", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "45", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "50", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "55", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "60", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "65", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "70", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "75", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "80", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "85", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "90", "Service Time Percentiles 5min"},
	{"Cache_Misses", "", "95", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "5", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "10", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "15", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "20", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "25", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "30", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "35", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "40", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "45", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "50", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "55", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "60", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "65", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "70", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "75", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "80", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "85", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "90", "Service Time Percentiles 5min"},
	{"Cache_Hits", "", "95", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "5", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "10", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "15", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "20", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "25", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "30", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "35", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "40", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "45", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "50", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "55", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "60", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "65", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "70", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "75", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "80", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "85", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "90", "Service Time Percentiles 5min"},
	{"Near_Hits", "", "95", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "5", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "10", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "15", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "20", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "25", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "30", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "35", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "40", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "45", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "50", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "55", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "60", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "65", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "70", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "75", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "80", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "85", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "90", "Service Time Percentiles 5min"},
	{"DNS_Lookups", "", "95", "Service Time Percentiles 5min"},
}

func generateSquidServiceTimes(labels []string) descMap {
	serviceTimes := descMap{}

	for i := range squidServiceTimess {
		serviceTime := squidServiceTimess[i]

		var key, name string

		if serviceTime.Counter != "" {
			key = fmt.Sprintf("%s_%s_%s", serviceTime.Section, serviceTime.Counter, serviceTime.Suffix)
			name = prometheus.BuildFQName(namespace, strings.Replace(serviceTime.Section, ".", "_", -1),
				fmt.Sprintf("%s_%s", serviceTime.Counter, serviceTime.Suffix))
		} else {
			key = fmt.Sprintf("%s_%s", serviceTime.Section, serviceTime.Suffix)
			name = prometheus.BuildFQName(namespace, strings.Replace(serviceTime.Section, ".", "_", -1),
				serviceTime.Suffix)
		}

		serviceTimes[key] = prometheus.NewDesc(
			name,
			serviceTime.Description,
			labels, nil,
		)
	}

	return serviceTimes
}
07070100000011000041ED0000000000000000000000026819A1F700000000000000000000000000000000000000000000001D00000000squid-exporter-1.13.0/config07070100000012000081A40000000000000000000000016819A1F700001174000000000000000000000000000000000000002700000000squid-exporter-1.13.0/config/config.gopackage config

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
)

const (
	defaultListenAddress       = "127.0.0.1:9301"
	defaultWebConfigPath       = ""
	defaultListenPort          = 9301
	defaultMetricsPath         = "/metrics"
	defaultSquidHostname       = "localhost"
	defaultSquidPort           = 3128
	defaultExtractServiceTimes = true
	defaultUseProxyHeader      = false
)

const (
	squidExporterListenKey        = "SQUID_EXPORTER_LISTEN"
	squidExporterWebConfigPathKey = "SQUID_EXPORTER_WEB_CONFIG_PATH"
	squidExporterMetricsPathKey   = "SQUID_EXPORTER_METRICS_PATH"
	squidHostnameKey              = "SQUID_HOSTNAME"
	squidPortKey                  = "SQUID_PORT"
	squidLoginKey                 = "SQUID_LOGIN"
	squidPasswordKey              = "SQUID_PASSWORD"
	squidPidfile                  = "SQUID_PIDFILE"
	squidExtractServiceTimes      = "SQUID_EXTRACTSERVICETIMES"
	squidUseProxyHeader           = "SQUID_USE_PROXY_HEADER"
)

var (
	VersionFlag *bool
)

type Labels struct {
	Keys   []string
	Values []string
}

// Config configurations for exporter.
type Config struct {
	ListenAddress       string
	WebConfigPath       string
	MetricPath          string
	Labels              Labels
	ExtractServiceTimes bool

	SquidHostname string
	SquidPort     int
	Login         string
	Password      string
	Pidfile       string

	UseProxyHeader bool
}

// NewConfig creates a new config object from command line args.
func NewConfig() *Config {
	c := &Config{}

	flag.StringVar(&c.ListenAddress, "listen",
		loadEnvStringVar(squidExporterListenKey, defaultListenAddress), "Address and Port to bind exporter, in host:port format")
	flag.StringVar(&c.WebConfigPath, "web.config.file", loadEnvStringVar(squidExporterWebConfigPathKey, defaultWebConfigPath),
		"Path to configuration file that can enable TLS or authentication. See: https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md")
	flag.StringVar(&c.MetricPath, "metrics-path",
		loadEnvStringVar(squidExporterMetricsPathKey, defaultMetricsPath), "Metrics path to expose prometheus metrics")

	flag.BoolVar(&c.ExtractServiceTimes, "extractservicetimes",
		loadEnvBoolVar(squidExtractServiceTimes, defaultExtractServiceTimes), "Extract service times metrics")

	flag.Var(&c.Labels, "label", "Custom metrics to attach to metrics, use -label multiple times for each additional label")

	flag.StringVar(&c.SquidHostname, "squid-hostname",
		loadEnvStringVar(squidHostnameKey, defaultSquidHostname), "Squid hostname")
	flag.IntVar(&c.SquidPort, "squid-port",
		loadEnvIntVar(squidPortKey, defaultSquidPort), "Squid port to read metrics")

	flag.StringVar(&c.Login, "squid-login", loadEnvStringVar(squidLoginKey, ""), "Login to squid service")
	flag.StringVar(&c.Password, "squid-password", loadEnvStringVar(squidPasswordKey, ""), "Password to squid service")

	flag.StringVar(&c.Pidfile, "squid-pidfile", loadEnvStringVar(squidPidfile, ""), "Optional path to the squid PID file for additional metrics")

	flag.BoolVar(&c.UseProxyHeader, "squid-use-proxy-header",
		loadEnvBoolVar(squidUseProxyHeader, defaultUseProxyHeader), "Use proxy headers when fetching metrics")

	VersionFlag = flag.Bool("version", false, "Print the version and exit")

	flag.Parse()

	return c
}

func loadEnvBoolVar(key string, def bool) bool {
	val := os.Getenv(key)
	if val == "" {
		return def
	}
	switch strings.ToLower(val) {
	case "true":
		return true
	case "false":
		return false
	default:
		return def
	}
}

func loadEnvStringVar(key, def string) string {
	val := os.Getenv(key)
	if val == "" {
		return def
	}

	return val
}

func loadEnvIntVar(key string, def int) int {
	valStr := os.Getenv(key)
	if valStr != "" {
		val, err := strconv.ParseInt(valStr, 0, 32)
		if err == nil {
			return int(val)
		}

		log.Printf("Error parsing  %s='%s'. Integer value expected", key, valStr)
	}

	return def
}

func (l *Labels) String() string {
	var lbls []string
	for i := range l.Keys {
		lbls = append(lbls, l.Keys[i]+"="+l.Values[i])
	}

	return strings.Join(lbls, ", ")
}

func (l *Labels) Set(value string) error {
	args := strings.Split(value, "=")

	if len(args) != 2 || len(args[1]) < 1 {
		return errors.New("label must be in 'key=value' format")
	}

	for _, key := range l.Keys {
		if key == args[0] {
			return fmt.Errorf("labels must be distinct; found duplicate key %q", args[0])
		}
	}
	l.Keys = append(l.Keys, args[0])
	l.Values = append(l.Values, args[1])

	return nil
}
07070100000013000041ED0000000000000000000000026819A1F700000000000000000000000000000000000000000000002100000000squid-exporter-1.13.0/dashboards07070100000014000081A40000000000000000000000016819A1F700003603000000000000000000000000000000000000003D00000000squid-exporter-1.13.0/dashboards/squid-sample-dashboard.json{
  "__inputs": [],
  "__requires": [
    {
      "type": "grafana",
      "id": "grafana",
      "name": "Grafana",
      "version": "5.2.4"
    },
    {
      "type": "panel",
      "id": "graph",
      "name": "Graph",
      "version": "5.0.0"
    },
    {
      "type": "panel",
      "id": "singlestat",
      "name": "Singlestat",
      "version": "5.0.0"
    },
    {
      "type": "panel",
      "id": "text",
      "name": "Text",
      "version": "5.0.0"
    }
  ],
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": "-- Grafana --",
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "gnetId": null,
  "graphTooltip": 0,
  "id": null,
  "iteration": 1536353270000,
  "links": [],
  "panels": [
    {
      "content": "<h1><center>Squid Sample Dashboard</center></h1>",
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 0,
        "y": 0
      },
      "id": 10,
      "links": [],
      "mode": "html",
      "title": "",
      "type": "text"
    },
    {
      "cacheTimeout": null,
      "colorBackground": true,
      "colorValue": false,
      "colors": [
        "#d44a3a",
        "rgba(237, 129, 40, 0.89)",
        "#299c46"
      ],
      "datasource": "$datasource",
      "format": "none",
      "gauge": {
        "maxValue": 100,
        "minValue": 0,
        "show": false,
        "thresholdLabels": false,
        "thresholdMarkers": true
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 6,
        "y": 0
      },
      "id": 14,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "200%",
      "prefix": "",
      "prefixFontSize": "200%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": true
      },
      "tableColumn": "",
      "targets": [
        {
          "expr": "up{job='squid'}",
          "format": "time_series",
          "intervalFactor": 1,
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "thresholds": "0,1",
      "title": "Services Up",
      "type": "singlestat",
      "valueFontSize": "200%",
      "valueMaps": [
        {
          "op": "=",
          "text": "N/A",
          "value": "null"
        }
      ],
      "valueName": "current"
    },
    {
      "cacheTimeout": null,
      "colorBackground": false,
      "colorValue": false,
      "colors": [
        "#299c46",
        "rgba(237, 129, 40, 0.89)",
        "#d44a3a"
      ],
      "datasource": "$datasource",
      "format": "percentunit",
      "gauge": {
        "maxValue": 100,
        "minValue": 0,
        "show": false,
        "thresholdLabels": false,
        "thresholdMarkers": true
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 12,
        "y": 0
      },
      "id": 8,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "50%",
      "prefix": "",
      "prefixFontSize": "50%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": false
      },
      "tableColumn": "",
      "targets": [
        {
          "expr": "squid_client_http_hit_kbytes_out_bytes_total / squid_client_http_kbytes_out_kbytes_total",
          "format": "time_series",
          "intervalFactor": 1,
          "refId": "A"
        }
      ],
      "thresholds": "",
      "title": "Bytes Hit Rate",
      "type": "singlestat",
      "valueFontSize": "80%",
      "valueMaps": [
        {
          "op": "=",
          "text": "N/A",
          "value": "null"
        }
      ],
      "valueName": "avg"
    },
    {
      "cacheTimeout": null,
      "colorBackground": false,
      "colorValue": false,
      "colors": [
        "#299c46",
        "rgba(237, 129, 40, 0.89)",
        "#d44a3a"
      ],
      "datasource": "$datasource",
      "format": "percentunit",
      "gauge": {
        "maxValue": 100,
        "minValue": 0,
        "show": false,
        "thresholdLabels": false,
        "thresholdMarkers": true
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 16,
        "y": 0
      },
      "id": 6,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "50%",
      "prefix": "",
      "prefixFontSize": "50%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": false
      },
      "tableColumn": "",
      "targets": [
        {
          "expr": "squid_client_http_hits_total / squid_client_http_requests_total",
          "format": "time_series",
          "intervalFactor": 1,
          "legendFormat": "Hit rate",
          "refId": "A"
        }
      ],
      "thresholds": "",
      "title": "Catch Hit Rate",
      "type": "singlestat",
      "valueFontSize": "80%",
      "valueMaps": [
        {
          "op": "=",
          "text": "N/A",
          "value": "null"
        }
      ],
      "valueName": "avg"
    },
    {
      "cacheTimeout": null,
      "colorBackground": false,
      "colorValue": false,
      "colors": [
        "#299c46",
        "rgba(237, 129, 40, 0.89)",
        "#d44a3a"
      ],
      "datasource": "$datasource",
      "format": "percentunit",
      "gauge": {
        "maxValue": 100,
        "minValue": 0,
        "show": false,
        "thresholdLabels": false,
        "thresholdMarkers": true
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 20,
        "y": 0
      },
      "id": 12,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "50%",
      "prefix": "",
      "prefixFontSize": "50%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": false
      },
      "tableColumn": "",
      "targets": [
        {
          "expr": "squid_client_http_errors_total / squid_client_http_requests_total",
          "format": "time_series",
          "intervalFactor": 1,
          "refId": "A"
        }
      ],
      "thresholds": "",
      "title": "Error Rate",
      "type": "singlestat",
      "valueFontSize": "80%",
      "valueMaps": [
        {
          "op": "=",
          "text": "N/A",
          "value": "null"
        }
      ],
      "valueName": "avg"
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": "$datasource",
      "fill": 1,
      "gridPos": {
        "h": 6,
        "w": 12,
        "x": 0,
        "y": 3
      },
      "id": 2,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": true,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 1,
      "links": [],
      "nullPointMode": "null",
      "percentage": false,
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "expr": "rate(squid_client_http_requests_total[5m])",
          "format": "time_series",
          "interval": "",
          "intervalFactor": 1,
          "legendFormat": "Total Requests",
          "refId": "B"
        },
        {
          "expr": "rate(squid_client_http_hits_total[5m])",
          "format": "time_series",
          "interval": "",
          "intervalFactor": 1,
          "legendFormat": "Total HTTP hits",
          "refId": "A"
        },
        {
          "expr": "rate(squid_client_http_errors_total[5m])",
          "format": "time_series",
          "intervalFactor": 1,
          "legendFormat": "Total Errors",
          "refId": "C"
        }
      ],
      "thresholds": [],
      "timeFrom": null,
      "timeShift": null,
      "title": "Client Requests",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "reqps",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": "$datasource",
      "fill": 1,
      "gridPos": {
        "h": 6,
        "w": 12,
        "x": 12,
        "y": 3
      },
      "id": 4,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": true,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 1,
      "links": [],
      "nullPointMode": "null",
      "percentage": false,
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "expr": "rate(squid_client_http_kbytes_in_kbytes_total[5m]) * -1",
          "format": "time_series",
          "interval": "",
          "intervalFactor": 1,
          "legendFormat": "HTTP Traffic in",
          "refId": "A"
        },
        {
          "expr": "rate(squid_client_http_kbytes_out_kbytes_total[5m])",
          "format": "time_series",
          "intervalFactor": 1,
          "legendFormat": "HTTP Traffic Out",
          "refId": "B"
        },
        {
          "expr": "rate(squid_client_http_hit_kbytes_out_bytes_total[5m])",
          "format": "time_series",
          "interval": "",
          "intervalFactor": 1,
          "legendFormat": "HTTP Traffic Out Hits",
          "refId": "C"
        }
      ],
      "thresholds": [],
      "timeFrom": null,
      "timeShift": null,
      "title": "Client Traffic",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "KBs",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    }
  ],
  "schemaVersion": 16,
  "style": "dark",
  "tags": [],
  "templating": {
    "list": [
      {
        "current": {
          "text": "default",
          "value": "default"
        },
        "hide": 0,
        "label": null,
        "name": "datasource",
        "options": [],
        "query": "prometheus",
        "refresh": 1,
        "regex": "",
        "type": "datasource"
      }
    ]
  },
  "time": {
    "from": "now-6h",
    "to": "now"
  },
  "timepicker": {
    "refresh_intervals": [
      "5s",
      "10s",
      "30s",
      "1m",
      "5m",
      "15m",
      "30m",
      "1h",
      "2h",
      "1d"
    ],
    "time_options": [
      "5m",
      "15m",
      "1h",
      "6h",
      "12h",
      "24h",
      "2d",
      "7d",
      "30d"
    ]
  },
  "timezone": "",
  "title": "Squid Sample Dashboard",
  "uid": "yRc_Bj2ik",
  "version": 3
}07070100000015000081A40000000000000000000000016819A1F70000015F000000000000000000000000000000000000002000000000squid-exporter-1.13.0/deploy.sh#!/bin/bash

# Travis Docker deploy script
IMAGE_NAME="boynux/squid-exporter"
IMAGE_TAG=${TRAVIS_TAG:-latest}

docker --version
docker build -t $IMAGE_NAME:$IMAGE_TAG .
docker tag $IMAGE_NAME:$IMAGE_TAG $IMAGE_NAME:latest
echo $DOCKER_API_KEY | docker login -u boynux --password-stdin
docker push $IMAGE_NAME:$IMAGE_TAG
docker push $IMAGE_NAME:latest
07070100000016000081A40000000000000000000000016819A1F700000524000000000000000000000000000000000000001D00000000squid-exporter-1.13.0/go.modmodule github.com/boynux/squid-exporter

go 1.20

require (
	github.com/go-kit/log v0.2.1
	github.com/pires/go-proxyproto v0.6.2
	github.com/prometheus/client_golang v1.19.0
	github.com/prometheus/common v0.53.0
	github.com/prometheus/exporter-toolkit v0.11.0
	github.com/stretchr/testify v1.7.0
)

require (
	github.com/beorn7/perks v1.0.1 // indirect
	github.com/cespare/xxhash/v2 v2.2.0 // indirect
	github.com/coreos/go-systemd/v22 v22.5.0 // indirect
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/go-logfmt/logfmt v0.5.1 // indirect
	github.com/golang/protobuf v1.5.3 // indirect
	github.com/jpillora/backoff v1.0.0 // indirect
	github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	github.com/prometheus/client_model v0.6.0 // indirect
	github.com/prometheus/procfs v0.12.0 // indirect
	golang.org/x/crypto v0.21.0 // indirect
	golang.org/x/net v0.22.0 // indirect
	golang.org/x/oauth2 v0.18.0 // indirect
	golang.org/x/sync v0.5.0 // indirect
	golang.org/x/sys v0.18.0 // indirect
	golang.org/x/text v0.14.0 // indirect
	google.golang.org/appengine v1.6.7 // indirect
	google.golang.org/protobuf v1.33.0 // indirect
	gopkg.in/yaml.v2 v2.4.0 // indirect
	gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
07070100000017000081A40000000000000000000000016819A1F7000019FA000000000000000000000000000000000000001D00000000squid-exporter-1.13.0/go.sumgithub.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.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8=
github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
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.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE=
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g=
github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
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=
07070100000018000041ED0000000000000000000000036819A1F700000000000000000000000000000000000000000000001B00000000squid-exporter-1.13.0/helm07070100000019000081A40000000000000000000000016819A1F70000015D000000000000000000000000000000000000002700000000squid-exporter-1.13.0/helm/.helmignore# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
0707010000001A000081A40000000000000000000000016819A1F70000008F000000000000000000000000000000000000002600000000squid-exporter-1.13.0/helm/Chart.yamlapiVersion: v2
name: squid-exporter
description: A helm chart to deploy Squid Exporter.
type: application
version: 0.1.0
appVersion: "v1.10.3"
0707010000001B000041ED0000000000000000000000026819A1F700000000000000000000000000000000000000000000002500000000squid-exporter-1.13.0/helm/templates0707010000001C000081A40000000000000000000000016819A1F7000006EF000000000000000000000000000000000000002F00000000squid-exporter-1.13.0/helm/templates/NOTES.txt1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
  {{- range .paths }}
  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
  {{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "squid-exporter.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "squid-exporter.fullname" . }}'
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "squid-exporter.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
  echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "squid-exporter.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
  export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}
0707010000001D000081A40000000000000000000000016819A1F7000007D6000000000000000000000000000000000000003200000000squid-exporter-1.13.0/helm/templates/_helpers.tpl{{/*
Expand the name of the chart.
*/}}
{{- define "squid-exporter.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "squid-exporter.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "squid-exporter.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "squid-exporter.labels" -}}
helm.sh/chart: {{ include "squid-exporter.chart" . }}
{{ include "squid-exporter.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
squid-exporter.boynux.com/proxy-hostname: {{ .Values.squidConfig.hostname }}
squid-exporter.boynux.com/proxy-port: {{ .Values.squidConfig.port | quote }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "squid-exporter.selectorLabels" -}}
app.kubernetes.io/name: {{ include "squid-exporter.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "squid-exporter.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "squid-exporter.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
0707010000001E000081A40000000000000000000000016819A1F700000986000000000000000000000000000000000000003500000000squid-exporter-1.13.0/helm/templates/deployment.yamlapiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "squid-exporter.fullname" . }}
  labels:
    {{- include "squid-exporter.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "squid-exporter.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
      {{- with .Values.podAnnotations }}
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        {{- include "squid-exporter.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "squid-exporter.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          envFrom:
            - secretRef:
                name: {{ include "squid-exporter.fullname" . }}
          env:
            - name: SQUID_EXPORTER_LISTEN
              value: "0.0.0.0:9301"
            - name: SQUID_EXPORTER_METRICS_PATH
              value: /metrics
            - name: SQUID_HOSTNAME
              value: {{ required ".Values.squidConfig.hostname must be defined" .Values.squidConfig.hostname }}
            - name: SQUID_PORT
              value: {{ .Values.squidConfig.port | quote }}
          ports:
            - name: metrics
              containerPort: 9301
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: metrics
          readinessProbe:
            httpGet:
              path: /
              port: metrics
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
0707010000001F000081A40000000000000000000000016819A1F70000082D000000000000000000000000000000000000003200000000squid-exporter-1.13.0/helm/templates/ingress.yaml{{- if .Values.ingress.enabled -}}
{{- $fullName := include "squid-exporter.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
  {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
  {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
  {{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
  name: {{ $fullName }}
  labels:
    {{- include "squid-exporter.labels" . | nindent 4 }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
  ingressClassName: {{ .Values.ingress.className }}
  {{- end }}
  {{- if .Values.ingress.tls }}
  tls:
    {{- range .Values.ingress.tls }}
    - hosts:
        {{- range .hosts }}
        - {{ . | quote }}
        {{- end }}
      secretName: {{ .secretName }}
    {{- end }}
  {{- end }}
  rules:
    {{- range .Values.ingress.hosts }}
    - host: {{ .host | quote }}
      http:
        paths:
          {{- range .paths }}
          - path: {{ .path }}
            {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
            pathType: {{ .pathType }}
            {{- end }}
            backend:
              {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
              service:
                name: {{ $fullName }}
                port:
                  number: {{ $svcPort }}
              {{- else }}
              serviceName: {{ $fullName }}
              servicePort: {{ $svcPort }}
              {{- end }}
          {{- end }}
    {{- end }}
{{- end }}
07070100000020000081A40000000000000000000000016819A1F7000001DD000000000000000000000000000000000000003A00000000squid-exporter-1.13.0/helm/templates/prometheusrules.yaml{{- if .Values.serviceMonitor.rules }}
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: {{ include "squid-exporter.fullname" . }}
  labels:
    {{- include "squid-exporter.labels" . | nindent 4 }}
    {{- with .Values.serviceMonitor.labels }}
    {{- . | toYaml | nindent 4 }}
    {{- end }}
spec:
  groups:
    - name: {{ include "squid-exporter.fullname" . }}
      rules:
        {{- .Values.serviceMonitor.rules | toYaml | nindent 8 }}
{{- end }}07070100000021000081A40000000000000000000000016819A1F700000116000000000000000000000000000000000000003100000000squid-exporter-1.13.0/helm/templates/secret.yamlapiVersion: v1
kind: Secret
metadata:
  name: {{ include "squid-exporter.fullname" . }}
  labels:
    {{- include "squid-exporter.labels" . | nindent 4 }}
data:
  SQUID_LOGIN: {{ .Values.squidConfig.login | b64enc }}
  SQUID_PASSWORD: {{ .Values.squidConfig.password | b64enc }}07070100000022000081A40000000000000000000000016819A1F70000030D000000000000000000000000000000000000003200000000squid-exporter-1.13.0/helm/templates/service.yamlapiVersion: v1
kind: Service
metadata:
  name: {{ include "squid-exporter.fullname" . }}
  labels:
    {{- include "squid-exporter.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  {{- if or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer") }}
  externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }}
  {{- end }}
  sessionAffinity: {{ .Values.service.sessionAffinity }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: metrics
      protocol: TCP
      name: metrics
      {{- if or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer") }}
      nodePort: {{ .Values.service.nodePort }}
      {{- end }}
  selector:
    {{- include "squid-exporter.selectorLabels" . | nindent 4 }}
07070100000023000081A40000000000000000000000016819A1F70000014E000000000000000000000000000000000000003900000000squid-exporter-1.13.0/helm/templates/serviceaccount.yaml{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ include "squid-exporter.serviceAccountName" . }}
  labels:
    {{- include "squid-exporter.labels" . | nindent 4 }}
  {{- with .Values.serviceAccount.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
{{- end }}
07070100000024000081A40000000000000000000000016819A1F7000003E2000000000000000000000000000000000000003900000000squid-exporter-1.13.0/helm/templates/servicemonitor.yamlapiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: {{ include "squid-exporter.fullname" . }}
  labels:
    {{- include "squid-exporter.labels" . | nindent 4 }}
    {{- with .Values.serviceMonitor.labels }}
    {{- . | toYaml | nindent 4 }}
    {{- end }}
spec:
  endpoints:
    - port: metrics
      interval: {{ .Values.serviceMonitor.interval }}
      metricRelabelings:
        {{- .Values.serviceMonitor.additionalMetricsRelabels | toYaml | nindent 10 }}
      path: "/metrics"
      relabelings:
        {{- .Values.serviceMonitor.additionalRelabeling | toYaml | nindent 10 }}      
      scheme: http
      scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout }}
  targetLabels:
    {{- range $label, $val := .Values.serviceMonitor.labels }}
    - {{ $label }}
    {{- end }}
    - squid-exporter.boynux.com/proxy-hostname
    - squid-exporter.boynux.com/proxy-port
  selector:
    matchLabels:
      {{- include "squid-exporter.selectorLabels" . | nindent 8 }}07070100000025000081A40000000000000000000000016819A1F700000D67000000000000000000000000000000000000002700000000squid-exporter-1.13.0/helm/values.yaml# Default values for squid-exporter.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

squidConfig:
  login: ""
  password: ""
  hostname: ""
  port: 3128

# Under normal circumstances one replica is needed.
replicaCount: 1

image:
  repository: boynux/squid-exporter
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: ""

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: ""

podAnnotations: {}

podSecurityContext:
  {}
  # fsGroup: 2000

securityContext:
  {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000

service:
  # Kubernetes Service type, one of [ClusterIP, NodePort, LoadBalancer]
  type: ClusterIP
  port: 80

  # Supports either ClientIP or None.
  # Used to maintain session affinity.
  # Enable client IP based session affinity.
  # https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
  sessionAffinity: ClientIP

  # Service settings below are applicable only if
  # service.type is one of [LoadBalancer, NodePort] and not ClusterIP.
  # Possible values are [Cluster, Local].
  # If set to Local, then the Service's port will be available only on Kubernetes
  # Nodes which have the Squid Pods so no Kubernetes Node-to-Node traffic will be forwarded.
  # If set to Cluster, then the Service's port will be available on any Node of
  # a Kubernetes cluster. The drawback is that Kubernetes will use double NAT
  # so it will hide the Client source IP from Squid.
  externalTrafficPolicy: Cluster
  # Node port to listen on. Typically, Kubernetes allows ports in range 30000-32767
  # see https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport
  # for more information.
  nodePort: ""

ingress:
  enabled: false
  className: ""
  annotations:
    {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  hosts:
    - host: chart-example.local
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

resources:
  {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #   cpu: 100m
  #   memory: 128Mi
  # requests:
  #   cpu: 100m
  #   memory: 128Mi

nodeSelector: {}

tolerations: []

affinity: {}

serviceMonitor:
  enabled: false
  additionalMetricsRelabels: []
  additionalRelabeling: []
  labels: {}
  interval: 30s
  scrapeTimeout: 30s
  # Prometheus Operator rules to install
  rules:
    []
    # - alert: SquidDown
    #   annotations:
    #     message: Exporter can not collect metrics from Squid proxy server {{ $labels.host }}
    #   expr: squid_up == 0
    #   for: 5m
    #   labels:
    #     severity: critical
07070100000026000081A40000000000000000000000016819A1F70000053C000000000000000000000000000000000000002100000000squid-exporter-1.13.0/helpers.gopackage main

import (
	"log"
	"net"
	"strconv"
	"strings"

	proxyproto "github.com/pires/go-proxyproto"

	"github.com/boynux/squid-exporter/config"
)

func createProxyHeader(cfg *config.Config) string {
	la := strings.Split(cfg.ListenAddress, ":")
	if len(la) < 2 {
		log.Printf("Cannot parse listen address (%s). Failed to create proxy header\n", cfg.ListenAddress)
		return ""
	}

	spt, err := strconv.Atoi(la[1])
	if err != nil {
		log.Printf("Failed to create proxy header: %v\n", err.Error())
		return ""
	}

	sip, err := net.LookupIP(la[0])
	if err != nil {
		log.Printf("Failed to create proxy header: %v\n", err.Error())
		return ""
	}

	dip, err := net.LookupIP(cfg.SquidHostname)
	if err != nil {
		log.Printf("Failed to create proxy header: %v\n", err.Error())
		return ""
	}

	ph := &proxyproto.Header{
		Version:           1,
		Command:           proxyproto.PROXY,
		TransportProtocol: proxyproto.TCPv4,
		SourceAddr: &net.TCPAddr{
			IP:   sip[0],
			Port: spt,
		},

		DestinationAddr: &net.TCPAddr{
			IP:   dip[0],
			Port: cfg.SquidPort,
		},
	}
	phs, err := ph.Format()

	if err != nil {
		log.Printf("Failed to create proxy header: %v\n", err.Error())
	}

	// proxyproto adds crlf to the end of the header string, but we will add this later
	// we are triming it here.
	return strings.TrimSuffix(string(phs), "\r\n")
}
07070100000027000081A40000000000000000000000016819A1F7000001C3000000000000000000000000000000000000002600000000squid-exporter-1.13.0/helpers_test.gopackage main

import (
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/boynux/squid-exporter/config"
)

func TestCreatProxyHelper(t *testing.T) {
	cfg := &config.Config{
		ListenAddress: "192.0.2.1:3192",
		SquidHostname: "127.0.0.1",
		SquidPort:     3128,
	}

	expectedHProxyString := "PROXY TCP4 192.0.2.1 127.0.0.1 3192 3128"

	p := createProxyHeader(cfg)
	assert.Equal(t, expectedHProxyString, p, "Proxy headers do not match!")
}
07070100000028000081A40000000000000000000000016819A1F700000A84000000000000000000000000000000000000001E00000000squid-exporter-1.13.0/main.gopackage main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	kitlog "github.com/go-kit/log"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/collectors"
	versioncollector "github.com/prometheus/client_golang/prometheus/collectors/version"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/prometheus/common/version"
	"github.com/prometheus/exporter-toolkit/web"

	"github.com/boynux/squid-exporter/collector"
	"github.com/boynux/squid-exporter/config"
)

func init() {
	prometheus.MustRegister(versioncollector.NewCollector("squid_exporter"))
}

func main() {
	cfg := config.NewConfig()
	if *config.VersionFlag {
		log.Println(version.Print("squid_exporter"))
		os.Exit(0)
	}
	collector.ExtractServiceTimes = cfg.ExtractServiceTimes

	proxyHeader := ""

	if cfg.UseProxyHeader {
		proxyHeader = createProxyHeader(cfg)
	}

	log.Println("Scraping metrics from", fmt.Sprintf("%s:%d", cfg.SquidHostname, cfg.SquidPort))
	e := collector.New(&collector.CollectorConfig{
		Hostname:    cfg.SquidHostname,
		Port:        cfg.SquidPort,
		Login:       cfg.Login,
		Password:    cfg.Password,
		Labels:      cfg.Labels,
		ProxyHeader: proxyHeader,
	})
	prometheus.MustRegister(e)

	if cfg.Pidfile != "" {
		procExporter := collectors.NewProcessCollector(collectors.ProcessCollectorOpts{
			PidFn: func() (int, error) {
				content, err := os.ReadFile(cfg.Pidfile)
				if err != nil {
					return 0, fmt.Errorf("cannot read pid file %q: %w", cfg.Pidfile, err)
				}
				value, err := strconv.Atoi(strings.TrimSpace(string(content)))
				if err != nil {
					return 0, fmt.Errorf("cannot parse pid file %q: %w", cfg.Pidfile, err)
				}
				return value, nil
			},
			Namespace: "squid",
		})
		prometheus.MustRegister(procExporter)
	}

	// Serve metrics
	http.Handle(cfg.MetricPath, promhttp.Handler())

	if cfg.MetricPath != "/" {
		landingConfig := web.LandingConfig{
			Name:        "Squid Exporter",
			Description: "Prometheus exporter for Squid caching proxy servers",
			HeaderColor: "#15a5be",
			Version:     version.Info(),
			Links: []web.LandingLinks{
				{
					Address: cfg.MetricPath,
					Text:    "Metrics",
				},
			},
		}
		landingPage, err := web.NewLandingPage(landingConfig)
		if err != nil {
			log.Fatal(err)
		}
		http.Handle("/", landingPage)
	}

	systemdSocket := false
	toolkitFlags := &web.FlagConfig{
		WebListenAddresses: &[]string{cfg.ListenAddress},
		WebSystemdSocket:   &systemdSocket,
		WebConfigFile:      &cfg.WebConfigPath,
	}
	logger := kitlog.NewLogfmtLogger(kitlog.StdlibWriter{})

	server := &http.Server{}
	log.Fatal(web.ListenAndServe(server, toolkitFlags, logger))
}
07070100000029000041ED0000000000000000000000026819A1F700000000000000000000000000000000000000000000002100000000squid-exporter-1.13.0/prometheus0707010000002A000081A40000000000000000000000016819A1F700000398000000000000000000000000000000000000003000000000squid-exporter-1.13.0/prometheus/prometheus.yml# my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'squid'

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'

    static_configs:
    - targets: ['localhost:9301']
0707010000002B000041ED0000000000000000000000026819A1F700000000000000000000000000000000000000000000001C00000000squid-exporter-1.13.0/types0707010000002C000081A40000000000000000000000016819A1F700000132000000000000000000000000000000000000002500000000squid-exporter-1.13.0/types/types.gopackage types

// VarLabel maps key value Prometheus labels.
type VarLabel struct {
	Key   string
	Value string
}

// Counter maps a Squid counter.
type Counter struct {
	Key       string
	Value     float64
	VarLabels []VarLabel
}

// Counters is a list of multiple Squid counters.
type Counters []Counter
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!183 blocks
openSUSE Build Service is sponsored by