Przejdź do głównej zawartości

Dziennik wydarzeń

Stworzycie Dziennik wydarzeń - aplikację webową do rejestrowania zdarzeń (logów) systemowych lub operacyjnych. To narzędzie, które pozwala administratorom, programistom lub operatorom dokumentować ważne wydarzenia - od błędów technicznych, przez ostrzeżenia, po informacje o wykonanych operacjach. System jest niezbędny do debugowania problemów i monitorowania stanu aplikacji.

Czego się nauczycie?

  • Pracy z plikami tekstowymi (zapis linia po linii)
  • Obsługi poziomów logowania (INFO, WARN, ERROR)
  • Kategoryzacji i filtrowania danych
  • Formatowania znaczników czasu (timestamps)
  • Praca zespołowa - podział zadań, współpraca, integracja kodu

W prawdziwej firmie...

Każda profesjonalna aplikacja ma system logowania. Serwery webowe (Apache, Nginx), bazy danych, aplikacje biznesowe - wszystkie generują logi. Umiejętność tworzenia i analizowania logów to podstawa pracy DevOps, administratora systemów i programisty.

Umiejętności rynkowe

Zrozumiecie koncepcję poziomów logowania (DEBUG, INFO, WARN, ERROR, FATAL) używaną w każdym profesjonalnym frameworku. Nauczycie się strukturyzować dane tak, aby były łatwe do przeszukiwania i analizy.

  1. Formularz dodawania wpisu Użytkownik wypełnia formularz z danymi zdarzenia: tytuł, opis, kategoria (np. “system”, “security”, “database”), poziom ważności (INFO/WARN/ERROR). System automatycznie dodaje znacznik czasu.

  2. Walidacja i zapis System sprawdza poprawność danych - czy wybrano prawidłowy poziom, czy wypełniono wymagane pola. Poprawne wpisy są zapisywane do pliku tekstowego (CSV/TSV) lub JSON Lines.

  3. Lista wpisów z filtrami Panel przeglądania wszystkich wpisów z możliwością filtrowania po poziomie (pokaż tylko ERROR) lub kategorii. Wpisy są posortowane od najnowszych.

  4. Podgląd szczegółów Możliwość obejrzenia pełnej treści wpisu wraz że wszystkimi metadanymi (timestamp, autor, kategoria).

Strona główna / Formularz

  • Formularz dodawania wpisu
  • Select z poziomami (INFO/WARN/ERROR)
  • Select z kategoriami
  • Pole tytułu i opisu
  • Przycisk “Dodaj wpis”

Lista logów

  • Tabela wszystkich wpisów
  • Kolorowe oznaczenia poziomów
  • Filtry po poziomie/kategorii
  • Sortowanie po dacie

Szczegóły wpisu

  • Pełna treść zdarzenia
  • Wszystkie metadane
  • Timestamp utworzenia

Eksport (wariant C)

  • Generowanie raportu HTML
  • Eksport do JSON
  • Filtrowanie przed eksportem

Przykładowa struktura pliku (format CSV/TSV):

id;timestamp;level;category;title;message;operator
1;2026-02-13 10:30:00;ERROR;database;Błąd połączenia;Nie można połączyć z bazą danych MySQL - timeout po 30s;admin
2;2026-02-13 10:35:00;INFO;system;Restart serwera;Planowy restart serwera zakończony pomyślnie;system
3;2026-02-13 11:00:00;WARN;security;Nieudane logowanie;3 nieudane próby logowania dla użytkownika jan.kowalski;security_bot

Alternatywnie - format JSON Lines (każda linia to osobny JSON):

{"id":1,"timestamp":"2026-02-13 10:30:00","level":"ERROR","category":"database","title":"Błąd połączenia","message":"Nie można połączyć z bazą danych MySQL - timeout po 30s","operator":"admin"}
{"id":2,"timestamp":"2026-02-13 10:35:00","level":"INFO","category":"system","title":"Restart serwera","message":"Planowy restart serwera zakończony pomyślnie","operator":"system"}

Wymagane funkcjonalności:

  • Formularz wpisu: tytuł, opis, kategoria, poziom (INFO/WARN/ERROR)
  • Walidacja PHP wszystkich pól
  • Minimum 1 walidacja JavaScript
  • Zapis do pliku TXT (format: 1 linia = 1 wpis, pola oddzielone separatorem)
  • Automatyczny timestamp przy zapisie
  • Generowanie unikalnego ID
  • Lista wszystkich wpisów z odczytem z pliku
  • Wyświetlanie komunikatów o błędach

Struktura plików:

  • Folderprojekt/
    • index.php (formularz + logika)
    • list.php (lista logów)
    • README.md
    • Folderdata/
      • events.txt
    • Foldercss/
      • style.css
    • Folderjs/
      • validation.js
Ocena: 3.0
  1. Administrator wykrywa problem z połączeniem do bazy danych
  2. Otwiera dziennik wydarzeń i wypełnia formularz
  3. Wybiera poziom “ERROR” i kategorię “database”
  4. Wpisuje tytuł “Błąd połączenia z MySQL” i szczegółowy opis
  5. Klika “Dodaj wpis”
  6. System waliduje, dodaje timestamp i zapisuje do pliku
  7. Wpis pojawia się na liście z czerwonym oznaczeniem
  1. Programista chcę sprawdzić wszystkie błędy z ostatniego dnia
  2. Otwiera listę logów
  3. Ustawia filtr na poziom “ERROR”
  4. Przegląda wpisy, szukając wzorców
  5. Klika w szczegóły interesującego wpisu
  6. Analizuje pełny opis i timestamp
  1. Kierownik prosi o raport błędów z ostatniego tygodnia
  2. Admin loguje się do systemu
  3. Filtruje wpisy po poziomie “ERROR” i zakresie dat
  4. Klika “Eksportuj do HTML”
  5. System generuje czytelny raport z tabelą
  6. Admin przesyła raport kierownikowi

Zapis linii do pliku TXT:

<?php
function appendLog(string $filePath, array $entry): bool {
// Format: id;timestamp;level;category;title;message
$line = implode(';', [
$entry['id'],
$entry['timestamp'],
$entry['level'],
$entry['category'],
// Escapuj średniki w treści
str_replace(';', '\\;', $entry['title']),
str_replace(';', '\\;', $entry['message'])
]) . PHP_EOL;
return file_put_contents($filePath, $line, FILE_APPEND | LOCK_EX) !== false;
}
// Użycie:
$entry = [
'id' => generateId(),
'timestamp' => date('Y-m-d H:i:s'),
'level' => 'ERROR',
'category' => 'database',
'title' => 'Błąd połączenia',
'message' => 'Nie można połączyć z bazą danych'
];
appendLog('data/events.txt', $entry);

Odczyt logów z pliku:

<?php
function readLogs(string $filePath): array {
if (!file_exists($filePath)) {
return [];
}
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$logs = [];
foreach ($lines as $line) {
$parts = explode(';', $line);
if (count($parts) >= 6) {
$logs[] = [
'id' => (int)$parts[0],
'timestamp' => $parts[1],
'level' => $parts[2],
'category' => $parts[3],
'title' => str_replace('\\;', ';', $parts[4]),
'message' => str_replace('\\;', ';', $parts[5])
];
}
}
// Sortuj od najnowszych
usort($logs, fn($a, $b) => strcmp($b['timestamp'], $a['timestamp']));
return $logs;
}

Walidacja poziomu logowania:

<?php
function validateLevel(string $level): bool {
$allowedLevels = ['INFO', 'WARN', 'ERROR'];
return in_array($level, $allowedLevels, true);
}
function validateCategory(string $category): bool {
$allowedCategories = ['system', 'security', 'database', 'application', 'network'];
return in_array($category, $allowedCategories, true);
}

Filtrowanie logów:

<?php
function filterLogs(array $logs, ?string $level = null, ?string $category = null): array {
return array_filter($logs, function($log) use ($level, $category) {
if ($level !== null && $log['level'] !== $level) {
return false;
}
if ($category !== null && $log['category'] !== $category) {
return false;
}
return true;
});
}
// Użycie:
$allLogs = readLogs('data/events.txt');
$errors = filterLogs($allLogs, 'ERROR'); // Tylko błędy
$dbLogs = filterLogs($allLogs, null, 'database'); // Tylko z kategorii database

CSS dla poziomów logowania:

.log-level {
padding: 2px 8px;
border-radius: 4px;
font-weight: bold;
font-size: 0.85em;
}
.log-level-info {
background-color: #d1fae5;
color: #065f46;
}
.log-level-warn {
background-color: #fef3c7;
color: #92400e;
}
.log-level-error {
background-color: #fee2e2;
color: #991b1b;
}

To prawdziwy projekt zespołowy!

Ten projekt to symulacja pracy w firmie IT. System logowania to podstawa każdej profesjonalnej aplikacji - nauczycie się tworzyć coś, co jest używane wszędzie!

Pracujcie iteracyjnie - lepiej mieć działający wariant A niż niedziałający C!