├── renovate.json ├── .gitignore ├── hooks ├── build └── post_push ├── .whitesource ├── go.mod ├── ChangeLog.md ├── snap └── snapcraft.yaml ├── speedtest_exporter_test.go ├── .github ├── issue_label_bot.yaml ├── workflows │ ├── gitleaks.yml │ ├── prow-lgtm-pull.yml │ ├── draft-labels.yml │ ├── prow-lgtm-merge.yml │ ├── prow-labels.yml │ ├── rebase.yml │ ├── release-drafter.yml │ ├── size.yaml │ ├── prow.yml │ ├── gorelease.yaml │ └── renovate.yml ├── labeler.yml ├── stale.yml ├── release-drafter.yml ├── labels.yaml └── renovate.json5 ├── version └── version.go ├── prometheus.yml ├── Dockerfile ├── README.md ├── speedtest └── client.go ├── Makefile ├── speedtest_exporter.go ├── go.sum └── LICENSE /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Go 2 | speedtest_exporter 3 | 4 | # Files 5 | .DS_Store 6 | 7 | # Editor swap files 8 | *.swp 9 | *.swo 10 | *.swn 11 | 12 | # Snap 13 | *.snap 14 | -------------------------------------------------------------------------------- /hooks/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # $IMAGE_NAME var is injected into the build so the tag is correct. 3 | docker build --build-arg VCS_REF=`git rev-parse --short HEAD` \ 4 | --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \ 5 | -t $IMAGE_NAME . 6 | -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "scanSettings": { 3 | "baseBranches": [] 4 | }, 5 | "checkRunSettings": { 6 | "vulnerableCheckRunConclusionLevel": "failure", 7 | "displayMode": "diff" 8 | }, 9 | "issueSettings": { 10 | "minSeverityLevel": "LOW" 11 | } 12 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/nlamirault/speedtest_exporter 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9 7 | github.com/prometheus/client_golang v0.9.4 8 | github.com/prometheus/common v0.4.1 9 | github.com/zpeters/speedtest v1.0.3 10 | ) 11 | -------------------------------------------------------------------------------- /hooks/post_push: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker tag $IMAGE_NAME $DOCKER_REPO:$SOURCE_COMMIT 3 | docker push $DOCKER_REPO:$SOURCE_COMMIT 4 | export GO_VERSION=$(cat version/version.go | awk 'match($0, /[0-9].[0-9].[0-9]/) {print substr( $0, RSTART, RLENGTH )}') 5 | docker tag $IMAGE_NAME $DOCKER_REPO:${GO_VERSION} 6 | docker push $DOCKER_REPO:${GO_VERSION} 7 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | ChangeLog 2 | ============== 3 | 4 | # Version 0.3.0 (08/19/2019) 5 | 6 | - Use Golang modules for dependencies 7 | - `FIX` Ping (#14) 8 | - Update Makefile so make init works correctly (#13) 9 | - Increase HTTP Timeout (#11) 10 | 11 | # Version 0.2.0 (01/17/2017) 12 | 13 | - `FIX` Initialize correctly client. 14 | - Update dependency to zpeters Speedtest code 15 | 16 | # Version 0.1.0 (10/05/2016) 17 | 18 | - Prometheus exporter for Speedtest measures 19 | -------------------------------------------------------------------------------- /snap/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: speedtest-exporter 2 | base: core18 3 | version: git 4 | summary: A Prometheus exporter for measuring Internet connection bandwidth 5 | description: | 6 | speedtest_exporter uses the speedtest.net network of bandwidth measurement 7 | servers to measure download and upload bandwidth of an Internet connection 8 | at a specific point in time, providing this information to Prometheus. 9 | 10 | grade: stable 11 | confinement: strict 12 | 13 | apps: 14 | daemon: 15 | plugs: 16 | - network 17 | - network-bind 18 | command: speedtest_exporter 19 | daemon: simple 20 | 21 | parts: 22 | speedtest-exporter: 23 | plugin: go 24 | source: . 25 | -------------------------------------------------------------------------------- /speedtest_exporter_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016, 2017 Nicolas Lamirault 2 | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | -------------------------------------------------------------------------------- /.github/issue_label_bot.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | label-alias: 16 | bug: 'kind/bug' 17 | feature_request: 'kind/feature' 18 | question: 'kind/question' 19 | -------------------------------------------------------------------------------- /version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016, 2017 Nicolas Lamirault 2 | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package version 16 | 17 | // Version represents the application version using SemVer 18 | const Version string = "0.3.0" 19 | -------------------------------------------------------------------------------- /.github/workflows/gitleaks.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Tools / Gitleaks 16 | 17 | on: [push,pull_request] 18 | 19 | jobs: 20 | gitleaks: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v3 24 | - name: gitleaks-action 25 | uses: zricethezav/gitleaks-action@master 26 | -------------------------------------------------------------------------------- /.github/workflows/prow-lgtm-pull.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Prow / Run Jobs on PR 16 | on: pull_request 17 | 18 | jobs: 19 | execute: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: jpmcb/prow-github-actions@v1.1.3 23 | with: 24 | jobs: 'lgtm' 25 | github-token: "${{ secrets.GITHUB_TOKEN }}" 26 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Labels for action/labeler 16 | 17 | area/kubernetes: 18 | - kubernetes/* 19 | - kubernetes/**/* 20 | 21 | cloud/gcp: 22 | - iac/gcp/* 23 | - iac/gcp/**/* 24 | 25 | cloud/aws: 26 | - iac/aws/* 27 | - iac/aws/**/* 28 | 29 | cloud/azure: 30 | - iac/azure/* 31 | - iac/azure/**/* 32 | 33 | kind/documentation: 34 | - docs/* 35 | - docs/**/* 36 | -------------------------------------------------------------------------------- /.github/workflows/draft-labels.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Project / Draft PR Labels 16 | 17 | on: 18 | pull_request: 19 | types: [opened, ready_for_review] 20 | 21 | jobs: 22 | triage: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: label swapping 26 | uses: jinmayamashita/ready-for-review@1.0.0 27 | with: 28 | in-progress-label: 'status/in_progress' 29 | ready-for-review-label: 'status/review_needed' 30 | repo-token: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /.github/workflows/prow-lgtm-merge.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Prow / Merge on lgtm label 16 | on: 17 | schedule: 18 | - cron: "0 * * * *" 19 | 20 | jobs: 21 | execute: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: jpmcb/prow-github-actions@v1.1.3 25 | with: 26 | jobs: 'lgtm' 27 | github-token: "${{ secrets.GITHUB_TOKEN }}" 28 | 29 | # this configuration is optional and will default to 'merge' 30 | # possible options are 'merge', 'rebase', or 'squash' 31 | merge-method: 'squash' 32 | -------------------------------------------------------------------------------- /prometheus.yml: -------------------------------------------------------------------------------- 1 | 2 | global: 3 | scrape_interval: 15s # By default, scrape targets every 15 seconds. 4 | evaluation_interval: 15s # By default, scrape targets every 15 seconds. 5 | # scrape_timeout is set to the global default (10s). 6 | 7 | # Attach these labels to any time series or alerts when communicating with 8 | # external systems (federation, remote storage, Alertmanager). 9 | external_labels: 10 | monitor: 'speedtest-monitor' 11 | 12 | # Load and evaluate rules in this file every 'evaluation_interval' seconds. 13 | rule_files: 14 | # - "first.rules" 15 | # - "second.rules" 16 | 17 | # A scrape configuration containing exactly one endpoint to scrape: 18 | # Here it's Prometheus itself. 19 | scrape_configs: 20 | # The job name is added as a label `job=` to any timeseries scraped from this config. 21 | - job_name: 'prometheus' 22 | 23 | # Override the global default and scrape targets from this job every 5 seconds. 24 | scrape_interval: 5s 25 | 26 | # metrics_path defaults to '/metrics' 27 | # scheme defaults to 'http'. 28 | 29 | static_configs: 30 | - targets: ['localhost:9191'] 31 | 32 | - job_name: 'speedtest' 33 | target_groups: 34 | - targets: ['localhost:9112'] 35 | -------------------------------------------------------------------------------- /.github/workflows/prow-labels.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # name: "Label PRs from globs" 16 | # on: 17 | # schedule: 18 | # - cron: "0 * * * *" 19 | 20 | # jobs: 21 | # execute: 22 | # runs-on: ubuntu-latest 23 | # steps: 24 | # - uses: jpmcb/prow-github-actions@v1.1.1 25 | # with: 26 | # jobs: 'pr-labeler' 27 | # github-token: "${{ secrets.GITHUB_TOKEN }}" 28 | 29 | name: Prow / Pull Request Labeler 30 | 31 | on: 32 | - pull_request_target 33 | 34 | jobs: 35 | triage: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/labeler@main 39 | with: 40 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 41 | -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Projet / Rebase 16 | on: 17 | issue_comment: 18 | types: [created] 19 | jobs: 20 | rebase: 21 | name: Rebase 22 | if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout the latest code 26 | uses: actions/checkout@v3 27 | with: 28 | token: ${{ secrets.GITHUB_TOKEN }} 29 | fetch-depth: 0 # otherwise, you will fail to push refs to dest repo 30 | - name: Automatic Rebase 31 | uses: cirrus-actions/rebase@1.8 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Project / Release Drafter 16 | 17 | on: 18 | push: 19 | # branches to consider in the event; optional, defaults to all 20 | branches: 21 | - master 22 | 23 | jobs: 24 | update_release_draft: 25 | runs-on: ubuntu-latest 26 | steps: 27 | # Drafts your next Release notes as Pull Requests are merged into "master" 28 | - uses: release-drafter/release-drafter@v5.22.0 29 | # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml 30 | # with: 31 | # config-name: my-config.yml 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | -------------------------------------------------------------------------------- /.github/workflows/size.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Project / Size PR 16 | 17 | on: 18 | pull_request: 19 | types: [opened, synchronize] 20 | 21 | jobs: 22 | update_labels: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - uses: actions-ecosystem/action-size@v2 28 | id: size 29 | 30 | - uses: actions-ecosystem/action-remove-labels@v1 31 | with: 32 | github_token: ${{ secrets.github_token }} 33 | labels: ${{ steps.size.outputs.stale_labels }} 34 | 35 | - uses: actions-ecosystem/action-add-labels@v1 36 | with: 37 | github_token: ${{ secrets.github_token }} 38 | labels: ${{ steps.size.outputs.new_label }} 39 | -------------------------------------------------------------------------------- /.github/workflows/prow.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Prow / Github Actions 16 | on: 17 | issue_comment: 18 | types: [created] 19 | 20 | jobs: 21 | execute: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: jpmcb/prow-github-actions@v1.1.3 25 | with: 26 | prow-commands: '/assign 27 | /unassign 28 | /approve 29 | /retitle 30 | /area 31 | /kind 32 | /priority 33 | /status 34 | /remove 35 | /lgtm 36 | /close 37 | /reopen 38 | /lock 39 | /milestone 40 | /hold 41 | /cc 42 | /uncc' 43 | github-token: "${{ secrets.GITHUB_TOKEN }}" 44 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) 2021 Nicolas Lamirault 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # Number of days of inactivity before an issue becomes stale 17 | daysUntilStale: 60 18 | # Number of days of inactivity before a stale issue is closed 19 | daysUntilClose: 7 20 | # Issues with these labels will never be considered stale 21 | exemptLabels: 22 | - security fix 23 | - security vulnerability 24 | # Label to use when marking an issue as stale 25 | staleLabel: lifecycle/stale 26 | # Comment to post when marking an issue as stale. Set to `false` to disable 27 | markComment: > 28 | This issue has been automatically marked as stale because it has not had 29 | recent activity. It will be closed if no further activity occurs. Thank you 30 | for your contributions. 31 | # Comment to post when closing a stale issue. Set to `false` to disable 32 | closeComment: false 33 | -------------------------------------------------------------------------------- /.github/workflows/gorelease.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Project / Release 16 | 17 | on: 18 | push: 19 | tags: 20 | - '*' 21 | 22 | jobs: 23 | release: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v3 28 | 29 | - name: Set up Go 1.x 30 | uses: actions/setup-go@v3 31 | with: 32 | go-version: ^1.14 33 | id: go 34 | 35 | - name: Publish Release Notes 36 | uses: release-drafter/release-drafter@v5.22.0 37 | with: 38 | publish: true 39 | env: 40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 41 | 42 | - name: Run GoReleaser 43 | uses: goreleaser/goreleaser-action@v4 44 | with: 45 | version: latest 46 | args: release --rm-dist 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016-2019 Nicolas Lamirault 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM golang:alpine as builder 16 | 17 | ENV CGO_ENABLED=0 18 | ENV GOOS=linux 19 | ENV GOARCH=amd64 20 | ENV GO111MODULE=on 21 | 22 | RUN apk update \ 23 | && apk add --no-cache git ca-certificates tzdata \ 24 | && update-ca-certificates 25 | 26 | RUN adduser -D -g '' appuser 27 | 28 | ADD . ${GOPATH}/src/app/ 29 | WORKDIR ${GOPATH}/src/app 30 | 31 | RUN go build -a -installsuffix cgo -ldflags="-w -s" -o /go/bin/speedtest_exporter 32 | 33 | # -------------------------------------------------------------------------------- 34 | 35 | FROM gcr.io/distroless/base 36 | 37 | LABEL summary="Speedtest Prometheus exporter" \ 38 | description="A Prometheus exporter for speedtest" \ 39 | name="nlamirault/speedtest_exporter" \ 40 | url="https://github.com/nlamirault/speedtest_exporter" \ 41 | maintainer="Nicolas Lamirault " 42 | 43 | COPY --from=builder /go/bin/speedtest_exporter /usr/bin/speedtest_exporter 44 | 45 | COPY --from=builder /etc/passwd /etc/passwd 46 | 47 | EXPOSE 9112 48 | 49 | ENTRYPOINT [ "/usr/bin/speedtest_exporter" ] 50 | -------------------------------------------------------------------------------- /.github/workflows/renovate.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Renovate / Helm releases 16 | 17 | on: 18 | workflow_dispatch: 19 | schedule: 20 | - cron: "0 * * * *" 21 | 22 | jobs: 23 | renovate-helmrelease: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v3 27 | with: 28 | fetch-depth: 1 29 | 30 | # - name: Update Helm Releases 31 | # run: | 32 | # docker-compose run -T --rm builder bootstrap/renovate-helm-releases.sh 33 | 34 | - name: Create Pull Request 35 | uses: peter-evans/create-pull-request@v4 36 | with: 37 | token: ${{ secrets.GITHUB_TOKEN }} 38 | branch: update/pre-commit-auto-update 39 | delete-branch: true 40 | title: Auto-update pre-commit hooks 41 | signoff: true 42 | committer: "Nicolas Lamirault " 43 | author: "Nicolas Lamirault " 44 | commit-message: Auto-update pre-commit hooks 45 | body: | 46 | Signed-off-by: Nicolas Lamirault 47 | labels: dependencies, merge 48 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name-template: 'v$RESOLVED_VERSION 🌈' 16 | tag-template: 'v$RESOLVED_VERSION' 17 | # https://gitmoji.carloscuesta.me/ 18 | categories: 19 | - title: '🚀 Features' 20 | labels: 21 | - 'feature' 22 | - 'enhancement' 23 | - 'kind/feature' 24 | - 'kind/enhancement' 25 | - title: '🐛 Bug Fixes' 26 | labels: 27 | - 'kind/bug' 28 | - 'fix' 29 | - 'bugfix' 30 | - 'bug' 31 | - title: '🚨 Maintenance' 32 | labels: 33 | - 'kind/renovate' 34 | - 'dependency/flux' 35 | - 'chore' 36 | - title: '📝 Documentation' 37 | labels: 38 | - 'kind/documentation' 39 | - title: '💡 Question' 40 | labels: 41 | - 'kind/question' 42 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)' 43 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. 44 | version-resolver: 45 | major: 46 | labels: 47 | - 'major' 48 | minor: 49 | labels: 50 | - 'minor' 51 | patch: 52 | labels: 53 | - 'patch' 54 | default: patch 55 | template: | 56 | ## 🚧 Changes 57 | 58 | $CHANGES 59 | -------------------------------------------------------------------------------- /.github/labels.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Nicolas Lamirault 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # labels to be used with /area command 16 | area: 17 | - 'kubernetes' 18 | - 'terraform' 19 | - 'ansible' 20 | - 'inspec' 21 | - 'github' 22 | 23 | kind: 24 | - 'bug' 25 | - 'documentation' 26 | - 'discussion' 27 | - 'feature' 28 | - 'question' 29 | - 'support' 30 | 31 | priority: 32 | - backlog 33 | - 'low' 34 | - 'medium' 35 | - 'high' 36 | - 'critical' 37 | 38 | status: 39 | - available 40 | - blocked 41 | - in_progress 42 | - on_hold 43 | 44 | # File globs for PR labeler 45 | # tests: 46 | # - '**/*.test.ts' 47 | 48 | 'area/kubernetes': 49 | - kubernetes/* 50 | - kubernetes/**/* 51 | 52 | 'cloud/gcp': 53 | - iac/gcp/* 54 | - iac/gcp/**/* 55 | 56 | 'cloud/aws': 57 | - iac/aws/* 58 | - iac/aws/**/* 59 | 60 | 'cloud/azure': 61 | - iac/azure/* 62 | - iac/azure/**/* 63 | 64 | 'cloud/alicloud': 65 | - iac/alicloud/* 66 | - iac/alicloud/**/* 67 | 68 | 'cloud/digitalocean': 69 | - iac/digitalocean/* 70 | - iac/digitalocean/**/* 71 | 72 | 'cloud/exoscale': 73 | - iac/exoscale/* 74 | - iac/exoscale/**/* 75 | 76 | 'cloud/scaleway': 77 | - iac/scaleway/* 78 | - iac/scaleway/**/* 79 | 80 | 'kind/documentation': 81 | - docs/* 82 | - docs/**/* 83 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | ":gitSignOff" 5 | ], 6 | "enabled": true, 7 | "timezone": "Europe/Paris", 8 | "dependencyDashboard": true, 9 | "dependencyDashboardTitle": "Renovate Dashboard", 10 | // "gitAuthor": "Nicolas Lamirault ", 11 | // "commitBody": "Signed-off-by: Nicolas Lamirault ", 12 | // Do not notify on closed unmerged PRs 13 | "suppressNotifications": ["prIgnoreNotification"], 14 | // Do not rebase PRs 15 | "rebaseWhen": "conflicted", 16 | "assignees": ["@nlamirault"], 17 | "reviewersFromCodeOwners": true, 18 | // "labels": ["kind/renovate", "lifecycle/active", "status/review_needed"], 19 | "helm-values": { 20 | "fileMatch": ["kubernetes/.+\\.yaml$"] 21 | }, 22 | "packageRules": [ 23 | // Labels for Package 24 | { 25 | "datasources": ["package"], 26 | "updateTypes": ["major"], 27 | "labels": ["kind/renovate", "lifecycle/active", "status/review_needed", "area/package", "dependency/package", "priority/high", "size/xs"] 28 | }, 29 | { 30 | "datasources": ["package"], 31 | "updateTypes": ["minor"], 32 | "labels": ["kind/renovate", "lifecycle/active", "status/review_needed", "area/package", "dependency/package", "priority/medium", "size/xs"] 33 | }, 34 | { 35 | "datasources": ["package"], 36 | "updateTypes": ["patch"], 37 | "labels": ["kind/renovate", "lifecycle/active", "status/review_needed", "area/package", "dependency/package", "priority/low", "size/xs"] 38 | }, 39 | // Labels for Github Actions 40 | { 41 | "datasources": ["action"], 42 | "updateTypes": ["major"], 43 | "labels": ["kind/renovate", "lifecycle/active", "status/review_needed", "area/github", "dependency/github", "priority/high", "size/xs"] 44 | }, 45 | { 46 | "datasources": ["action"], 47 | "updateTypes": ["minor"], 48 | "labels": ["kind/renovate", "lifecycle/active", "status/review_needed", "area/github", "dependency/github", "priority/medium", "size/xs"] 49 | }, 50 | { 51 | "datasources": ["action"], 52 | "updateTypes": ["patch"], 53 | "labels": ["kind/renovate", "lifecycle/active", "status/review_needed", "area/github", "dependency/github", "priority/low", "size/xs"] 54 | }, 55 | // Enable auto-merge docker 56 | // { 57 | // "datasources": ["docker"], 58 | // "automerge": true, 59 | // "requiredStatusChecks": null, 60 | // "updateTypes": ["minor", "patch"], 61 | // }, 62 | // Enable auto-merge helm 63 | // { 64 | // "datasources": ["helm"], 65 | // "automerge": true, 66 | // "requiredStatusChecks": null, 67 | // "updateTypes": ["patch"], 68 | // } 69 | ] 70 | } 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # speedtest_exporter 2 | 3 | [![License Apache 2][badge-license]](LICENSE) 4 | [![GitHub version](https://badge.fury.io/gh/nlamirault%2Fspeedtest_exporter.svg)](https://badge.fury.io/gh/nlamirault%2Fspeedtest_exporter) 5 | 6 | * Master : [![Circle CI](https://circleci.com/gh/nlamirault/speedtest_exporter/tree/master.svg?style=svg)](https://circleci.com/gh/nlamirault/speedtest_exporter/tree/master) 7 | * Develop : [![Circle CI](https://circleci.com/gh/nlamirault/speedtest_exporter/tree/develop.svg?style=svg)](https://circleci.com/gh/nlamirault/speedtest_exporter/tree/develop) 8 | 9 | This Prometheus exporter check your network connection. Metrics are : 10 | 11 | * Latency 12 | * Download bandwidth 13 | * Upload bandwidth 14 | 15 | 16 | ## Installation 17 | 18 | You can download the binaries : 19 | 20 | * Architecture amd64 [ [linux](https://bintray.com/artifact/download/nlamirault/oss/speedtest_exporter-0.3.0_linux_amd64) / [darwin](https://bintray.com/artifact/download/nlamirault/oss/speedtest_exporter-0.3.0_darwin_amd64) / [freebsd](https://bintray.com/artifact/download/nlamirault/oss/speedtest_exporter-0.3.0_freebsd_amd64) / [netbsd](https://bintray.com/artifact/download/nlamirault/oss/speedtest_exporter-0.3.0_netbsd_amd64) / [openbsd](https://bintray.com/artifact/download/nlamirault/oss/speedtest_exporter-0.3.0_openbsd_amd64) / [windows](https://bintray.com/artifact/download/nlamirault/oss/speedtest_exporter-0.3.0_windows_amd64.exe) ] 21 | * Architecture arm [ [linux](https://bintray.com/artifact/download/nlamirault/oss/speedtest_exporter-0.3.0_linux_arm) ] 22 | * Architecture arm64 [ [linux](https://bintray.com/artifact/download/nlamirault/oss/speedtest_exporter-0.3.0_linux_arm64) ] 23 | 24 | 25 | ## Usage 26 | 27 | Launch the Prometheus exporter : 28 | 29 | ```bash 30 | $ speedtest_exporter -log.level=debug 31 | ``` 32 | 33 | ## Development 34 | 35 | * Initialize environment 36 | 37 | ```bash 38 | $ make init 39 | ``` 40 | 41 | * Build tool : 42 | 43 | ```bash 44 | $ make build 45 | ``` 46 | 47 | * Launch unit tests : 48 | 49 | ```bash 50 | $ make test 51 | ``` 52 | 53 | ## Local Deployment 54 | 55 | * Launch Prometheus using the configuration file in this repository: 56 | 57 | ```bash 58 | $ prometheus -config.file=prometheus.yml 59 | ``` 60 | 61 | * Launch exporter: 62 | 63 | ```bash 64 | $ speedtest_exporter -log.level=debug 65 | ``` 66 | 67 | * Check that Prometheus find the exporter on `http://localhost:9090/targets` 68 | 69 | 70 | ## Contributing 71 | 72 | See [CONTRIBUTING](CONTRIBUTING.md). 73 | 74 | 75 | ## License 76 | 77 | See [LICENSE](LICENSE) for the complete license. 78 | 79 | 80 | ## Changelog 81 | 82 | A [changelog](ChangeLog.md) is available 83 | 84 | 85 | ## Contact 86 | 87 | Nicolas Lamirault 88 | 89 | [badge-license]: https://img.shields.io/badge/license-Apache2-green.svg?style=flat 90 | -------------------------------------------------------------------------------- /speedtest/client.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016, 2017 Nicolas Lamirault 2 | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package speedtest 16 | 17 | import ( 18 | "time" 19 | 20 | "github.com/prometheus/common/log" 21 | "github.com/zpeters/speedtest/print" 22 | "github.com/zpeters/speedtest/sthttp" 23 | "github.com/zpeters/speedtest/tests" 24 | ) 25 | 26 | const ( 27 | userAgent = "speedtest_exporter" 28 | ) 29 | 30 | // Client defines the Speedtest client 31 | type Client struct { 32 | Server sthttp.Server 33 | SpeedtestClient *sthttp.Client 34 | AllServers []sthttp.Server 35 | ClosestServers []sthttp.Server 36 | } 37 | 38 | // NewClient defines a new client for Speedtest 39 | func NewClient(configURL string, serversURL string) (*Client, error) { 40 | log.Debugf("New Speedtest client %s %s", configURL, serversURL) 41 | stClient := sthttp.NewClient( 42 | &sthttp.SpeedtestConfig{ 43 | ConfigURL: configURL, 44 | ServersURL: serversURL, 45 | AlgoType: "max", 46 | NumClosest: 3, 47 | NumLatencyTests: 5, 48 | Interface: "", 49 | Blacklist: []string{}, 50 | UserAgent: userAgent, 51 | }, 52 | &sthttp.HTTPConfig{ 53 | HTTPTimeout: 5 * time.Minute, 54 | }, 55 | true, 56 | "|") 57 | 58 | log.Debug("Retrieve configuration") 59 | config, err := stClient.GetConfig() 60 | if err != nil { 61 | return nil, err 62 | } 63 | stClient.Config = &config 64 | 65 | print.EnvironmentReport(stClient) 66 | 67 | log.Debugf("Retrieve all servers") 68 | var allServers []sthttp.Server 69 | allServers, err = stClient.GetServers() 70 | if err != nil { 71 | return nil, err 72 | } 73 | 74 | closestServers := stClient.GetClosestServers(allServers) 75 | // log.Infof("Closest Servers: %s", closestServers) 76 | testServer := stClient.GetFastestServer(closestServers) 77 | log.Infof("Test server: %s", testServer) 78 | 79 | return &Client{ 80 | Server: testServer, 81 | SpeedtestClient: stClient, 82 | AllServers: allServers, 83 | ClosestServers: closestServers, 84 | }, nil 85 | } 86 | 87 | func (client *Client) NetworkMetrics() map[string]float64 { 88 | result := map[string]float64{} 89 | tester := tests.NewTester(client.SpeedtestClient, tests.DefaultDLSizes, tests.DefaultULSizes, false, false) 90 | downloadMbps := tester.Download(client.Server) 91 | log.Infof("Speedtest Download: %v Mbps", downloadMbps) 92 | uploadMbps := tester.Upload(client.Server) 93 | log.Infof("Speedtest Upload: %v Mbps", uploadMbps) 94 | 95 | ping, err := client.SpeedtestClient.GetLatency(client.Server, client.SpeedtestClient.GetLatencyURL(client.Server)) 96 | if err != nil { 97 | log.Fatal(err) 98 | } 99 | 100 | log.Infof("Speedtest Latency: %v ms", ping) 101 | result["download"] = downloadMbps 102 | result["upload"] = uploadMbps 103 | result["ping"] = ping 104 | log.Infof("Speedtest results: %s", result) 105 | return result 106 | } 107 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016, 2017 Nicolas Lamirault 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | APP = speedtest_exporter 16 | 17 | VERSION=$(shell \ 18 | grep "const Version" version/version.go \ 19 | |awk -F'=' '{print $$2}' \ 20 | |sed -e "s/[^0-9.]//g" \ 21 | |sed -e "s/ //g") 22 | 23 | SHELL = /bin/bash 24 | 25 | DIR = $(shell pwd) 26 | 27 | DOCKER = docker 28 | 29 | GO = go 30 | GLIDE = glide 31 | 32 | # GOX_OS = -os="linux darwin windows freebsd openbsd netbsd" 33 | # GOX_ARGS = "-output={{.Dir}}-$(VERSION)_{{.OS}}_{{.Arch}}" 34 | 35 | GOX_OS = -osarch="linux/amd64 linux/arm linux/arm64 darwin/amd64 freebsd/amd64 openbsd/amd64 netbsd/amd64 windows/amd64" 36 | GOX_ARGS = "-output={{.Dir}}-$(VERSION)_{{.OS}}_{{.Arch}}" 37 | 38 | BINTRAY_URI = https://api.bintray.com 39 | BINTRAY_USERNAME = nlamirault 40 | BINTRAY_REPOSITORY= oss 41 | 42 | NO_COLOR=\033[0m 43 | OK_COLOR=\033[32;01m 44 | ERROR_COLOR=\033[31;01m 45 | WARN_COLOR=\033[33;01m 46 | 47 | MAKE_COLOR=\033[33;01m%-20s\033[0m 48 | 49 | MAIN = github.com/nlamirault/speedtest_exporter 50 | SRCS = $(shell git ls-files '*.go' | grep -v '^vendor/') 51 | PKGS = $(shell glide novendor) 52 | EXE = $(shell ls speedtest_exporter-${VERSION}_*) 53 | 54 | PACKAGE=$(APP)-$(VERSION) 55 | ARCHIVE=$(PACKAGE).tar 56 | 57 | .DEFAULT_GOAL := help 58 | 59 | .PHONY: help 60 | help: 61 | @echo -e "$(OK_COLOR)==== $(APP) [$(VERSION)] ====$(NO_COLOR)" 62 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(MAKE_COLOR) : %s\n", $$1, $$2}' 63 | 64 | clean: ## Cleanup 65 | @echo -e "$(OK_COLOR)[$(APP)] Cleanup$(NO_COLOR)" 66 | @rm -fr $(EXE) $(APP) $(APP)-*.tar.gz 67 | 68 | .PHONY: init 69 | init: ## Install requirements 70 | @echo -e "$(OK_COLOR)[$(APP)] Install requirements$(NO_COLOR)" 71 | @go get -u github.com/golang/glog 72 | @go get -u github.com/kardianos/govendor 73 | @go get -u github.com/Masterminds/rmvcsdir 74 | @go get -u github.com/golang/lint/golint 75 | @go get -u github.com/kisielk/errcheck 76 | @go get -u golang.org/x/tools/cmd/guru 77 | @go get -u github.com/mitchellh/gox 78 | 79 | .PHONY: deps 80 | deps: ## Install dependencies 81 | @echo -e "$(OK_COLOR)[$(APP)] Update dependencies$(NO_COLOR)" 82 | @glide up -u -s -v 83 | 84 | .PHONY: build 85 | build: ## Make binary 86 | @echo -e "$(OK_COLOR)[$(APP)] Build $(NO_COLOR)" 87 | @$(GO) build . 88 | 89 | .PHONY: test 90 | test: ## Launch unit tests 91 | @echo -e "$(OK_COLOR)[$(APP)] Launch unit tests $(NO_COLOR)" 92 | @$(GO) test -v $$(glide nv) 93 | 94 | .PHONY: run 95 | run: ## Start exporter 96 | @echo -e "$(OK_COLOR)[$(APP)] Start the exporter $(NO_COLOR)" 97 | @./$(APP) -log.level DEBUG 98 | 99 | .PHONY: lint 100 | lint: ## Launch golint 101 | @$(foreach file,$(SRCS),golint $(file) || exit;) 102 | 103 | .PHONY: vet 104 | vet: ## Launch go vet 105 | @$(foreach file,$(SRCS),$(GO) vet $(file) || exit;) 106 | 107 | .PHONY: errcheck 108 | errcheck: ## Launch go errcheck 109 | @echo -e "$(OK_COLOR)[$(APP)] Go Errcheck $(NO_COLOR)" 110 | @$(foreach pkg,$(PKGS),errcheck $(pkg) $(glide novendor) || exit;) 111 | 112 | .PHONY: coverage 113 | coverage: ## Launch code coverage 114 | @$(foreach pkg,$(PKGS),$(GO) test -cover $(pkg) $(glide novendor) || exit;) 115 | 116 | gox: ## Make all binaries 117 | @echo -e "$(OK_COLOR)[$(APP)] Create binaries $(NO_COLOR)" 118 | @gox $(GOX_OS) $(GOX_ARGS) github.com/nlamirault/speedtest_exporter 119 | 120 | .PHONY: binaries 121 | binaries: ## Upload all binaries 122 | @echo -e "$(OK_COLOR)[$(APP)] Upload binaries to Bintray $(NO_COLOR)" 123 | for i in $(EXE); do \ 124 | curl -T $$i \ 125 | -u$(BINTRAY_USERNAME):$(BINTRAY_APIKEY) \ 126 | "$(BINTRAY_URI)/content/$(BINTRAY_USERNAME)/$(BINTRAY_REPOSITORY)/$(APP)/${VERSION}/$$i;publish=1"; \ 127 | done 128 | 129 | # for goprojectile 130 | .PHONY: gopath 131 | gopath: 132 | @echo `pwd`:`pwd`/vendor 133 | -------------------------------------------------------------------------------- /speedtest_exporter.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016, 2017 Nicolas Lamirault 2 | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "flag" 19 | "fmt" 20 | "net/http" 21 | _ "net/http/pprof" 22 | "os" 23 | "time" 24 | 25 | "github.com/dchest/uniuri" 26 | "github.com/prometheus/client_golang/prometheus" 27 | "github.com/prometheus/common/log" 28 | prom_version "github.com/prometheus/common/version" 29 | 30 | "github.com/nlamirault/speedtest_exporter/speedtest" 31 | "github.com/nlamirault/speedtest_exporter/version" 32 | ) 33 | 34 | const ( 35 | namespace = "speedtest" 36 | ) 37 | 38 | var ( 39 | ping = prometheus.NewDesc( 40 | prometheus.BuildFQName(namespace, "", "ping"), 41 | "Latency (ms)", 42 | nil, nil, 43 | ) 44 | download = prometheus.NewDesc( 45 | prometheus.BuildFQName(namespace, "", "download"), 46 | "Download bandwidth (Mbps).", 47 | nil, nil, 48 | ) 49 | upload = prometheus.NewDesc( 50 | prometheus.BuildFQName(namespace, "", "upload"), 51 | "Upload bandwidth (Mbps).", 52 | nil, nil, 53 | ) 54 | ) 55 | 56 | // Exporter collects Speedtest stats from the given server and exports them using 57 | // the prometheus metrics package. 58 | type Exporter struct { 59 | Client *speedtest.Client 60 | } 61 | 62 | // NewExporter returns an initialized Exporter. 63 | func NewExporter(config string, server string, interval time.Duration) (*Exporter, error) { 64 | log.Infof("Setup Speedtest client with interval %s", interval) 65 | client, err := speedtest.NewClient(config, server) 66 | if err != nil { 67 | return nil, fmt.Errorf("Can't create the Speedtest client: %s", err) 68 | } 69 | 70 | log.Debugln("Init exporter") 71 | return &Exporter{ 72 | Client: client, 73 | }, nil 74 | } 75 | 76 | // Describe describes all the metrics ever exported by the Speedtest exporter. 77 | // It implements prometheus.Collector. 78 | func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { 79 | ch <- ping 80 | ch <- download 81 | ch <- upload 82 | } 83 | 84 | // Collect fetches the stats from configured Speedtest location and delivers them 85 | // as Prometheus metrics. 86 | // It implements prometheus.Collector. 87 | func (e *Exporter) Collect(ch chan<- prometheus.Metric) { 88 | log.Infof("Speedtest exporter starting") 89 | if e.Client == nil { 90 | log.Errorf("Speedtest client not configured.") 91 | return 92 | } 93 | 94 | metrics := e.Client.NetworkMetrics() 95 | ch <- prometheus.MustNewConstMetric(ping, prometheus.GaugeValue, metrics["ping"]) 96 | ch <- prometheus.MustNewConstMetric(download, prometheus.GaugeValue, metrics["download"]) 97 | ch <- prometheus.MustNewConstMetric(upload, prometheus.GaugeValue, metrics["upload"]) 98 | log.Infof("Speedtest exporter finished") 99 | } 100 | 101 | func init() { 102 | prometheus.MustRegister(prom_version.NewCollector("speedtest_exporter")) 103 | } 104 | 105 | func main() { 106 | var ( 107 | showVersion = flag.Bool("version", false, "Print version information.") 108 | listenAddress = flag.String("web.listen-address", ":9112", "Address to listen on for web interface and telemetry.") 109 | metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.") 110 | configURL = flag.String("speedtest.config-url", "http://c.speedtest.net/speedtest-config.php?x="+uniuri.New(), "Speedtest configuration URL") 111 | serverURL = flag.String("speedtest.server-url", "http://c.speedtest.net/speedtest-servers-static.php?x="+uniuri.New(), "Speedtest server URL") 112 | //interval = flag.Int("interval", 60*time.Second, "Interval for metrics.") 113 | ) 114 | flag.Parse() 115 | 116 | if *showVersion { 117 | fmt.Printf("Speedtest Prometheus exporter. v%s\n", version.Version) 118 | os.Exit(0) 119 | } 120 | 121 | log.Infoln("Starting speedtest exporter", prom_version.Info()) 122 | log.Infoln("Build context", prom_version.BuildContext()) 123 | 124 | interval := 60 * time.Second 125 | exporter, err := NewExporter(*configURL, *serverURL, interval) 126 | if err != nil { 127 | log.Errorf("Can't create exporter : %s", err) 128 | os.Exit(1) 129 | } 130 | log.Infoln("Register exporter") 131 | prometheus.MustRegister(exporter) 132 | 133 | http.Handle(*metricsPath, prometheus.Handler()) 134 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 135 | w.Write([]byte(` 136 | Speedtest Exporter 137 | 138 |

Speedtest Exporter

139 |

Metrics

140 | 141 | `)) 142 | }) 143 | 144 | log.Infoln("Listening on", *listenAddress) 145 | log.Fatal(http.ListenAndServe(*listenAddress, nil)) 146 | } 147 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= 2 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 3 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= 4 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 5 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= 6 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 7 | github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= 8 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 11 | github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9 h1:74lLNRzvsdIlkTgfDSMuaPjBr4cf6k7pwQQANm/yLKU= 12 | github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4= 13 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 14 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 15 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 16 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 17 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= 18 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 19 | github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= 20 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 21 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 22 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 23 | github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= 24 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 25 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 26 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 27 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 28 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 29 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 30 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 31 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 32 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 33 | github.com/prometheus/client_golang v0.9.1 h1:K47Rk0v/fkEfwfQet2KWhscE0cJzjgCCDBG2KHZoVno= 34 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 35 | github.com/prometheus/client_golang v0.9.4 h1:Y8E/JaaPbmFSW2V81Ab/d8yZFYQQGbni1b1jPcG9Y6A= 36 | github.com/prometheus/client_golang v0.9.4/go.mod h1:oCXIBxdI62A4cR6aTRJCgetEjecSIYzOEaeAn4iYEpM= 37 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= 38 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 39 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= 40 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 41 | github.com/prometheus/common v0.0.0-20190107103113-2998b132700a h1:bLKgQQEViHvsdgCwCGyyga8npETKygQ8b7c/28mJ8tw= 42 | github.com/prometheus/common v0.0.0-20190107103113-2998b132700a/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 43 | github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= 44 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 45 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ= 46 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 47 | github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= 48 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 49 | github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= 50 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 51 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 52 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 53 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 54 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 55 | github.com/zpeters/speedtest v1.0.3 h1:w0aKeI4HLVfXkRMa1akWqbAHoUwWkM3nw+A3SQalkXw= 56 | github.com/zpeters/speedtest v1.0.3/go.mod h1:cWHUWQgGnnK27PrpvhAEojTEkM0WE+UmsP+5WawphVw= 57 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= 58 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 59 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 60 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 61 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 62 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 63 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5 h1:mzjBh+S5frKOsOBobWIMAbXavqjmgO17k/2puhcFR94= 64 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 65 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 66 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 67 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 68 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------