├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── charts
└── isp-logger
│ ├── Chart.yaml
│ ├── README.md
│ ├── templates
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ └── secret.yaml
│ └── values.yaml
├── requirements.txt
└── script.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | venv
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.9-alpine
2 |
3 | ADD script.py .
4 |
5 | COPY requirements.txt .
6 |
7 | RUN pip install -r requirements.txt
8 |
9 | CMD [ "python", "./script.py" ]
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 isplogger.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Keep track of your internet speed.
4 |
Automated internet speed logger for your connection at home, office and servers.
5 |
6 |
7 |
8 | Thank you for your interest in ISP Logger.
9 |
10 | The project is still heavily work in progress, but a basic version is working.
11 |
12 | ## Setup
13 |
14 | What you need:
15 | - Create an account over at https://isplogger.com/
16 | - Create a network and obtain your Device ID. It's a UUID string.
17 | > For simplicity, run this project on Docker, but you're also free to run the python code directly.
18 |
19 | > It's been tested on MacOS and Linux.
20 | I'd love it if Windows users can help me out. It should work fine on Docker, but let me know if you have trouble.
21 |
22 | - Pull the project from the Docker Hub Hub (Recommended):
23 | ```shell
24 | $ docker pull ronaldl93/isp-logger
25 | ```
26 |
27 | - If this is successful, run the container:
28 |
29 | ```shell
30 | $ docker run -it -d -e NETWORK_ID="" ronaldl93/isp-logger
31 | ```
32 |
33 | A speed test will now perform once, and then again every 60 minutes.
34 |
35 | You can see the results on your account at ISP Logger.
36 |
37 | I highly recommend running this on a home server or computer that never sleeps / gets switched off.
38 | I'm using an old-ish computer, running Ubuntu Server.
39 |
40 | Something like a Raspberry Pi will work just fine as well. As long as it can run docker, you can run it on any device.
41 |
--------------------------------------------------------------------------------
/charts/isp-logger/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: isp-logger
3 | description: Internet Performance Analytics Tool
4 |
5 | type: application
6 |
7 | # This is the chart version. This version number should be incremented each time you make changes
8 | # to the chart and its templates, including the app version.
9 | # Versions are expected to follow Semantic Versioning (https://semver.org/)
10 | version: 0.1.0
11 |
12 | # This is the version number of the application being deployed. This version number should be
13 | # incremented each time you make changes to the application. Versions are not expected to
14 | # follow Semantic Versioning. They should reflect the version the application is using.
15 | appVersion: latest
16 |
--------------------------------------------------------------------------------
/charts/isp-logger/README.md:
--------------------------------------------------------------------------------
1 | # Helm Chart for ISP Logger
2 |
3 | ## Installation
4 | ```sh
5 | git clone https://github.com/ronaldlangeveld/isplogger_server
6 | helm install --set network_id= --set TZ= isp-logger ./isplogger_server/charts/isp-logger
7 | ```
8 |
--------------------------------------------------------------------------------
/charts/isp-logger/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/*
2 | Expand the name of the chart.
3 | */}}
4 | {{- define "isp-logger.name" -}}
5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
6 | {{- end }}
7 |
8 | {{/*
9 | Create a default fully qualified app name.
10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
11 | If release name contains chart name it will be used as a full name.
12 | */}}
13 | {{- define "isp-logger.fullname" -}}
14 | {{- if .Values.fullnameOverride }}
15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
16 | {{- else }}
17 | {{- $name := default .Chart.Name .Values.nameOverride }}
18 | {{- if contains $name .Release.Name }}
19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }}
20 | {{- else }}
21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
22 | {{- end }}
23 | {{- end }}
24 | {{- end }}
25 |
26 | {{/*
27 | Create chart name and version as used by the chart label.
28 | */}}
29 | {{- define "isp-logger.chart" -}}
30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
31 | {{- end }}
32 |
33 | {{/*
34 | Common labels
35 | */}}
36 | {{- define "isp-logger.labels" -}}
37 | helm.sh/chart: {{ include "isp-logger.chart" . }}
38 | {{ include "isp-logger.selectorLabels" . }}
39 | {{- if .Chart.AppVersion }}
40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
41 | {{- end }}
42 | app.kubernetes.io/managed-by: {{ .Release.Service }}
43 | {{- end }}
44 |
45 | {{/*
46 | Selector labels
47 | */}}
48 | {{- define "isp-logger.selectorLabels" -}}
49 | app.kubernetes.io/name: {{ include "isp-logger.name" . }}
50 | app.kubernetes.io/instance: {{ .Release.Name }}
51 | {{- end }}
52 |
53 |
--------------------------------------------------------------------------------
/charts/isp-logger/templates/deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: {{ include "isp-logger.fullname" . }}
5 | labels:
6 | {{- include "isp-logger.labels" . | nindent 4 }}
7 | spec:
8 | replicas: {{ .Values.replicaCount }}
9 | selector:
10 | matchLabels:
11 | {{- include "isp-logger.selectorLabels" . | nindent 6 }}
12 | template:
13 | metadata:
14 | {{- with .Values.podAnnotations }}
15 | annotations:
16 | {{- toYaml . | nindent 8 }}
17 | {{- end }}
18 | labels:
19 | {{- include "isp-logger.selectorLabels" . | nindent 8 }}
20 | spec:
21 | {{- with .Values.imagePullSecrets }}
22 | imagePullSecrets:
23 | {{- toYaml . | nindent 8 }}
24 | {{- end }}
25 | securityContext:
26 | {{- toYaml .Values.podSecurityContext | nindent 8 }}
27 | containers:
28 | - name: {{ .Chart.Name }}
29 | securityContext:
30 | {{- toYaml .Values.securityContext | nindent 12 }}
31 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
32 | imagePullPolicy: {{ .Values.image.pullPolicy }}
33 | env:
34 | - name: NETWORK_ID
35 | valueFrom:
36 | secretKeyRef:
37 | key: network_id
38 | name: {{ .Release.Name }}-auth
39 | - name: TZ
40 | value: {{ .Values.TZ }}
41 | resources:
42 | {{- toYaml .Values.resources | nindent 12 }}
43 | {{- with .Values.nodeSelector }}
44 | nodeSelector:
45 | {{- toYaml . | nindent 8 }}
46 | {{- end }}
47 | {{- with .Values.affinity }}
48 | affinity:
49 | {{- toYaml . | nindent 8 }}
50 | {{- end }}
51 | {{- with .Values.tolerations }}
52 | tolerations:
53 | {{- toYaml . | nindent 8 }}
54 | {{- end }}
55 |
--------------------------------------------------------------------------------
/charts/isp-logger/templates/secret.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: {{ .Release.Name }}-auth
5 | data:
6 | network_id: {{ .Values.network_id | b64enc }}
7 |
8 |
--------------------------------------------------------------------------------
/charts/isp-logger/values.yaml:
--------------------------------------------------------------------------------
1 | # Default values for isp-logger.
2 |
3 | replicaCount: 1
4 |
5 | image:
6 | repository: ronaldl93/isp-logger
7 | tag: "latest"
8 |
9 | network_id: ""
10 | TZ: "UTC"
11 |
12 | imagePullSecrets: []
13 | nameOverride: ""
14 | fullnameOverride: ""
15 |
16 | podAnnotations: {}
17 |
18 | podSecurityContext: {}
19 | # fsGroup: 2000
20 |
21 | securityContext: {}
22 | # capabilities:
23 | # drop:
24 | # - ALL
25 | # readOnlyRootFilesystem: true
26 | # runAsNonRoot: true
27 | # runAsUser: 1000
28 |
29 | resources: {}
30 | # We usually recommend not to specify default resources and to leave this as a conscious
31 | # choice for the user. This also increases chances charts run on environments with little
32 | # resources, such as Minikube. If you do want to specify resources, uncomment the following
33 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
34 | # limits:
35 | # cpu: 100m
36 | # memory: 128Mi
37 | # requests:
38 | # cpu: 100m
39 | # memory: 128Mi
40 |
41 | nodeSelector: {}
42 |
43 | tolerations: []
44 |
45 | affinity: {}
46 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | APScheduler==3.6.3
2 | astroid==2.4.2
3 | certifi==2020.12.5
4 | chardet==4.0.0
5 | idna==2.10
6 | isort==5.6.4
7 | lazy-object-proxy==1.4.3
8 | mccabe==0.6.1
9 | pylint==2.6.0
10 | python-dotenv==0.15.0
11 | pytz==2020.5
12 | requests==2.25.1
13 | six==1.15.0
14 | speedtest-cli==2.1.3
15 | toml==0.10.2
16 | tzlocal==2.1
17 | urllib3==1.26.2
18 | wrapt==1.12.1
19 |
--------------------------------------------------------------------------------
/script.py:
--------------------------------------------------------------------------------
1 | from dotenv import load_dotenv
2 | load_dotenv()
3 | import speedtest
4 | import requests
5 | import json
6 | import datetime
7 | import os
8 | from apscheduler.schedulers.blocking import BlockingScheduler
9 | import logging
10 | import ssl
11 |
12 |
13 | ssl._create_default_https_context = ssl._create_unverified_context
14 |
15 | sched = BlockingScheduler()
16 |
17 | # Enable logging
18 | logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
19 | level=logging.INFO)
20 |
21 | logger = logging.getLogger(__name__)
22 |
23 |
24 | key = os.environ.get("NETWORK_ID", False)
25 | server = "https://api.isplogger.com"
26 |
27 | def initSpeedtest():
28 | # key = os.environ.get("NETWORK_ID")
29 | print("Speedtest in Progress")
30 | s = speedtest.Speedtest()
31 | s.get_servers()
32 | s.get_best_server()
33 | s.download()
34 | s.upload()
35 | res = s.results.dict()
36 | data = {
37 | "status": "success",
38 | "upload": int(res["upload"]),
39 | "download": int(res["download"]),
40 | "ping": res["ping"],
41 | "isp": res["client"]["isp"],
42 | "ip": res["client"]["ip"],
43 | "country": res["client"]["country"],
44 | "sent": res["bytes_sent"],
45 | "received": res["bytes_received"]
46 | }
47 |
48 | return data
49 |
50 | @sched.scheduled_job('interval', minutes=60, id='tester')
51 | def test():
52 | attempts = 10
53 | key = os.environ.get("NETWORK_ID")
54 | for i in range(attempts):
55 |
56 | try:
57 |
58 | tst = initSpeedtest()
59 | req = requests.post(server + "/api/speedtest/"+key, data=tst)
60 | print("Test complete")
61 | return "OK"
62 |
63 | except Exception as e:
64 | print(e)
65 | if i < attempts - 1:
66 | pass
67 | return "error"
68 | else:
69 | raise
70 | break
71 |
72 | if key is not False:
73 | test()
74 | sched.start()
75 | else:
76 | net_key = input("Enter the network key, obtained from the ISP Logger dashboard: ")
77 | os.environ["NETWORK_ID"] = str(net_key)
78 | test()
79 | sched.start()
--------------------------------------------------------------------------------