Gesamte Doku

Start

  1. 01Erste Schritte
  2. 02Installation
  3. 03Tracking

Funktionen

  1. 04Das Dashboard
  2. 05Ziele
  3. 06Kurzlinks
  4. 07KI-Quellen und Agenten
  5. 08E-Mail-Berichte
  6. 09Stündlicher Check
  7. 10Frag deine KI

Referenz

  1. 11Konfiguration
  2. 12HTTP-API

Plattformen

  1. 13Eigenständiger Server
  2. 14PHP
  3. 15WordPress
  4. 16Drupal
  5. 17Craft CMS
  6. 18Python
  7. 19Rails
  8. 20Ruby
  9. 21Go
  10. 22Java
  11. 23.NET
  12. 24Elixir
  13. 25Rust

Vertrauen

  1. 26Datenschutz

Plattformen

Ruby

Runlight läuft mit Ruby 3.2 oder neuer, in einer Rack-App wie Sinatra, Hanami oder Roda, oder als eigenständiger Server auf einer eigenen Domain.

Das Ruby-Gem ist Runlight, noch einmal in Ruby geschrieben. Es liefert dasselbe Dashboard und dieselbe API aus und gibt auf jede Anfrage die Antwort, die auch die TypeScript-Bibliothek gibt. Seine Zahlen landen in denselben Tabellen, deshalb kann jede der beiden eine Datenbank lesen, die die andere geschrieben hat. Es braucht Ruby 3.2 oder neuer und speichert seine Daten über ActiveRecord, das es mitbringt. Für eine Rails-App bietet die Seite Rails eine Engine und einen Generator, die die Einrichtung für dich erledigen.

Installieren

Füge das Gem mit dem Treiber für deine Datenbank hinzu.

bash

bundle add runlight sqlite3

Nimm statt sqlite3 für Postgres pg und für MySQL und MariaDB trilogy oder mysql2.

Die Instanz erstellen

Erstelle beim Start der App eine Instanz und teile sie.

runlight.rb

require "runlight"

RL = Runlight.new(
  store: Runlight::Stores.sqlite("data/runlight.db"),
  site: { name: "example.com", hostnames: ["example.com"], timezone: "Europe/London" },
)

Die Optionen tragen die Namen aus Konfiguration, in Snake Case geschrieben, deshalb funktionieren sites, trust_proxy, rate_limit, mail und managed_sites alle so wie dort. Die Tabellen werden bei der ersten Anfrage angelegt.

Stores

Runlights Tabellen beginnen mit rl_. Jeder Store nimmt prefix:, das stattdessen verwendet wird, etwa Runlight::Stores.sqlite(path, prefix: "wp_rl_"), damit zwei Apps in einer gemeinsamen Datenbank jeweils ihre eigenen Tabellen behalten. Ein Präfix besteht aus bis zu 32 Buchstaben, Ziffern und Unterstrichen und beginnt nicht mit einer Ziffer. store.tables listet die Tabellen des Stores mit Namen auf, für eine App, die Runlight entfernt.

SQLite

ruby

Runlight::Stores.sqlite("data/runlight.db")

Leg die Datei außerhalb jedes Ordners ab, den der Webserver ausliefert. Fehlt der Ordner, wird er angelegt, und die Datenbank läuft im WAL-Modus, sodass sich mehrere Prozesse sie teilen können.

MySQL und MariaDB

ruby

Runlight::Stores.mysql("mysql://runlight:password@127.0.0.1:3306/runlight")

Dieser Store funktioniert mit MySQL 8.0.20 oder neuer und MariaDB 11.4 oder neuer, über das Gem trilogy, wenn es installiert ist, und sonst über mysql2. Eine mariadb://-URL funktioniert auch. statement_timeout: 30_000 bricht jede einzelne Abfrage nach so vielen Millisekunden ab, Standard ist 120000, wie unter Konfiguration.

Postgres

ruby

Runlight::Stores.postgres("postgres://runlight:password@127.0.0.1:5432/runlight")

Dieser Store braucht das Gem pg. Er nimmt ebenfalls statement_timeout:, und schema: "analytics" legt die Tabellen in ein eigenes Schema. Runlight::Stores.url wählt den Store anhand einer DATABASE_URL, die mit postgres://, mysql://, mariadb:// oder sqlite: beginnt.

Die eigene ActiveRecord-Datenbank einer App

ruby

Runlight::Stores.active_record

Dieser Store legt Runlights Tabellen in die Datenbank, mit der ActiveRecord in der App ohnehin verbunden ist, neben die eigenen Tabellen der App. Übergib eine abstrakte Modellklasse, etwa Runlight::Stores.active_record(AnalyticsRecord), um eine andere Datenbank der App zu nutzen. Seine Schreibvorgänge schließen sich einer Transaktion an, die die App offen hat.

Rack-Apps

Setze Runlight in config.ru vor die App.

config.ru

require_relative "runlight"
require_relative "app"

use Runlight::RackApp, runlight: RL, base_path: "/runlight"
run App

Runlight beantwortet die Pfade unter /runlight, die Kurzlinks unter /go und jede Link-Domain, die du unter Einstellungen hinzufügst, und gibt jede andere Anfrage an die App weiter. Nebenbei zeichnet es auch die Abrufe von KI-Agenten auf, was für alle anderen keine Zeit kostet. Runlight prüft seine Anfragen selbst, deshalb kommt es vor jede CSRF-Middleware. Füge das Skript in jede Seite ein, direkt vor </head>.

html

<script defer src="/runlight/s.js"></script>

Setze dann RUNLIGHT_TOKEN auf eine lange zufällige Zeichenkette und öffne einmal /runlight/?token=, gefolgt von dieser Zeichenkette, um dich anzumelden, wie es Erste Schritte beschreibt. Mit accounts: true in den Optionen und einem RUNLIGHT_SECRET melden sich Leute mit ihrer eigenen E-Mail-Adresse und ihrem Passwort an, wie unter Konten. Übergib token:, um das Token im Code festzulegen. Ein leerer String hält das Dashboard dabei geschlossen, und nil lässt es für alle offen.

RL.rack_app(base_path: "/runlight") ist dieselbe App ohne etwas dahinter, für eine config.ru, die sie mit map unter einem eigenen Pfad einhängt.

Ein Kurzlink unter /go/<name>, zu dem es keinen Link dieses Namens gibt, geht weiter an die App, sodass ihre eigene 404-Seite antwortet, so wie die von Rails. RL.rack_app hat keine App dahinter und antwortet selbst mit einem 404. Auf einer Link-Domain ist /go/<name> ein 404 wie jeder andere Pfad, der keiner der Links dieser Domain ist.

Der stündliche Check

Der stündliche Check verschickt E-Mail-Berichte und hält die Daten in Ordnung. Ruf ihn alle paar Minuten auf, über Cron, einen Job-Scheduler oder einen eigenen Thread.

ruby

RL.check

Wenn nichts in der App ihn nach Zeitplan ausführen kann, setze CRON_SECRET und lass einen externen Scheduler damit /runlight/api/check aufrufen, wie Stündlicher Check zeigt.

Der eigenständige Server

Der Befehl runlight des Gems betreibt Runlight auf einer eigenen Domain, etwa stats.example.com, so wie der eigenständige Server. Er liefert das Dashboard an der Wurzel aus, verwaltet die Websites im Dashboard und bietet Konten mit Anmeldung und Kurzlinks auf jeder Domain, die du darauf zeigen lässt.

bash

mkdir stats && cd stats
bundle init && bundle add runlight sqlite3 puma
bundle exec runlight serve

Der Server lauscht auf Port 3000 oder auf PORT. Er läuft unter Puma, wenn das Gem vorhanden ist, und sonst unter WEBrick, und die config.ru im Ordner betreibt ihn unter jedem anderen Rack-Server. Die Daten liegen in runlight-data in dem Ordner, aus dem du ihn startest. Beim ersten Start gibt er einen Link mit einem Einmalcode aus, der das erste Konto anlegt, und bundle exec runlight setup gibt den Link noch einmal aus. Rollen, Einladungen, Zwei-Faktor-Anmeldung und das Hinzufügen von Websites funktionieren wie beim eigenständigen Server.

Die Einstellungen kommen aus den Umgebungsvariablen, die auch das PHP-Drop-in liest, etwa RUNLIGHT_URL, DATABASE_URL, DATA_DIR, RUNLIGHT_SECRET, TRUST_PROXY und RUNLIGHT_GEO, oder aus einer config.rb im Ordner, die einen Hash mit denselben Namen zurückgibt. Sind beide gesetzt, gewinnen die Umgebungsvariablen. Der Server führt den stündlichen Check alle fünf Minuten aus, und bundle exec runlight cron führt ihn über Cron aus, für einen Server, der nicht ständig läuft.

Was der Befehl sonst noch kann, zeigt bundle exec runlight --help. password gibt einem Konto ein neues Passwort und gibt es aus, migrate aktualisiert die Tabellen sofort, und agents liest KI-Agenten aus dem Zugriffslog eines Webservers, so wie es der Befehl des PHP-Drop-ins tut.

Was anders ist als bei der TypeScript-Bibliothek

Das Ruby-Gem besteht dieselben Konformitätstests wie die TypeScript-Bibliothek, auf SQLite, Postgres, MySQL und MariaDB. Die Unterschiede kommen daher, wie Ruby-Apps laufen.

  • Der Connection-Pool ist der von ActiveRecord. Jeder Store, der seine eigene Datenbank öffnet, hat einen Pool von fünf Verbindungen pro Prozess, und Runlight::Stores.active_record nutzt den eigenen ActiveRecord-Pool der App.
  • Was die TypeScript-Bibliothek im Hintergrund erledigt, etwa das Löschen von Besuchen, nachdem eine kürzere Aufbewahrungsdauer gewählt wurde, läuft, sobald die Antwort gesendet ist, wenn der Rack-Server den Body der Antwort schließt.
  • Die Limits für falsche Passwörter liegen in der Datenbank, deshalb teilen sich alle Prozesse sie. Das Rate-Limit des Trackers liegt in kleinen Dateien im temporären Ordner des Systems, die sich alle Prozesse auf einer Maschine teilen.
  • E-Mail-Berichte formatieren Zahlen, Datumsangaben, Geldbeträge und Ländernamen anhand einer Kopie der ICU-Daten, die Node nutzt, weil Ruby keine mitbringt.