Installation PIWIK
Installation
Warnung: Die Datenbank kann sehr viel Platz in Anspruch nehmen! Werden sehr grosse Logfiles importiert und wird dann die Speichergrenze von 100% erreicht, kommt es zum Zusammenbruch aller Webseiten, die an diesem Datenbankserver angehängt sind. Daher macht es aus Sicherheitsgründen Sinn, die PIWIK Datenbank auf eine separate Partition auszulagern!
Die Installation ist sehr einfach. Runterladen, installieren, fertig 🙂
Cronjobs
Auswertung Logfiles
Dazu kann man das import_logs.py Script verwenden, welches sich im Ordner misc/log-analytics von PIWIK befindet.
python /path/to/piwik/misc/log-analytics/import_logs.py --url=http://analytics.example.com access.log --idsite=1234 --recorders=4 --enable-http-errors --enable-http-redirects --enable-static --enable-bots
Gut zu wissen:
- recorders: Anzahl Threads – hier wird am Besten die Anzahl der CPUs eingetragen.
Weitere Infos: PIWIK FAQ
Archivierung der Reports.
crontab -e
5 * * * * /usr/local/bin/php /www/example.com/piwik/misc/cron/archive.php --url=http://piwik.example.com > /dev/null 2>&1
Wird 1x pro Stunde ausgeführt. Nun solltem an noch in den Einstellungen die Archivierung über das Interface deaktivieren:
Einstellungen -> Allgemeine Einstellungen -> "Piwik erlauben, die Archivierung zu starten, wenn Berichte im Browser angezeigt werden." -> NEIN
Berichte für heute (sowie jeden anderen Zeitraum, die den heutigen Tag beinhalten) höchstens so oft neu berechnen: 3600 Sekunden
Einstellungen
Logfiles
Damit Piwik die Logfiles automatisch zuordnen kann – und bei Bedarf neue Sites eröffnen kann, muss bei den Logfiles der Host übergeben werden. Dafür erstellen wir ein extra Logformat – ich nenne es piwik:
vi nginx.conf
http { rewrite_log on; include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; log_format piwik '$host $remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
Nun muss man entsprechend alle access_logs anpassen:
access_log logs/access.log combined;
nach
access_log logs/access.log piwik;
danach Webserver neu starten.
Memory Limit
PIWIK benötigt recht viel Memory für alle Berechnungen. Daher sollte man mind. 512MB zur Verfügung stellen. Dazu einfach im php.ini folgende Zeile eintragen (Tipp: mit HOST= kann man die Einstellung auf eine Domain limitieren)
[HOST=piwik.example.com] memory_limit=1024M max_execution_time=4800 max_input_time=4800
FastCGI
Unbedingt das Timeout höher setzen, sonst gibts bei der Archivierung Fehler und Timeouts.
fastcgi_read_timeout 14400; # 4 Stunden
MySQL RAM Disk
Wenn man MySQL eine RAMDisk zur Verfügung stellt, unbedingt darauf achten, dass tmpfs genügend Platz hat und eventuell SWAP Bereich vergrössern.
Als Beispiel: Nach meinem Datenimport (der mehrere Tage dauerte) war piwik_log_link_visit_action 7.6GB gross. Mein tmpfs 2.6GB. Nachdem ich die Archivierung startete, crashte die Datenbank, da tmpfs voll war.
[ERROR] /usr/local/libexec/mysqld: Disk is full writing './piwik/piwik_log_link_visit_action.TMD' (Errcode: 28). Waiting for someone to free space... (Expect up to 60 secs delay for server to continue after freeing disk space)
[ERROR] /usr/local/libexec/mysqld: Sort aborted: Error writing file '/db/tmpfs01/MYq0e63Y' (Errcode: 28)
[ERROR] /usr/local/libexec/mysqld: Table './piwik/piwik_log_link_visit_action' is marked as crashed and should be repaired
Reparatur Versuche haben nichts gebracht. Die Table piwik_log_link_visit_action wurde nach REPAIR zwar vermeintlich repariert, nach einem erneuten Starten vom Archivierungsscript, hat er sofort wieder abgebrochen mit dem Fehler: Can’t find record in ‚piwik_log_link_visit_action‘
Inzwischen hab ich die RamDisk von 2.6GB auf 6GB vergrössert. Danach haben alle REPAIR, ANALYZE und die Archivierungsscripts problemlos funktioniert.
Speicherplatz
Wenn man Piwik bei den Standardeinstellungen belässt, ist es ein grosser Datenfresser (Ich habe ca. 4 Jahre Daten importiert bei einer grösseren Website und hatte 7.4G Daten – nach dem Löschen konnte ich rund 5GB sparen). Hier erreicht man schon nach kurzer Zeit mehrere GB an Speicherplatz. Daher ist es wichtig, dass man alte Daten regelmässig löscht. Dabei löscht man vorallem die Detail / Trackingdaten. Somit bleiben Historisch interessante Daten weiterhin bestehen.
Sobald alle Daten Importiert und Archiviert sind (siehe Archiv Cronjob), kann man PIWIK dazu veranlassen, alte Daten regelmässig zu löschen:
Einstellungen -> Privatsphäre -> Alte Besucherlogs & Berichte löschen
Achtung, hier ist wirklich wichtig, dass man regelmässig archiviert, damit Tages- Wochen und Jahresstatistiken weiterhin vorhanden sind. Ansonsten sind alle Daten weg!
Weitere Infos: PIWIK FAQ / Datenbankgrösse
GeoIP
Damit die Logfile Auswertungen detailierter sind, sollte man GeoIP verwenden. Aktivierung unter:
Einstellungen -> Standorterkennung
Hier am Besten GeoIP (PECL) verwenden. Falls die geoip.so PHP Extension noch nicht installiert ist, einfach wie folgt installieren:
/usr/ports/net/pecl-geoip make install clean
Das Install Script fügt die Extension auch direkt in /usr/local/etc/php/extensions.ini hinzu. Weitere Details zur GeoIP Konfiguration gibts in diesem Artikel.
Daten Import von Google Analytics
Dazu benötigen erstmal das Python Modul, worüber auf die Google API zugegriffen werden kann.
cd /usr/ports/lang/python make install clean cd /usr/ports/databases/py-MySQLdb make install clean cd /usr/ports/devel/py-gdata make install clean
Nun den Google2Piwik Python Script downloaden für den Import:
https://github.com/clearcode/Google2Piwik
Daten entpacken, google2piwik.conf.sample nach google2piwik.conf kopieren
cp google2piwik.conf.sample google2piwik.conf
und anpassen.
Google API Key
Bei den Google API Daten ist es wichtig, dass man die Gmail Adresse für das Login eingibt. Wenn man eine eigene Domain verwendet (user@example.com) dann funktioniert es nicht. Das Login muss über user@gmail.com laufen.
Den API Key muss man noch haben. Dazu die API Konsole öffnen:
https://code.google.com/apis/console
- Nun unter APIs & Auth -> „Analytics API“ aktivieren.
- Dann unter „Credentials“ -> Public API access einen Server Key generieren.
PIWIK Seiteneinstellungen
Hier ist es wichtig, bei der zu importierenden Page die Zeitzone auf UTC zu stellen.
PIWIK -> Einstellungen -> Verwalten -> Webseiten -> Seite bearbeiten
Optimierung
Der Importscript ist sehr langsam. Marius Cramer hat dazu eine Lösung geschrieben.
Damit ist der Import zwar immernoch langsam, jedoch trotzdem etwas schneller als zuvor.
In der Lösung vom Marius Cramer ist jedoch nur „update_visit_actions“ berücksichtigt. Ich hab dieselbe Änderung jedoch noch bei „update_total_visit_actions“ gemacht, da ich nur mit der einen Änderung keine Verbesserung spührte. Somit sind folgende Anpassungen gemacht:
vi sql.py
alt (ab Zeile 178)
def update_visit_actions(start_date, end_date): raw_sql = """UPDATE {LV} AS lv LEFT JOIN ( SELECT idvisit, COUNT(*) AS visit_actions FROM {LVA} GROUP BY idvisit ) AS m ON m.idvisit = lv.idvisit SET lv.visit_total_actions = m.visit_actions WHERE visit_last_action_time >= %s AND visit_last_action_time <= %s """.format(LV=T_LOGV, LVA=T_LOGVA) cursor.execute(raw_sql, (start_date, end_date)) def update_total_visit_actions(): raw_sql = """UPDATE {LV} AS lv LEFT JOIN ( SELECT idvisit, COUNT(*) AS visit_actions FROM {LVA} GROUP BY idvisit ) AS m ON m.idvisit = lv.idvisit SET lv.visit_total_actions = m.visit_actions """.format(LV=T_LOGV, LVA=T_LOGVA) cursor.execute(raw_sql)
neu
def update_visit_actions(start_date, end_date): raw_sql = """UPDATE {LV} AS lv SET lv.visit_total_actions = ( SELECT COUNT(*) FROM {LVA} as la WHERE la.idvisit = lv.idvisit ) WHERE visit_last_action_time >= %s AND visit_last_action_time <= %s """.format(LV = T_LOGV, LVA = T_LOGVA) cursor.execute(raw_sql, (start_date, end_date)) def update_total_visit_actions(): raw_sql = """UPDATE {LV} AS lv SET lv.visit_total_actions = ( SELECT COUNT(*) FROM {LVA} as la WHERE la.idvisit = lv.idvisit ) """.format(LV=T_LOGV, LVA=T_LOGVA) cursor.execute(raw_sql)
Link zum Original Artikel: http://www.soeren-hentzschel.at/technik/programmierung/2012/06/21/import-von-daten-mit-google2piwik-erheblich-beschleunigen/
Importieren
Sicherung der Daten
Vorher unbedingt ein Backup der bestehenden Datenbank machen! Wer bereits viele alte Daten archiviert hat, und regelmässig alte Tracking Daten (piwik_log_link_visit_action, etc.) löscht, muss unbedingt noch das google2piwik.py Script anpassen, damit die alten Archive nicht gelöscht werden.
- Vor dem Ausführen ein Backup der gesamten DB machen
- google2piwik.py anpassen und die Zeile
sql.clear_archives()
auskommentieren / löschen. Ansonsten werden alle *archive* Tables gelöscht. Und wer regelmässig seine Tracking Daten löscht, wird diese dann nicht mehr restoren können! Wer noch alle Trackingdaten hat (also noch alle Daten in Tables wie piwik_log_link_visit_action vorhanden sind), muss diese Anpassung nicht machen. Anscheinen wurde im Import Script Version 1.3 bereits eine Änderung diesbezüglich gemacht, aber ich hab davon nicht bemerkt. Ich nutzte Version 1.7 und bei mir waren nachher alle Daten weg.
Starten
Nun Script ausführen:
./google2piwik.py -p
nun werden alle Table ID’s angezeigt. Die gewünschte nehmen und in das Config File kopieren.
Jetzt kann der Import beginnen:
./google2piwik.py
Jetzt heisst es warten…. 😉
Tipp: man kann auch mehrere Imports gleichzeitig laufen lassen. Dazu einfach den Ordner mit dem Importscript kopieren und Config erneut anpassen. Auch darauf achten, dass man im Google API mehrere gleichzeitige Zugriffe machen kann. (APIs & Auth -> Analytics API -> Quota -> Per-User-Limit erhöhen)
Daten nach Import aktualisieren
Nach dem Importieren könnte es sein, dass man alles neu berechnen muss.
Das einfachste ist, alle zu re-generierenden piwik_archive_* Tables zu löschen, danach Archiv neu builden. Wichtig ist, dass man nicht einfach alle piwik_archive_* Tables löscht, sondern nur die, die neu berechnet werden müssen. Wichtig ist auch, dass die Tracking Daten noch vorhanden sind.
Fehlermeldungen
Google Import: IndexError: list index out of range
Folgende Daten lassen sich zum Teil nicht importieren. Je nach Site ist es etwas unterschiedlich. Z.B. hat der import für das Datum 2010-06-16 bei der einen Seite fehlgeschlagen, bei der anderen Page hat’s dann aber funktioniert: 2010-06-11 (FAILED), 2010-06-12 (OK), 2010-06-13 (OK), 2010-06-14 (FAILED), 2010-06-15 (OK), 2010-06-16 (OK). Ab 2010-06-17 klappts aber auf jeden Fall wieder. Da mir diese paar Tage nicht so wichtig sind, bin ich nicht auf Lösungssuche gegangen, sondern hab einfach das Startdatum im Configfile entsprechend angepasst. Muss aber wohl irgendwas mit der Datums- /Rangeberechung zu tun haben.
Please wait, this process - depending on popularity of your site may take some time. Fetching paths and titles of pages. Fetching number of unique users in days and months. Exporting 2010-06-16 Traceback (most recent call last): File "./google2piwik.py", line 665, in export_period(start_date, end_date) File "./google2piwik.py", line 72, in export_period export_day(str(currentdate), fetcher) File "./google2piwik.py", line 116, in export_day simulator.initialize(fetcher, "ga:latitude,ga:longitude,ga:hour,ga:flashVersion,ga:javaEnabled,ga:language,ga:screenResolution", "ga:visits") File "./google2piwik.py", line 371, in initialize self.visits[index].first(visit) IndexError: list index out of range
cron/archive.php – Webserver Timeout
Beim Ausführen des Archiv Cronjobs bricht er immer wieder nach kurzer Zeit ab.
2013/12/30 18:57:37 [error] 59060#0: *13 upstream timed out (60: Operation timed out) while reading response header from upstream, client: 178.22.71.83, server: piwik.example.com, request: "GET /index.php?module=API&method=VisitsSummary.getVisits&idSite=1&period=week&date=last260[..] HTTP/1.1", upstream: "fastcgi://unix:/tmp/php-fpm.sock", host: "piwik.example.com"
oder
Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 131072 bytes) in /www/syzzling.com/piwik/2.0.2/core/DataAccess/ArchiveWriter.php on line 139 a:2:{s:6:"result";s:5:"error";s:7:"message";s:81:"Allowed memory size of 536870912 bytes exhausted (tried to allocate 131072 bytes)";}'
Lösung: Memory Limit in PHP und FastCGI Settings machen.
SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
Beim Archivieren (/usr/local/bin/php /www/analyze/console core:archive --OPTS
) bricht der Script plötzlich ab mit dem Fehler:
ERROR [2021-04-09 07:08:56] 10453 Got invalid response from API request: ?module=API&method=API.get&idSite=4&period=day&date=last52&format=php&trigger=archivephp. Response was 'a:2:{s:6:"result";s:5:"error";s:7:"message";s:139:"SQLSTATE[HY000]: General error: 2006 MySQL server has gone away, caused by: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away";}' ERROR [2021-04-09 07:08:56] 10453 Empty or invalid response '' for website id 4, Time elapsed: 191.573s, skipping [Zend_Db_Statement_Exception] SQLSTATE[HY000]: General error: 2006 MySQL server has gone away [PDOException] SQLSTATE[HY000]: General error: 2006 MySQL server has gone away core:archive [--url="..."] [--force-all-websites] [--force-all-periods[="..."]] [--force-timeout-for-periods[="..."]] [--skip-idsites[="..."]] [--skip-all-segments] [--force-idsites[="..."]] [--force-periods[="..."]] [--force-date-last-n="..."] [--force-date-range[="..."]] [--force-idsegments="..."] [--concurrent-requests-per-website[="..."]] [--concurrent-archivers[="..."]] [--disable-scheduled-tasks] [--accept-invalid-ssl-certificate] [--php-cli-options[="..."]]
Die Lösung dazu findet man in der FAQ bei Matomo.
In meinem Fall musste ich innodb_log_file_size
von 256M auf 512M heraufsetzen. Aber ACHTUNG! Den Wert bitte nicht einfach so im /etc/my.cnf ändern und mysql neu starten. Denn das führt wiederum zum Fehler
Error: Unknown storage engine 'InnoDB'
Da MySQL aufgrund der neuen Filesizes von ib_logfile*
InnoDB nicht mehr startet.
Output von /var/log/mysql/mysql-startup.log
InnoDB: Error: log file ./ib_logfile1 is of different size 0 117440512 bytes
InnoDB: than specified in the .cnf file 0 536870912 bytes!
210409 8:17:06 [ERROR] Plugin 'InnoDB' init function returned error.
210409 8:17:06 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
Korrektes Ändern vom Wert innodb_log_file_size
im /etc/my.cnf
Damit MySQL wieder sauber startet nach dem Ändern des Wertes, am Besten diese Schritte in der angegebenen Reihenfolge ausführen (Den gesamten Lösungsweg inkl. genauerer Beschreibung findest du auf dem StackExchange Forum):
vi /etc/my.cnf
–> Ändere den Wert voninnodb_log_file_size
unterhalb vom Abschnitt[mysqld]
–> Speichere die Änderung im my.cnf- Führe folgende Globalen MySQL Queries aus (Den Dirty Pages Wert optimalerweise so 1 Stunde vor Shutdown):
SET GLOBAL innodb_max_dirty_pages_pct = 0;
SET GLOBAL innodb_fast_shutdown = 0;
Nach dem Reboot werden diese Variabeln automatisch wieder auf die ursprünglichen Werte gesetzt. - Vergewissere dich, dass die Festplatte wo die
ib_logfiles
drauf sind auch genügend Speicherplatz haben für die neuen Filegrössen. Ansonsten vergrössere das Laufwerk oder lagere einige grössere Datenbanken auf eine zweite Festplatte aus. - Stoppe MySQL
/usr/local/etc/rc.d/mysql-server stop
- Verschiebe die ib_logfiles als Backup in ein anderes Verzeichnis (mit genügend Platz)
mv /database/ib_logfile* /tmp/
- MySQL neu starten
/usr/local/etc/rc.d/mysql-server stop
- Und startup-logfile Checken
tail -f /var/log/mysql/mysql-startup.log
Beim Neustart werden die ib_logfiles 0 und 1 wieder neu erstellt.
Wenn nun alles sauber funktioniert, kann man die alten Backups der ib_logfiles im /tmp Folder nun bedenkenlos löschen.
Sollte es nicht funktionieren, setze den Wert von innodb_log_file_size
wieder auf den ursprünglichen Wert und kopiere die gebackupten Logfiles wieder ins Mysql Verzeichnis um den ursprünglichen Zustand wieder herzustellen & Starte Mysql neu. Es sollte nun wieder wie vor der Änderungen funktionieren.
.