Commit 816a5393 authored by Dominik Hebeler's avatar Dominik Hebeler
Browse files

Merge branch '247-log-erweitern' into 'development'

Resolve "Log erweitern"

Closes #247

See merge request !413
parents 1c22092e 0782a9b2
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Redis;
class LogRotate extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'log:rotate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Dieses Kommando bezieht alle Log-Einträge aus dem Redis System und exportiert diese in entsprechende Dateien.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
# Wir extrahieren die Logs mit den Daten der einzelnen Suchmaschinen:
# In den Daten ist festgehalten, wie oft eine jede Suchmaschine abgefragt wurde
# und wie häufig diese geantwortet hat:
$this->extractSearchEngineLogs();
}
private function extractSearchEngineLogs()
{
$redis = Redis::connection('redisLogs');
# Hier legen wir das Ergebnis ab:
# [
# 'fastbot' => [
# ''
# ]
# ]
$searchEngineLogs = ['recent' => [], 'overall' => []];
try {
# Wir benötigen zunächst die Namen aller Suchmaschinen:
$sumasFile = config_path() . "/sumas.xml";
$xml = simplexml_load_file($sumasFile);
$xml = $xml->xpath("suma");
$sumaNames = [];
foreach ($xml as $suma) {
$searchEngineLogs['recent'][$suma["name"]->__toString()] = ["requests" => 0, "answered" => 0];
}
#Auslesen/hinzufügen der Daten:
foreach ($searchEngineLogs['recent'] as $name => $values) {
$searchEngineLogs['recent'][$name]["requests"] = $redis->getset('logs.engines.requests.' . $name, 0);
$searchEngineLogs['recent'][$name]["answered"] = $redis->getset('logs.engines.answered.' . $name, 0);
}
$filePath = "/var/log/metager/";
# Wir haben nun die aktuellen daten und müssen diese noch mit den aktuellen Kombinieren:
# Hierbei behalten wir die Daten, seid dem letzten Rotate so wie sie sind und verknüpfen diese mit einer gesamt Statistik.
if (file_exists($filePath . "engine.log") && is_readable($filePath . "engine.log")) {
$oldData = file_get_contents($filePath . "engine.log");
# JSON Decode
$oldData = json_decode($oldData, true);
if (isset($oldData['overall'])) {
$searchEngineLogs['overall'] = $oldData['overall'];
}
}
# Jetzt fügen wir zu den Gesamtdaten die zuletzt erfassten hinzu:
foreach ($searchEngineLogs['recent'] as $name => $values) {
if (isset($searchEngineLogs['overall'][$name]["requests"])) {
$searchEngineLogs['overall'][$name]["requests"] += $values["requests"];
} else {
$searchEngineLogs['overall'][$name]["requests"] = $values["requests"];
}
if (isset($searchEngineLogs['overall'][$name]["answered"])) {
$searchEngineLogs['overall'][$name]["answered"] += $values["answered"];
} else {
$searchEngineLogs['overall'][$name]["answered"] = $values["answered"];
}
}
# Ins JSON Format umwandeln:
$searchEngineLogs = json_encode($searchEngineLogs, JSON_PRETTY_PRINT);
# Und in die Datei sichern
if (((file_exists($filePath . "engine.log") && is_writable($filePath . "engine.log")) || (!file_exists($filePath . "engine.log") && is_writable($filePath))) && file_put_contents($filePath . "engine.log", $searchEngineLogs) !== false) {
$this->info("Logs der Suchmaschinen erfolgreich exportiert.");
return;
} else {
# Der Schreibvorgang war nicht erfolgreich. Wir packen die Daten zurück
foreach (json_decode($searchEngineLogs, true) as $name => $values) {
$redis->incrby('logs.engines.requests.' . $name, $values["requests"]);
$redis->incrby('logs.engines.answered.' . $name, $values["answered"]);
}
$this->info("Konnte die Datei \"$filePath" . "engine.log\" nicht erstellen. Keine Rechte.");
return;
}
} catch (\ErrorException $e) {
return;
}
}
}
......@@ -13,7 +13,7 @@ class Kernel extends ConsoleKernel
* @var array
*/
protected $commands = [
// Commands\Inspire::class,
Commands\LogRotate::class,
];
/**
......@@ -24,6 +24,7 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('log:rotate')->everyTenMinutes();
// $schedule->command('inspire')
// ->hourly();
}
......
......@@ -96,4 +96,37 @@ class AdminInterface extends Controller
->with('title', 'Wer sucht was? - MetaGer')
->with('q', $q);
}
public function engines()
{
# Wir laden den Inhalt der Log Datei und übergeben ihn an den view
$file = "/var/log/metager/engine.log";
if (file_exists($file) && is_readable($file)) {
$engineStats = file_get_contents($file);
# Daten vom JSON Format dekodieren
$engineStats = json_decode($engineStats, true);
# Eine Sortierung wäre nicht das verkehrteste
uasort($engineStats["recent"], function ($a, $b) {
if ($a["requests"] == $b["requests"]) {
return 0;
}
return ($a["requests"] < $b["requests"]) ? 1 : -1;
});
uasort($engineStats["overall"], function ($a, $b) {
if ($a["requests"] == $b["requests"]) {
return 0;
}
return ($a["requests"] < $b["requests"]) ? 1 : -1;
});
return view('admin.engines')
->with('engineStats', $engineStats)
->with('title', "Suchmaschinenstatus - MetaGer");
} else {
return redirect(url('admin'));
}
}
}
......@@ -144,6 +144,7 @@ Route::group(
Route::get('admin', 'AdminInterface@index');
Route::get('admin/count', 'AdminInterface@count');
Route::get('admin/check', 'AdminInterface@check');
Route::get('admin/engines', 'AdminInterface@engines');
Route::get('settings', 'StartpageController@loadSettings');
......
......@@ -524,19 +524,20 @@ class MetaGer
*/
# Wir zählen die Suchmaschinen, die durch den Cache beantwortet wurden:
$enginesToLoad = 0;
$enginesToLoad = [];
$canBreak = false;
foreach ($engines as $engine) {
if ($engine->cached) {
$enginesToLoad--;
if ($overtureEnabled && ($engine->name === "overture" || $engine->name === "overtureAds")) {
$canBreak = true;
}
} else {
# Das Array zählt einerseits die Suchmaschinen, auf die wir warten und andererseits
# welche Suchmaschinen nicht rechtzeitig geantwortet haben.
$enginesToLoad[$engine->name] = false;
}
}
$enginesToLoad += count($engines);
$this->waitForResults($enginesToLoad, $overtureEnabled, $canBreak);
$this->retrieveResults($engines);
......@@ -616,6 +617,10 @@ class MetaGer
{
$loadedEngines = 0;
$timeStart = microtime(true);
# Auf wie viele Suchmaschinen warten wir?
$engineCount = count($enginesToLoad);
while (true) {
$time = (microtime(true) - $timeStart) * 1000;
$loadedEngines = intval(Redis::hlen('search.' . $this->getHashCode()));
......@@ -625,12 +630,12 @@ class MetaGer
# Abbruchbedingung
if ($time < 500) {
if (($enginesToLoad === 0 || $loadedEngines >= $enginesToLoad) && $canBreak) {
if (($engineCount === 0 || $loadedEngines >= $engineCount) && $canBreak) {
break;
}
} elseif ($time >= 500 && $time < $this->time) {
if (($enginesToLoad === 0 || ($loadedEngines / ($enginesToLoad * 1.0)) >= 0.8) && $canBreak) {
if (($engineCount === 0 || ($loadedEngines / ($engineCount * 1.0)) >= 0.8) && $canBreak) {
break;
}
......@@ -639,6 +644,13 @@ class MetaGer
}
usleep(50000);
}
# Wir haben nun so lange wie möglich gewartet. Wir registrieren nun noch die Suchmaschinen, die geanwortet haben.
$answered = Redis::hgetall('search.' . $this->getHashCode());
foreach ($answered as $key => $value) {
$enginesToLoad[$key] = true;
}
$this->enginesToLoad = $enginesToLoad;
}
public function retrieveResults($engines)
......@@ -940,7 +952,19 @@ class MetaGer
$useragent = str_replace(" ", "", $useragent);
$logEntry .= " time=" . round((microtime(true) - $this->starttime), 2) . " serv=" . $this->fokus;
$logEntry .= " search=" . $this->eingabe;
$redis->rpush('logs.search', $logEntry);
# 2 Arten von Logs in einem wird die Anzahl der Abfragen an eine Suchmaschine gespeichert und in der anderen
# die Anzahl, wie häufig diese Ergebnisse geliefert hat.
$enginesToLoad = $this->enginesToLoad;
$redis->pipeline(function ($pipe) use ($enginesToLoad, $logEntry) {
$pipe->rpush('logs.search', $logEntry);
foreach ($this->enginesToLoad as $name => $answered) {
$pipe->incr('logs.engines.requests.' . $name);
if ($answered) {
$pipe->incr('logs.engines.answered.' . $name);
}
}
});
} catch (\Exception $e) {
return;
}
......
......@@ -178,7 +178,6 @@ abstract class Searchengine
}
}
if ($body !== "") {
$this->loadResults($body);
$this->getNext($metager, $body);
......
@extends('layouts.subPages')
@section('title', $title )
@section('content')
<h1>Suchmaschinenübersicht</h1>
<p>Diese Übersicht gibt Aufschluss darüber, welche Suchmaschinen wie oft abgefragt wurden und zusätzlich wie oft diese innerhalb unseres Timeouts geantwortet haben</p>
<table class="table table-bordered">
<caption>Daten der letzten 10 Minuten</caption>
<thead>
<tr>
<th>Name</th>
<th>Anzahl der gesamten Abfragen</th>
<th>Davon tatsächlich beantwortet</th>
<th>Prozent</th>
</tr>
</thead>
<tbody>
@foreach($engineStats["recent"] as $name => $values)
@if($values["requests"] > 0)
<tr @if($values["requests"] === $values["answered"]) class="success" @else class="danger" @endif>
<td>{{$name}}</td>
<td>{{$values["requests"]}}</td>
<td>{{$values["answered"]}}</td>
<td>{{ floor(($values["answered"] / $values["requests"]) * 100) }}%</td>
</tr>
@endif
@endforeach
</tbody>
</table>
<table class="table table-bordered">
<caption>Daten insgesamt</caption>
<thead>
<tr>
<th>Name</th>
<th>Anzahl der gesamten Abfragen</th>
<th>Davon tatsächlich beantwortet</th>
<th>Prozent</th>
</tr>
</thead>
<tbody>
@foreach($engineStats["overall"] as $name => $values)
@if($values["requests"] > 0)
<tr @if($values["requests"] === $values["answered"]) class="success" @else class="danger" @endif>
<td>{{$name}}</td>
<td>{{$values["requests"]}}</td>
<td>{{$values["answered"]}}</td>
<td>{{ floor(($values["answered"] / $values["requests"]) * 100) }}%</td>
</tr>
@endif
@endforeach
</tbody>
</table>
@endsection
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment