DSL Geschwindigkeiten

Da ich in den vergangenen Wochen einen neuen DSL-Vertrag abgeschlossen habe, bei dem vermehrt Probleme bei der Erreichbarkeit meines privaten Webservers auftraten, habe ich beschlossen Verbindungsgeschwindigkeiten und Erreichbarkeit zu überwachen. Basierend auf diesem Blogpost und dem zugrundeliegenden Python-Tool zur Messung von Verbindungsgeschwindigkeiten von Janis Jansons habe ich eine dauerhafte Geschwindigkeitsüberwachung, die alle 10 Minute ausgeführt wird, eingerichtet.
Da die produzierte *.csv-Datei allerdings reichlich unübersichtlich ist, habe ich ein kleines Skript in R geschrieben, um die Daten, die in die *.csv-Datei geschrieben werden, zu visualisieren. Zunächst muss also R installiert werden. Unter Ubuntu erfolgt das mit folgendem Befehl:
sudo apt-get install r-base
Danach speichert man das folgende Skript lokal unter ~/scripts/speedtest_plot.R ab.

### set locale
Sys.setlocale("LC_TIME", "en_US.utf8")

### set working directory
setwd("/home/arnd/")

### import data
data.df <- read.table("speedtest.csv", header=FALSE, sep=",", dec=".", 
                      stringsAsFactors=FALSE, fill=TRUE, na.strings=c("[]", ""))

### preprocess the data
# name the columns
colnames(data.df) <- c("time", "download", "upload", "unit", "server")
# strptime
data.df$time <- strptime(data.df$time, format="%a, %d %b %Y %H:%M:%S %z", tz="")
# down- & upload
data.df$download[which(data.df$download == -1)] <- NA
data.df$upload[which(data.df$upload == -1)] <- NA
# manipulate server names => remove brackets
data.df$server <- gsub("[", "", data.df$server, fixed=TRUE)
data.df$server <- gsub("]", "", data.df$server, fixed=TRUE)
data.df$server <- gsub("'", "", data.df$server, fixed=TRUE)
#unique(data.df$server)
# create and factorize date
data.df$date <- strptime(data.df$time, format="%Y-%m-%d")
data.df$fdate <- as.factor(as.character(data.df$date))

### plot
pdf("speedtest_plot.pdf")
par(font.lab=2)
plot(data.df$time, data.df$download, type="l", col="blue", lwd=2, xlab="Zeit", 
     ylab="Mbit", main="DSL-Geschwindigkeiten", ylim=c(0,100), xaxt="n")
r <- as.POSIXct(round(range(data.df$time), "days"))
axis.POSIXct(1, at=seq(r[1], r[2], by="day"), format="%d.%m.%y", labels=TRUE)
lines(data.df$time, data.df$upload, col="red", lwd=2)
points(data.df$time[which(is.na(data.df$download) == TRUE)], 
       rep(100, length(which(is.na(data.df$download) == TRUE))), pch=19, 
       cex=0.1, col="blue")
text(data.df$time[ceiling(length(data.df$time)/2)], 97.4, 
     "Zeitpunkte ohne Messung", cex=0.7)
points(data.df$time[which(is.na(data.df$upload) == TRUE)], 
       rep(95, length(which(is.na(data.df$upload) == TRUE))), pch=19, cex=0.1, 
       col="red")
text(data.df$time[1], 55, "DOWNLOAD", col="blue", cex=1.5, pos=4)
text(data.df$time[1], 5, "UPLOAD", col="red", cex=1.5, pos=4)
abline(h=50, lty=3, lwd=0.5)
mtext(paste0("Aktualisiert: ", strftime(Sys.time(), "%d.%m.%Y %H:%M:%S")), 
      cex=0.7)
dev.off()

png("speedtest_plot.png")
par(font.lab=2)
plot(data.df$time, data.df$download, type="l", col="blue", lwd=2, xlab="Zeit", 
     ylab="Mbit", main="DSL-Geschwindigkeiten", ylim=c(0,100), xaxt="n")
r <- as.POSIXct(round(range(data.df$time), "days"))
axis.POSIXct(1, at=seq(r[1], r[2], by="day"), format="%d.%m.%y", labels=TRUE)
lines(data.df$time, data.df$upload, col="red", lwd=2)
points(data.df$time[which(is.na(data.df$download) == TRUE)], 
       rep(100, length(which(is.na(data.df$download) == TRUE))), pch=19, 
       cex=0.1, col="blue")
text(data.df$time[ceiling(length(data.df$time)/2)], 97.4, 
     "Zeitpunkte ohne Messung", cex=0.7)
points(data.df$time[which(is.na(data.df$upload) == TRUE)], 
       rep(95, length(which(is.na(data.df$upload) == TRUE))), pch=19, cex=0.1, 
       col="red")
text(data.df$time[1], 55, "DOWNLOAD", col="blue", cex=1.5, pos=4)
text(data.df$time[1], 5, "UPLOAD", col="red", cex=1.5, pos=4)
abline(h=50, lty=3, lwd=0.5)
mtext(paste0("Aktualisiert: ", strftime(Sys.time(), "%d.%m.%Y %H:%M:%S")), 
      cex=0.7)
dev.off()

###
# subset to print the data only for the last month
# select the last month:
# 60 sec * 60 min * 24 hours * 30 days
# 2592000 = one month
data.df <- subset(data.df, time > max(data.df$time) - 2592000)

png("speedtest_plot_last_month.png", height=720, width=720)
par(font.lab=2)
plot(data.df$time, data.df$download, type="l", col="blue", lwd=2, xlab="Zeit", 
     ylab="Mbit", main="DSL-Geschwindigkeiten", ylim=c(0,100), xaxt="n")
r <- as.POSIXct(round(range(data.df$time), "days"))
axis.POSIXct(1, at=seq(r[1], r[2], by="day"), format="%d.%m.%y", labels=TRUE)
lines(data.df$time, data.df$upload, col="red", lwd=2)
points(data.df$time[which(is.na(data.df$download) == TRUE)], 
       rep(100, length(which(is.na(data.df$download) == TRUE))), pch=19, 
       cex=0.1, col="blue")
text(data.df$time[ceiling(length(data.df$time)/2)], 97.4, 
     "Zeitpunkte ohne Messung", cex=0.8)
points(data.df$time[which(is.na(data.df$upload) == TRUE)], 
       rep(95, length(which(is.na(data.df$upload) == TRUE))), pch=19, cex=0.1, 
       col="red")
text(data.df$time[1], 55, "DOWNLOAD", col="blue", cex=1.5, pos=4)
text(data.df$time[1], 5, "UPLOAD", col="red", cex=1.5, pos=4)
abline(h=50, lty=3, lwd=0.5)
mtext(paste0("Aktualisiert: ", strftime(Sys.time(), "%d.%m.%Y %H:%M:%S")), 
      cex=0.8)
dev.off()

###
# subset to print the data only for the last week
# select the last week:
# 60 sec * 60 min * 24 hours * 7 days
# 640800 = one week
data.df <- subset(data.df, time > max(data.df$time) - 604800)

png("speedtest_plot_last_week.png", height=720, width=720)
par(font.lab=2)
plot(data.df$time, data.df$download, type="l", col="blue", lwd=2, xlab="Zeit", 
     ylab="Mbit", main="DSL-Geschwindigkeiten", ylim=c(0,100), xaxt="n")
r <- as.POSIXct(round(range(data.df$time), "days"))
axis.POSIXct(1, at=seq(r[1], r[2], by="day"), format="%d.%m.%y", labels=TRUE)
lines(data.df$time, data.df$upload, col="red", lwd=2)
points(data.df$time[which(is.na(data.df$download) == TRUE)], 
       rep(100, length(which(is.na(data.df$download) == TRUE))), pch=19, 
       cex=0.1, col="blue")
text(data.df$time[ceiling(length(data.df$time)/2)], 97.4, 
     "Zeitpunkte ohne Messung", cex=0.8)
points(data.df$time[which(is.na(data.df$upload) == TRUE)], 
       rep(95, length(which(is.na(data.df$upload) == TRUE))), pch=19, cex=0.1, 
       col="red")
text(data.df$time[1], 55, "DOWNLOAD", col="blue", cex=1.5, pos=4)
text(data.df$time[1], 5, "UPLOAD", col="red", cex=1.5, pos=4)
abline(h=50, lty=3, lwd=0.5)
mtext(paste0("Aktualisiert: ", strftime(Sys.time(), "%d.%m.%Y %H:%M:%S")), 
      cex=0.8)
dev.off()
q("no")

Und führt es anschliessend ebenso zeitgesteuert, wie den Speedtest, als Cronjob aus. Dazu öffnet man mit crontab -e die Crontab und fügt folgende Zeile ein:
1 * * * * Rscript ~/scripts/speedtest_plot.R 2>&1 /dev/null
Dieser Befehl, der stündlich ausgeführt wird, produziert drei unterschiedliche Plots, von denen einer – nämlich der mit den Ergebnissen der Geschwindigkeitsmessungen der letzten Woche – hier dargestellt ist. Hinter dem verlinkten Bild findeet sich eine interaktive R Shiny-Animation:

Geschwindigkeitsdaten der letzten Woche

2 thoughts on “DSL Geschwindigkeiten

  1. ralf

    Hallo Arnd, beim Ausführen des Scripts erhalte ich diesen Fehler:

    Fehler in plot.window(…) : endliche ‘xlim’ Werte nötig
    Ruft auf: plot -> plot.default -> localWindow -> plot.window
    Zusätzlich: Warnmeldungen:
    1: In min(x) : kein nicht-fehlendes Argument für min; gebe Inf zurück
    2: In max(x) : kein nicht-fehlendes Argument für max; gebe -Inf zurück
    Ausführung angehalten

    Kannst Du mir einen Tip geben wo ich suchen soll?

  2. Arnd Post author

    Das dürfte am Import der Daten (Zeile 8: read.table) oder dem Konvertieren der Zeitspalte von der Klasse “character” nach “POSIXlt” liegen (Zeile 15: strptime).

    read.table:
    Durch andere Spaltenseparatoren (sep=",") oder Dezimaltrennzeichen (dec=".") könnte der Datenimport schief laufen, so dass im folgenden keine Daten in data.df existieren, was erst mit Aufruf des ersten plot-Befehls als Fehlermeldung bemerkbar wird.

    strptime:
    Am wahrscheinlichsten ist aber ein Fehler bei der Konvertierung der Zeit von “character” nach “POSIXlt”. Insbesondere der abgekürzte Wochentag “%a” und der Monat “%b” im Argument format="%a, %d %b %Y %H:%M:%S %z" sind abhängig von lokalen Systemeinstellungen. Das gilt bei der Konvertieung hier in R, aber auch schon beim Export der *.csv-Datei aus Python. In diesem R-Skript ist explizit Sys.setlocale("LC_TIME", "en_US.utf8") gesetzt, vielleicht führt das bei Ihnen zu Problemen.

Leave a Reply

Your email address will not be published. Required fields are marked *