Log class – klasa loggera zdarzeń cz 2

W pierwszej części Log class – klasa loggera zdarzeń 1 rozpoczęliśmy prace nad klasą logowania zdarzeń. Utworzyliśmy interfejs klasy, który będzie implementowany. W tej części zajmiemy się implementacją tego interfejsu.

Z racji użycia interfejsu, klasy naszego loggera muszą zawierać 3 publiczne, statyczne metody: error(), warn(), info(). Najłatwiejszym, a zarazem dość przenośnym rodzajem klasy logowania do napisania jest logowanie do pliku. Zatem stwórzmy taką klasę:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class logFile implements log_log {
	public static function error($err){
		echo 'logFile - error |'.$err;
	}
	public static function warn($err){
		echo 'logFile - warn |'.$err;
	}
	public static function info($err){
		echo 'logFile - info |'.$err;
	}
}
?>

Taki zarys musi mieć (ze względu na implementację interfejsu) nasza klasa logFile – logująca do pliku. Jednak to co mamy do tej pory nie jest zbyt użyteczne 😉 Zatem zajmijmy się wypełnieniem metod:

Wszystkie z trzech metod mają za zadanie zapisać informację do logu, z tą różnicą, że są to informacją z inną flagą (błąd, ostrzeżenie, informacja). Zatem możemy je połączyć w jedną write(), która będzie zapisywać log do pliku.

<?php
/**
 * Zapis pojedynczego komunikatu
 * @param	string	$logMsg	Pojedynczy komunikat
 */
private function write($logMsg){
    file_put_contents(self::$file_name,$logMsg,FILE_APPEND | LOCK_EX);	
}
?>

Zapis do logu jak widzimy możemy przeprowadzić za pomocą file_put_contents 2 , z ustawionymi flagami FILE_APPEND | LOCK_EX – dopisywaniem do pliku, jeśli istnieje oraz blokowaniem dostępu do pliku na czas zapisu. Dzięki temu logów w naszym pliku będzie przybywało, nie będą zastępowane, nadpisywane.

Po dodaniu metody write trzy wcześniej utworzone powinny ją wywoływać. Zatem w ciele metod dodajemy wywołanie metody write:

<?php
/**
 * Dodanie komunikatu informacyjnego do logów
 * @see log_log#info($msg)
 */
public static function info($msg){
	self::write(self::logPrefix('INFO').$msg);
}
?>

Pojawiła się tu nowa rzecz: self::logPrefix('INFO');. Otóż jest to wywołanie kolejnej metody, która ma za zadania do linii logu dodać informację o rodzaju zdarzenia, które jest logowane. Jak ta metoda wygląda w przypadku logowania do pliku? Następująco:

<?php
/**
 * Dodanie przedrostka do linijki logu
 * @param	string	$flag	Flaga określająca rodzaj zdarzenia
 * @return	string
 */
private function logPrefix($flag){
	return "\n".date('Y-m-d H:i:s')."\t|".$flag."\t|\t";
}
?>

Przyjęty format pliku logu wygląda następująco:

TIMESTAMP	|TYPE	|	MESSAGE

Przykładowo:

2009-09-02 10:50:07	|INFO	|	Pomyślnie zakończono akcję 123
2009-09-02 10:50:07	|WARN	|	Brak aktywnych zadań
2009-09-02 10:50:33	|ERROR	|	Połączenie zerwane

Wykańczając naszą klasę loggera dogramy kilka szczegółów: wybór pliku logu, ustawienie domyślnego logu w przypadku jego braku. Możemy to zrobić na kilka sposobów, jeden z nich:

<?php
/**
 * Plik logu
 * @var	string 
 */
private static $file_name;
/**
 * Ustawienie nazwy pliku logu z danego dnia
 */
public function setFile($logFile){
	self::$file_name = $logFile;
}
?>

Zbierając to w całość otrzymujemy taką klasę logFile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?php
/**
 * Klasa logowania do pliku, implementująca interfejs log_log
 * @author Vokiel
 * @package log
 */
class logFile implements log_log {
	/**
	 * Plik logu
	 * @var	string 
	 */
	private static $file_name;
 
	/**
	 * Ustawienie domyślnego pliku logu
	 * @return unknown_type
	 */
	public function __construct($logFile=''){
		$file_name = 'logs/'.date('Y-m').'_default.log';
		if ($logFile){
			$file_name = $logFile;
		}
		self::setFile($file_name);
	}
	/**
	 * Ustawienie nazwy pliku logu z danego dnia
	 */
	public function setFile($logFile){
		self::$file_name = $logFile;
	}
	/**
	 * Dodanie błędu do logów
	 * @see logInterface#error($err)
	 */
	public static function error($msg){
		self::write(self::logPrefix('ERROR').$msg); 
	}
	/**
	 * Dodanie ostrzeżenia do logów
	 * @see logInterface#warning()
	 */
	public static function warn($msg){
		self::write(self::logPrefix('WARN').$msg);
	}
	/**
	 * Dodanie komunikatu informacyjnego do logów
	 * @see log_log#info($msg)
	 */
	public static function info($msg){
		self::write(self::logPrefix('INFO').$msg);
	}
 
	/**
	 * Zapis pojedynczego komunikatu
	 * @param	string	$logMsg	Pojedynczy komunikat
	 */
	private function write($logMsg){
		file_put_contents(self::$file_name,$logMsg,FILE_APPEND | LOCK_EX);	
	}
	/**
	 * Dodanie przedrostka do linijki logu
	 * @param	string	$flag	Flaga określająca rodzaj zdarzenia
	 * @return	string
	 */
	private function logPrefix($flag){
		return "\n".date('Y-m-d H:i:s')."\t|".$flag."\t|\t";
	}
 
}// end of logFile
?>

Użycie jest banalnie proste, tak jak zakładaliśmy w pierwszym wpisie: Log class – klasa loggera zdarzeń 1:

<?php
logFile::info('Wszystko ok');
logFile::error('Wszystko jak krew w piach!');
?>

Teraz, w przypadku chęci zmiany sposobu logowania, na np.: bazę danych, wystarczy napisać klasę logDB implementującą interfejs log_log. Oczywiście dobrym rozwiązaniem byłoby dodanie metody write(), tak aby usprawnić proces zapisu do logów, jednak nie jest to konieczne, ani wymagane.

Co jeśli zechcielibyśmy płynnie zmieniać sposób logowania zdarzeń? Np logując część zdarzeń do pliku a część do bazy? Sprawa banalnie prosta:

<?php
logFile::info('To zapisujemy do pliku');
logDB::error('A tu zapiszemy do bazy');
?>

W trakcie używania takich klas może pojawić się sytuacja, w której okaże się, że zechcemy zmienić sposób logowania dla całego pliku, części aplikacji etc. (sam miałem taką sytuację – początkowo logowanie do pliku było wystarczające, później okazało się, że jednak przejdę na bazę). Zmiana z logFile na logDB w całym projekcie nie jest mądrym rozwiązaniem. Ale i z tym sobie poradzimy – w trzeciej, ostatniej, części opisującej loggera zdarzeń.

Źródła

  1. http://blog.vokiel.com/log-class-klasa-loggera-zdarzen [] []
  2. http://pl.php.net/manual/pl/function.file-put-contents.php []
 

Przeczytaj także

Komentarze: 1

Dodaj komentarz »

 
 
 

[…] klasy Log, ustaliliśmy strukturę, zasady funkcjonowania klasy oraz napisaliśmy interfejs. W drugiej części rozwinęliśmy nasz projekt o klasę logFile implementującą wcześniej utworzony interfejs, […]

 

Odpowiedz

 

Dodaj komentarz

 
(nie będzie publikowany)
 
 
Komentarz
 
 

Dozwolone tagi XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
© 2009 - 2023 Vokiel.com
WordPress Theme by Arcsin modified by Vokiel