Browse Source

Add Monolog

tags/2019.03^2
Philipp Holzer 6 months ago
parent
commit
2e602afd3e

+ 4
- 1
bin/auth_ejabberd.php View File

@@ -34,6 +34,7 @@
34 34
 
35 35
 use Friendica\App;
36 36
 use Friendica\Util\ExAuth;
37
+use Friendica\Util\LoggerFactory;
37 38
 
38 39
 if (sizeof($_SERVER["argv"]) == 0) {
39 40
 	die();
@@ -51,7 +52,9 @@ chdir($directory);
51 52
 
52 53
 require dirname(__DIR__) . '/vendor/autoload.php';
53 54
 
54
-$a = new App(dirname(__DIR__));
55
+$logger = LoggerFactory::create('auth_ejabberd');
56
+
57
+$a = new App(dirname(__DIR__), $logger);
55 58
 
56 59
 if ($a->getMode()->isNormal()) {
57 60
 	$oAuth = new ExAuth();

+ 5
- 1
bin/console.php View File

@@ -3,7 +3,11 @@
3 3
 
4 4
 require dirname(__DIR__) . '/vendor/autoload.php';
5 5
 
6
-$a = new Friendica\App(dirname(__DIR__));
6
+use Friendica\Util\LoggerFactory;
7
+
8
+$logger = LoggerFactory::create('console');
9
+
10
+$a = new Friendica\App(dirname(__DIR__), $logger);
7 11
 \Friendica\BaseObject::setApp($a);
8 12
 
9 13
 (new Friendica\Core\Console($argv))->execute();

+ 10
- 8
bin/daemon.php View File

@@ -9,9 +9,9 @@
9 9
 
10 10
 use Friendica\App;
11 11
 use Friendica\Core\Config;
12
-use Friendica\Core\Logger;
13 12
 use Friendica\Core\Worker;
14 13
 use Friendica\Database\DBA;
14
+use Friendica\Util\LoggerFactory;
15 15
 
16 16
 // Get options
17 17
 $shortopts = 'f';
@@ -32,7 +32,9 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
32 32
 
33 33
 require dirname(__DIR__) . '/vendor/autoload.php';
34 34
 
35
-$a = new App(dirname(__DIR__));
35
+$logger = LoggerFactory::create('daemon');
36
+
37
+$a = new App(dirname(__DIR__), $logger);
36 38
 
37 39
 if ($a->getMode()->isInstall()) {
38 40
 	die("Friendica isn't properly installed yet.\n");
@@ -102,7 +104,7 @@ if ($mode == "stop") {
102 104
 
103 105
 	unlink($pidfile);
104 106
 
105
-	Logger::log("Worker daemon process $pid was killed.", Logger::DEBUG);
107
+	$logger->notice("Worker daemon process was killed", ["pid" => $pid]);
106 108
 
107 109
 	Config::set('system', 'worker_daemon_mode', false);
108 110
 	die("Worker daemon process $pid was killed.\n");
@@ -112,7 +114,7 @@ if (!empty($pid) && posix_kill($pid, 0)) {
112 114
 	die("Daemon process $pid is already running.\n");
113 115
 }
114 116
 
115
-Logger::log('Starting worker daemon.', Logger::DEBUG);
117
+$logger->notice('Starting worker daemon.', ["pid" => $pid]);
116 118
 
117 119
 if (!$foreground) {
118 120
 	echo "Starting worker daemon.\n";
@@ -160,7 +162,7 @@ $last_cron = 0;
160 162
 // Now running as a daemon.
161 163
 while (true) {
162 164
 	if (!$do_cron && ($last_cron + $wait_interval) < time()) {
163
-		Logger::log('Forcing cron worker call.', Logger::DEBUG);
165
+		$logger->info('Forcing cron worker call.', ["pid" => $pid]);
164 166
 		$do_cron = true;
165 167
 	}
166 168
 
@@ -174,7 +176,7 @@ while (true) {
174 176
 		$last_cron = time();
175 177
 	}
176 178
 
177
-	Logger::log("Sleeping", Logger::DEBUG);
179
+	$logger->info("Sleeping", ["pid" => $pid]);
178 180
 	$start = time();
179 181
 	do {
180 182
 		$seconds = (time() - $start);
@@ -191,10 +193,10 @@ while (true) {
191 193
 
192 194
 	if ($timeout) {
193 195
 		$do_cron = true;
194
-		Logger::log("Woke up after $wait_interval seconds.", Logger::DEBUG);
196
+		$logger->info("Woke up after $wait_interval seconds.", ["pid" => $pid, 'sleep' => $wait_interval]);
195 197
 	} else {
196 198
 		$do_cron = false;
197
-		Logger::log("Worker jobs are calling to be forked.", Logger::DEBUG);
199
+		$logger->info("Worker jobs are calling to be forked.", ["pid" => $pid]);
198 200
 	}
199 201
 }
200 202
 

+ 4
- 1
bin/worker.php View File

@@ -8,6 +8,7 @@ use Friendica\App;
8 8
 use Friendica\Core\Config;
9 9
 use Friendica\Core\Worker;
10 10
 use Friendica\Core\Update;
11
+use Friendica\Util\LoggerFactory;
11 12
 
12 13
 // Get options
13 14
 $shortopts = 'sn';
@@ -28,7 +29,9 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
28 29
 
29 30
 require dirname(__DIR__) . '/vendor/autoload.php';
30 31
 
31
-$a = new App(dirname(__DIR__));
32
+$logger = LoggerFactory::create('worker');
33
+
34
+$a = new App(dirname(__DIR__), $logger);
32 35
 
33 36
 // Check the database structure and possibly fixes it
34 37
 Update::check(true);

+ 2
- 1
composer.json View File

@@ -42,7 +42,8 @@
42 42
 		"npm-asset/jgrowl": "^1.4",
43 43
 		"npm-asset/fullcalendar": "^3.0.1",
44 44
 		"npm-asset/cropperjs": "1.2.2",
45
-		"npm-asset/imagesloaded": "4.1.4"
45
+		"npm-asset/imagesloaded": "4.1.4",
46
+		"monolog/monolog": "^1.24"
46 47
 	},
47 48
 	"repositories": [
48 49
 		{

+ 126
- 1
composer.lock View File

@@ -4,7 +4,7 @@
4 4
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 5
         "This file is @generated automatically"
6 6
     ],
7
-    "content-hash": "51f7b3ab622038d7ef62ed03c06b48d0",
7
+    "content-hash": "8cf7268fbcae8a22a518b9e7727eab84",
8 8
     "packages": [
9 9
         {
10 10
             "name": "asika/simple-console",
@@ -809,6 +809,84 @@
809 809
             ],
810 810
             "time": "2018-09-01T15:05:15+00:00"
811 811
         },
812
+        {
813
+            "name": "monolog/monolog",
814
+            "version": "1.24.0",
815
+            "source": {
816
+                "type": "git",
817
+                "url": "https://github.com/Seldaek/monolog.git",
818
+                "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266"
819
+            },
820
+            "dist": {
821
+                "type": "zip",
822
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266",
823
+                "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266",
824
+                "shasum": ""
825
+            },
826
+            "require": {
827
+                "php": ">=5.3.0",
828
+                "psr/log": "~1.0"
829
+            },
830
+            "provide": {
831
+                "psr/log-implementation": "1.0.0"
832
+            },
833
+            "require-dev": {
834
+                "aws/aws-sdk-php": "^2.4.9 || ^3.0",
835
+                "doctrine/couchdb": "~1.0@dev",
836
+                "graylog2/gelf-php": "~1.0",
837
+                "jakub-onderka/php-parallel-lint": "0.9",
838
+                "php-amqplib/php-amqplib": "~2.4",
839
+                "php-console/php-console": "^3.1.3",
840
+                "phpunit/phpunit": "~4.5",
841
+                "phpunit/phpunit-mock-objects": "2.3.0",
842
+                "ruflin/elastica": ">=0.90 <3.0",
843
+                "sentry/sentry": "^0.13",
844
+                "swiftmailer/swiftmailer": "^5.3|^6.0"
845
+            },
846
+            "suggest": {
847
+                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
848
+                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
849
+                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
850
+                "ext-mongo": "Allow sending log messages to a MongoDB server",
851
+                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
852
+                "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
853
+                "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
854
+                "php-console/php-console": "Allow sending log messages to Google Chrome",
855
+                "rollbar/rollbar": "Allow sending log messages to Rollbar",
856
+                "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
857
+                "sentry/sentry": "Allow sending log messages to a Sentry server"
858
+            },
859
+            "type": "library",
860
+            "extra": {
861
+                "branch-alias": {
862
+                    "dev-master": "2.0.x-dev"
863
+                }
864
+            },
865
+            "autoload": {
866
+                "psr-4": {
867
+                    "Monolog\\": "src/Monolog"
868
+                }
869
+            },
870
+            "notification-url": "https://packagist.org/downloads/",
871
+            "license": [
872
+                "MIT"
873
+            ],
874
+            "authors": [
875
+                {
876
+                    "name": "Jordi Boggiano",
877
+                    "email": "j.boggiano@seld.be",
878
+                    "homepage": "http://seld.be"
879
+                }
880
+            ],
881
+            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
882
+            "homepage": "http://github.com/Seldaek/monolog",
883
+            "keywords": [
884
+                "log",
885
+                "logging",
886
+                "psr-3"
887
+            ],
888
+            "time": "2018-11-05T09:00:11+00:00"
889
+        },
812 890
         {
813 891
             "name": "npm-asset/cropperjs",
814 892
             "version": "1.2.2",
@@ -1810,6 +1888,53 @@
1810 1888
             ],
1811 1889
             "time": "2016-08-06T14:39:51+00:00"
1812 1890
         },
1891
+        {
1892
+            "name": "psr/log",
1893
+            "version": "1.1.0",
1894
+            "source": {
1895
+                "type": "git",
1896
+                "url": "https://github.com/php-fig/log.git",
1897
+                "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
1898
+            },
1899
+            "dist": {
1900
+                "type": "zip",
1901
+                "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
1902
+                "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
1903
+                "shasum": ""
1904
+            },
1905
+            "require": {
1906
+                "php": ">=5.3.0"
1907
+            },
1908
+            "type": "library",
1909
+            "extra": {
1910
+                "branch-alias": {
1911
+                    "dev-master": "1.0.x-dev"
1912
+                }
1913
+            },
1914
+            "autoload": {
1915
+                "psr-4": {
1916
+                    "Psr\\Log\\": "Psr/Log/"
1917
+                }
1918
+            },
1919
+            "notification-url": "https://packagist.org/downloads/",
1920
+            "license": [
1921
+                "MIT"
1922
+            ],
1923
+            "authors": [
1924
+                {
1925
+                    "name": "PHP-FIG",
1926
+                    "homepage": "http://www.php-fig.org/"
1927
+                }
1928
+            ],
1929
+            "description": "Common interface for logging libraries",
1930
+            "homepage": "https://github.com/php-fig/log",
1931
+            "keywords": [
1932
+                "log",
1933
+                "psr",
1934
+                "psr-3"
1935
+            ],
1936
+            "time": "2018-11-20T15:27:04+00:00"
1937
+        },
1813 1938
         {
1814 1939
             "name": "seld/cli-prompt",
1815 1940
             "version": "1.0.3",

+ 41
- 37
include/api.php View File

@@ -55,6 +55,8 @@ define('API_METHOD_GET', 'GET');
55 55
 define('API_METHOD_POST', 'POST,PUT');
56 56
 define('API_METHOD_DELETE', 'POST,DELETE');
57 57
 
58
+define('API_LOG_PREFIX', 'API {action} - ');
59
+
58 60
 $API = [];
59 61
 $called_api = [];
60 62
 
@@ -97,9 +99,9 @@ function api_source()
97 99
 			return "Twidere";
98 100
 		}
99 101
 
100
-		Logger::log("Unrecognized user-agent ".$_SERVER['HTTP_USER_AGENT'], Logger::DEBUG);
102
+		Logger::info(API_LOG_PREFIX . 'Unrecognized user-agent', ['module' => 'api', 'action' => 'source', 'http_user_agent' => $_SERVER['HTTP_USER_AGENT']]);
101 103
 	} else {
102
-		Logger::log("Empty user-agent", Logger::DEBUG);
104
+		Logger::info(API_LOG_PREFIX . 'Empty user-agent', ['module' => 'api', 'action' => 'source']);
103 105
 	}
104 106
 
105 107
 	return "api";
@@ -181,7 +183,7 @@ function api_login(App $a)
181 183
 		var_dump($consumer, $token);
182 184
 		die();
183 185
 	} catch (Exception $e) {
184
-		Logger::log($e);
186
+		Logger::warning(API_LOG_PREFIX . 'error', ['module' => 'api', 'action' => 'login', 'exception' => $e->getMessage()]);
185 187
 	}
186 188
 
187 189
 	// workaround for HTTP-auth in CGI mode
@@ -195,7 +197,7 @@ function api_login(App $a)
195 197
 	}
196 198
 
197 199
 	if (empty($_SERVER['PHP_AUTH_USER'])) {
198
-		Logger::log('API_login: ' . print_r($_SERVER, true), Logger::DEBUG);
200
+		Logger::debug(API_LOG_PREFIX . 'failed', ['module' => 'api', 'action' => 'login', 'parameters' => $_SERVER]);
199 201
 		header('WWW-Authenticate: Basic realm="Friendica"');
200 202
 		throw new UnauthorizedException("This API requires login");
201 203
 	}
@@ -236,7 +238,7 @@ function api_login(App $a)
236 238
 	}
237 239
 
238 240
 	if (!DBA::isResult($record)) {
239
-		Logger::log('API_login failure: ' . print_r($_SERVER, true), Logger::DEBUG);
241
+		Logger::debug(API_LOG_PREFIX . 'failed', ['module' => 'api', 'action' => 'login', 'parameters' => $_SERVER]);
240 242
 		header('WWW-Authenticate: Basic realm="Friendica"');
241 243
 		//header('HTTP/1.0 401 Unauthorized');
242 244
 		//die('This api requires login');
@@ -309,33 +311,35 @@ function api_call(App $a)
309 311
 					api_login($a);
310 312
 				}
311 313
 
312
-				Logger::log('API call for ' . $a->user['username'] . ': ' . $a->query_string);
313
-				Logger::log('API parameters: ' . print_r($_REQUEST, true));
314
+				Logger::info(API_LOG_PREFIX . 'username {username}', ['module' => 'api', 'action' => 'call', 'username' => $a->user['username']]);
315
+				Logger::debug(API_LOG_PREFIX . 'parameters', ['module' => 'api', 'action' => 'call', 'parameters' => $_REQUEST]);
314 316
 
315 317
 				$stamp =  microtime(true);
316 318
 				$return = call_user_func($info['func'], $type);
317 319
 				$duration = (float) (microtime(true) - $stamp);
318
-				Logger::log("API call duration: " . round($duration, 2) . "\t" . $a->query_string, Logger::DEBUG);
320
+
321
+				Logger::info(API_LOG_PREFIX . 'username {username}', ['module' => 'api', 'action' => 'call', 'username' => $a->user['username'], 'duration' => round($duration, 2)]);
319 322
 
320 323
 				if (Config::get("system", "profiler")) {
321 324
 					$duration = microtime(true)-$a->performance["start"];
322 325
 
323 326
 					/// @TODO round() really everywhere?
324
-					Logger::log(
325
-						parse_url($a->query_string, PHP_URL_PATH) . ": " . sprintf(
326
-							"Database: %s/%s, Cache %s/%s, Network: %s, I/O: %s, Other: %s, Total: %s",
327
-							round($a->performance["database"] - $a->performance["database_write"], 3),
328
-							round($a->performance["database_write"], 3),
329
-							round($a->performance["cache"], 3),
330
-							round($a->performance["cache_write"], 3),
331
-							round($a->performance["network"], 2),
332
-							round($a->performance["file"], 2),
333
-							round($duration - ($a->performance["database"]
334
-								+ $a->performance["cache"] + $a->performance["cache_write"]
335
-								+ $a->performance["network"] + $a->performance["file"]), 2),
336
-							round($duration, 2)
337
-						),
338
-						Logger::DEBUG
327
+					Logger::debug(
328
+						API_LOG_PREFIX . 'performance',
329
+						[
330
+							'module' => 'api',
331
+							'action' => 'call',
332
+							'database_read' => round($a->performance["database"] - $a->performance["database_write"], 3),
333
+							'database_write' => round($a->performance["database_write"], 3),
334
+							'cache_read' => round($a->performance["cache"], 3),
335
+							'cache_write' => round($a->performance["cache_write"], 3),
336
+							'network_io' => round($a->performance["network"], 2),
337
+							'file_io' => round($a->performance["file"], 2),
338
+							'other_io' => round($duration - ($a->performance["database"]
339
+									+ $a->performance["cache"] + $a->performance["cache_write"]
340
+									+ $a->performance["network"] + $a->performance["file"]), 2),
341
+							'total' => round($duration, 2)
342
+						]
339 343
 					);
340 344
 
341 345
 					if (Config::get("rendertime", "callstack")) {
@@ -376,7 +380,7 @@ function api_call(App $a)
376 380
 								$o .= $func . ": " . $time . "\n";
377 381
 							}
378 382
 						}
379
-						Logger::log($o, Logger::DEBUG);
383
+						Logger::debug(API_LOG_PREFIX . $o, ['module' => 'api', 'action' => 'call']);
380 384
 					}
381 385
 				}
382 386
 
@@ -413,7 +417,7 @@ function api_call(App $a)
413 417
 			}
414 418
 		}
415 419
 
416
-		Logger::log('API call not implemented: ' . $a->query_string);
420
+		Logger::warning(API_LOG_PREFIX . 'not implemented', ['module' => 'api', 'action' => 'call']);
417 421
 		throw new NotImplementedException();
418 422
 	} catch (HTTPException $e) {
419 423
 		header("HTTP/1.1 {$e->httpcode} {$e->httpdesc}");
@@ -522,7 +526,7 @@ function api_get_user(App $a, $contact_id = null)
522 526
 	$extra_query = "";
523 527
 	$url = "";
524 528
 
525
-	Logger::log("api_get_user: Fetching user data for user ".$contact_id, Logger::DEBUG);
529
+	Logger::info(API_LOG_PREFIX . 'Fetching data for user {user}', ['module' => 'api', 'action' => 'get_user', 'user' => $contact_id]);
526 530
 
527 531
 	// Searching for contact URL
528 532
 	if (!is_null($contact_id) && (intval($contact_id) == 0)) {
@@ -606,7 +610,7 @@ function api_get_user(App $a, $contact_id = null)
606 610
 		}
607 611
 	}
608 612
 
609
-	Logger::log("api_get_user: user ".$user, Logger::DEBUG);
613
+	Logger::info(API_LOG_PREFIX . 'getting user {user}', ['module' => 'api', 'action' => 'get_user', 'user' => $user]);
610 614
 
611 615
 	if (!$user) {
612 616
 		if (api_user() === false) {
@@ -618,7 +622,7 @@ function api_get_user(App $a, $contact_id = null)
618 622
 		}
619 623
 	}
620 624
 
621
-	Logger::log('api_user: ' . $extra_query . ', user: ' . $user);
625
+	Logger::info(API_LOG_PREFIX . 'found user {user}', ['module' => 'api', 'action' => 'get_user', 'user' => $user, 'extra_query' => $extra_query]);
622 626
 
623 627
 	// user info
624 628
 	$uinfo = q(
@@ -1937,7 +1941,7 @@ function api_conversation_show($type)
1937 1941
 		$id = intval(defaults($a->argv, 4, 0));
1938 1942
 	}
1939 1943
 
1940
-	Logger::log('API: api_conversation_show: '.$id);
1944
+	Logger::info(API_LOG_PREFIX . '{subaction}', ['module' => 'api', 'action' => 'conversation', 'subaction' => 'show', 'id' => $id]);
1941 1945
 
1942 1946
 	// try to fetch the item for the local user - or the public item, if there is no local one
1943 1947
 	$item = Item::selectFirst(['parent-uri'], ['id' => $id]);
@@ -2331,7 +2335,7 @@ function api_favorites($type)
2331 2335
 
2332 2336
 	// in friendica starred item are private
2333 2337
 	// return favorites only for self
2334
-	Logger::log('api_favorites: self:' . $user_info['self']);
2338
+	Logger::info(API_LOG_PREFIX . 'for {self}', ['module' => 'api', 'action' => 'favorites', 'self' => $user_info['self']]);
2335 2339
 
2336 2340
 	if ($user_info['self'] == 0) {
2337 2341
 		$ret = [];
@@ -3694,7 +3698,7 @@ function api_friendships_destroy($type)
3694 3698
 	$contact_id = defaults($_REQUEST, 'user_id');
3695 3699
 
3696 3700
 	if (empty($contact_id)) {
3697
-		Logger::log("No user_id specified", Logger::DEBUG);
3701
+		Logger::notice(API_LOG_PREFIX . 'No user_id specified', ['module' => 'api', 'action' => 'friendships_destroy']);
3698 3702
 		throw new BadRequestException("no user_id specified");
3699 3703
 	}
3700 3704
 
@@ -3702,7 +3706,7 @@ function api_friendships_destroy($type)
3702 3706
 	$contact = DBA::selectFirst('contact', ['url'], ['id' => $contact_id, 'uid' => 0, 'self' => false]);
3703 3707
 
3704 3708
 	if(!DBA::isResult($contact)) {
3705
-		Logger::log("No contact found for ID" . $contact_id, Logger::DEBUG);
3709
+		Logger::notice(API_LOG_PREFIX . 'No contact found for ID {contact}', ['module' => 'api', 'action' => 'friendships_destroy', 'contact' => $contact_id]);
3706 3710
 		throw new NotFoundException("no contact found to given ID");
3707 3711
 	}
3708 3712
 
@@ -3714,12 +3718,12 @@ function api_friendships_destroy($type)
3714 3718
 	$contact = DBA::selectFirst('contact', [], $condition);
3715 3719
 
3716 3720
 	if (!DBA::isResult($contact)) {
3717
-		Logger::log("Not following Contact", Logger::DEBUG);
3721
+		Logger::notice(API_LOG_PREFIX . 'Not following contact', ['module' => 'api', 'action' => 'friendships_destroy']);
3718 3722
 		throw new NotFoundException("Not following Contact");
3719 3723
 	}
3720 3724
 
3721 3725
 	if (!in_array($contact['network'], Protocol::NATIVE_SUPPORT)) {
3722
-		Logger::log("Not supported", Logger::DEBUG);
3726
+		Logger::notice(API_LOG_PREFIX . 'Not supported for {network}', ['module' => 'api', 'action' => 'friendships_destroy', 'network' => $contact['network']]);
3723 3727
 		throw new ExpectationFailedException("Not supported");
3724 3728
 	}
3725 3729
 
@@ -3730,7 +3734,7 @@ function api_friendships_destroy($type)
3730 3734
 		Contact::terminateFriendship($owner, $contact, $dissolve);
3731 3735
 	}
3732 3736
 	else {
3733
-		Logger::log("No owner found", Logger::DEBUG);
3737
+		Logger::notice(API_LOG_PREFIX . 'No owner {uid} found', ['module' => 'api', 'action' => 'friendships_destroy', 'uid' => $uid]);
3734 3738
 		throw new NotFoundException("Error Processing Request");
3735 3739
 	}
3736 3740
 
@@ -4837,7 +4841,7 @@ function api_friendica_remoteauth()
4837 4841
 		'sec' => $sec, 'expire' => time() + 45];
4838 4842
 	DBA::insert('profile_check', $fields);
4839 4843
 
4840
-	Logger::log($contact['name'] . ' ' . $sec, Logger::DEBUG);
4844
+	Logger::info(API_LOG_PREFIX . 'for contact {contact}', ['module' => 'api', 'action' => 'friendica_remoteauth', 'contact' => $contact['name'], 'hey' => $sec]);
4841 4845
 	$dest = ($url ? '&destination_url=' . $url : '');
4842 4846
 
4843 4847
 	System::externalRedirect(
@@ -5086,7 +5090,7 @@ function api_in_reply_to($item)
5086 5090
 		// https://github.com/friendica/friendica/issues/1010
5087 5091
 		// This is a bugfix for that.
5088 5092
 		if (intval($in_reply_to['status_id']) == intval($item['id'])) {
5089
-			Logger::log('this message should never appear: id: '.$item['id'].' similar to reply-to: '.$in_reply_to['status_id'], Logger::DEBUG);
5093
+			Logger::warning(API_LOG_PREFIX . 'ID {id} is similar to reply-to {reply-to}', ['module' => 'api', 'action' => 'in_reply_to', 'id' => $item['id'], 'reply-to' => $in_reply_to['status_id']]);
5090 5094
 			$in_reply_to['status_id'] = null;
5091 5095
 			$in_reply_to['user_id'] = null;
5092 5096
 			$in_reply_to['status_id_str'] = null;

+ 4
- 2
index.php View File

@@ -5,6 +5,7 @@
5 5
  */
6 6
 
7 7
 use Friendica\App;
8
+use Friendica\Util\LoggerFactory;
8 9
 
9 10
 if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
10 11
 	die('Vendor path not found. Please execute "bin/composer.phar --no-dev install" on the command line in the web root.');
@@ -12,9 +13,10 @@ if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
12 13
 
13 14
 require __DIR__ . '/vendor/autoload.php';
14 15
 
16
+$logger = LoggerFactory::create('index');
17
+
15 18
 // We assume that the index.php is called by a frontend process
16 19
 // The value is set to "true" by default in App
17
-$a = new App(__DIR__, false);
20
+$a = new App(__DIR__, $logger, false);
18 21
 
19 22
 $a->runFrontend();
20
-

+ 1
- 1
mod/acl.php View File

@@ -34,7 +34,7 @@ function acl_content(App $a)
34 34
 		$search = $_REQUEST['query'];
35 35
 	}
36 36
 
37
-	Logger::log("Searching for ".$search." - type ".$type." conversation ".$conv_id, Logger::DEBUG);
37
+	Logger::info('ACL {action} - {subaction}', ['module' => 'acl', 'action' => 'content', 'subaction' => 'search', 'search' => $search, 'type' => $type, 'conversation' => $conv_id]);
38 38
 
39 39
 	if ($search != '') {
40 40
 		$sql_extra = "AND `name` LIKE '%%" . DBA::escape($search) . "%%'";

+ 30
- 3
src/App.php View File

@@ -8,8 +8,10 @@ use Detection\MobileDetect;
8 8
 use DOMDocument;
9 9
 use DOMXPath;
10 10
 use Exception;
11
+use Friendica\Core\Logger;
11 12
 use Friendica\Database\DBA;
12 13
 use Friendica\Network\HTTPException\InternalServerErrorException;
14
+use Psr\Log\LoggerInterface;
13 15
 
14 16
 /**
15 17
  *
@@ -106,6 +108,11 @@ class App
106 108
 	 */
107 109
 	public $mobileDetect;
108 110
 
111
+	/**
112
+	 * @var LoggerInterface The current logger of this App
113
+	 */
114
+	private $logger;
115
+
109 116
 	/**
110 117
 	 * Register a stylesheet file path to be included in the <head> tag of every page.
111 118
 	 * Inclusion is done in App->initHead().
@@ -146,13 +153,16 @@ class App
146 153
 	/**
147 154
 	 * @brief App constructor.
148 155
 	 *
149
-	 * @param string $basePath  Path to the app base folder
150
-	 * @param bool   $isBackend Whether it is used for backend or frontend (Default true=backend)
156
+	 * @param string           $basePath  Path to the app base folder
157
+	 * @param LoggerInterface  $logger    Logger of this application
158
+	 * @param bool             $isBackend Whether it is used for backend or frontend (Default true=backend)
151 159
 	 *
152 160
 	 * @throws Exception if the Basepath is not usable
153 161
 	 */
154
-	public function __construct($basePath, $isBackend = true)
162
+	public function __construct($basePath, LoggerInterface $logger, $isBackend = true)
155 163
 	{
164
+		$this->logger = $logger;
165
+
156 166
 		if (!static::isDirectoryUsable($basePath, false)) {
157 167
 			throw new Exception('Basepath ' . $basePath . ' isn\'t usable.');
158 168
 		}
@@ -301,6 +311,21 @@ class App
301 311
 		return $this->mode;
302 312
 	}
303 313
 
314
+	/**
315
+	 * Returns the Logger of the Application
316
+	 *
317
+	 * @return LoggerInterface The Logger
318
+	 * @throws InternalServerErrorException when the logger isn't created
319
+	 */
320
+	public function getLogger()
321
+	{
322
+		if (empty($this->logger)) {
323
+			throw new InternalServerErrorException('Logger of the Application is not defined');
324
+		}
325
+
326
+		return $this->logger;
327
+	}
328
+
304 329
 	/**
305 330
 	 * Reloads the whole app instance
306 331
 	 */
@@ -328,6 +353,8 @@ class App
328 353
 		Core\L10n::init();
329 354
 
330 355
 		$this->process_id = Core\System::processID('log');
356
+
357
+		Core\Logger::setLogger($this->logger);
331 358
 	}
332 359
 
333 360
 	/**

+ 4
- 1
src/BaseObject.php View File

@@ -6,6 +6,8 @@ namespace Friendica;
6 6
 
7 7
 require_once 'boot.php';
8 8
 
9
+use Friendica\Util\LoggerFactory;
10
+
9 11
 /**
10 12
  * Basic object
11 13
  *
@@ -25,7 +27,8 @@ class BaseObject
25 27
 	public static function getApp()
26 28
 	{
27 29
 		if (empty(self::$app)) {
28
-			self::$app = new App(dirname(__DIR__));
30
+			$logger = $logger = LoggerFactory::create('app');
31
+			self::$app = new App(dirname(__DIR__), $logger);
29 32
 		}
30 33
 
31 34
 		return self::$app;

+ 5
- 6
src/Core/Addon.php View File

@@ -4,9 +4,7 @@
4 4
  */
5 5
 namespace Friendica\Core;
6 6
 
7
-use Friendica\App;
8 7
 use Friendica\BaseObject;
9
-use Friendica\Core\Logger;
10 8
 use Friendica\Database\DBA;
11 9
 
12 10
 /**
@@ -76,7 +74,7 @@ class Addon extends BaseObject
76 74
 	 */
77 75
 	public static function uninstall($addon)
78 76
 	{
79
-		Logger::log("Addons: uninstalling " . $addon);
77
+		Logger::notice("Addon {addon}: {action}", ['action' => 'uninstall', 'addon' => $addon]);
80 78
 		DBA::delete('addon', ['name' => $addon]);
81 79
 
82 80
 		@include_once('addon/' . $addon . '/' . $addon . '.php');
@@ -101,7 +99,7 @@ class Addon extends BaseObject
101 99
 		if (!file_exists('addon/' . $addon . '/' . $addon . '.php')) {
102 100
 			return false;
103 101
 		}
104
-		Logger::log("Addons: installing " . $addon);
102
+		Logger::notice("Addon {addon}: {action}", ['action' => 'install', 'addon' => $addon]);
105 103
 		$t = @filemtime('addon/' . $addon . '/' . $addon . '.php');
106 104
 		@include_once('addon/' . $addon . '/' . $addon . '.php');
107 105
 		if (function_exists($addon . '_install')) {
@@ -126,7 +124,7 @@ class Addon extends BaseObject
126 124
 			}
127 125
 			return true;
128 126
 		} else {
129
-			Logger::log("Addons: FAILED installing " . $addon);
127
+			Logger::error("Addon {addon}: {action} failed", ['action' => 'uninstall', 'addon' => $addon]);
130 128
 			return false;
131 129
 		}
132 130
 	}
@@ -156,7 +154,8 @@ class Addon extends BaseObject
156 154
 						$t = @filemtime($fname);
157 155
 						foreach ($installed as $i) {
158 156
 							if (($i['name'] == $addon) && ($i['timestamp'] != $t)) {
159
-								Logger::log('Reloading addon: ' . $i['name']);
157
+
158
+								Logger::notice("Addon {addon}: {action}", ['action' => 'reload', 'addon' => $i['name']]);
160 159
 								@include_once($fname);
161 160
 
162 161
 								if (function_exists($addon . '_uninstall')) {

+ 320
- 98
src/Core/Logger.php View File

@@ -5,82 +5,335 @@
5 5
 namespace Friendica\Core;
6 6
 
7 7
 use Friendica\BaseObject;
8
-use Friendica\Core\Config;
9
-use Friendica\Util\DateTimeFormat;
10
-use ReflectionClass;
8
+use Friendica\Network\HTTPException\InternalServerErrorException;
9
+use Friendica\Util\LoggerFactory;
10
+use Psr\Log\LoggerInterface;
11
+use Psr\Log\LogLevel;
11 12
 
12 13
 /**
13 14
  * @brief Logger functions
14 15
  */
15 16
 class Logger extends BaseObject
16 17
 {
17
-    // Log levels:
18
-    const WARNING = 0;
19
-    const INFO = 1;
20
-    const TRACE = 2;
21
-    const DEBUG = 3;
22
-    const DATA = 4;
23
-    const ALL = 5;
24
-
25
-    public static $levels = [
26
-        self::WARNING => 'Warning',
27
-        self::INFO => 'Info',
28
-        self::TRACE => 'Trace',
29
-        self::DEBUG => 'Debug',
30
-        self::DATA => 'Data',
31
-        self::ALL => 'All',
32
-    ];
18
+	/**
19
+	 * @see Logger::error()
20
+	 */
21
+	const WARNING = LogLevel::ERROR;
22
+	/**
23
+	 * @see Logger::warning()
24
+	 */
25
+	const INFO = LogLevel::WARNING;
26
+	/**
27
+	 * @see Logger::notice()
28
+	 */
29
+	const TRACE = LogLevel::NOTICE;
30
+	/**
31
+	 * @see Logger::info()
32
+	 */
33
+	const DEBUG = LogLevel::INFO;
34
+	/**
35
+	 * @see Logger::debug()
36
+	 */
37
+	const DATA = LogLevel::DEBUG;
38
+	/**
39
+	 * @see Logger::debug()
40
+	 */
41
+	const ALL = LogLevel::DEBUG;
42
+
43
+	/**
44
+	 * @var array the legacy loglevels
45
+	 * @deprecated 2019.03 use PSR-3 loglevels
46
+	 * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel
47
+	 *
48
+	 */
49
+	public static $levels = [
50
+		self::WARNING => 'Warning',
51
+		self::INFO => 'Info',
52
+		self::TRACE => 'Trace',
53
+		self::DEBUG => 'Debug',
54
+		self::DATA => 'Data',
55
+		self::ALL => 'All',
56
+	];
57
+
58
+	/**
59
+	 * @var LoggerInterface A PSR-3 compliant logger instance
60
+	 */
61
+	private static $logger;
62
+
63
+	/**
64
+	 * @var LoggerInterface A PSR-3 compliant logger instance for developing only
65
+	 */
66
+	private static $devLogger;
67
+
68
+	/**
69
+	 * Sets the default logging handler for Friendica.
70
+	 * @todo Can be combined with other handlers too if necessary, could be configurable.
71
+	 *
72
+	 * @param LoggerInterface $logger The Logger instance of this Application
73
+	 *
74
+	 * @throws InternalServerErrorException if the logger factory is incompatible to this logger
75
+	 */
76
+	public static function setLogger($logger)
77
+	{
78
+		$debugging = Config::get('system', 'debugging');
79
+		$logfile = Config::get('system', 'logfile');
80
+		$loglevel = Config::get('system', 'loglevel');
81
+
82
+		if (!$debugging || !$logfile) {
83
+			return;
84
+		}
85
+
86
+		if (is_int($loglevel)) {
87
+			$loglevel = self::mapLegacyConfigDebugLevel($loglevel);
88
+		}
89
+
90
+		LoggerFactory::addStreamHandler($logger, $logfile, $loglevel);
91
+
92
+		self::$logger = $logger;
93
+
94
+		$logfile = Config::get('system', 'dlogfile');
95
+
96
+		if (!$logfile) {
97
+			return;
98
+		}
99
+
100
+		$developIp = Config::get('system', 'dlogip');
101
+
102
+		self::$devLogger = LoggerFactory::createDev('develop', $developIp);
103
+		LoggerFactory::addStreamHandler(self::$devLogger, $logfile, LogLevel::DEBUG);
104
+	}
105
+
106
+	/**
107
+	 * Mapping a legacy level to the PSR-3 compliant levels
108
+	 * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel
109
+	 *
110
+	 * @param int $level the level to be mapped
111
+	 *
112
+	 * @return string the PSR-3 compliant level
113
+	 */
114
+	private static function mapLegacyConfigDebugLevel($level)
115
+	{
116
+		switch ($level) {
117
+			// legacy WARNING
118
+			case 0:
119
+				return LogLevel::ERROR;
120
+			// legacy INFO
121
+			case 1:
122
+				return LogLevel::WARNING;
123
+			// legacy TRACE
124
+			case 2:
125
+				return LogLevel::NOTICE;
126
+			// legacy DEBUG
127
+			case 3:
128
+				return LogLevel::INFO;
129
+			// legacy DATA
130
+			case 4:
131
+				return LogLevel::DEBUG;
132
+			// legacy ALL
133
+			case 5:
134
+				return LogLevel::DEBUG;
135
+			// default if nothing set
136
+			default:
137
+				return LogLevel::NOTICE;
138
+		}
139
+	}
140
+
141
+	/**
142
+	 * System is unusable.
143
+	 * @see LoggerInterface::emergency()
144
+	 *
145
+	 * @param string $message
146
+	 * @param array  $context
147
+	 *
148
+	 * @return void
149
+	 *
150
+	 */
151
+	public static function emergency($message, $context = [])
152
+	{
153
+		if (!isset(self::$logger)) {
154
+			return;
155
+		}
156
+
157
+		$stamp1 = microtime(true);
158
+		self::$logger->emergency($message, $context);
159
+		self::getApp()->saveTimestamp($stamp1, 'file');
160
+	}
161
+
162
+	/**
163
+	 * Action must be taken immediately.
164
+	 * @see LoggerInterface::alert()
165
+	 *
166
+	 * Example: Entire website down, database unavailable, etc. This should
167
+	 * trigger the SMS alerts and wake you up.
168
+	 *
169
+	 * @param string $message
170
+	 * @param array  $context
171
+	 *
172
+	 * @return void
173
+	 *
174
+	 */
175
+	public static function alert($message, $context = [])
176
+	{
177
+		if (!isset(self::$logger)) {
178
+			return;
179
+		}
180
+
181
+		$stamp1 = microtime(true);
182
+		self::$logger->alert($message, $context);
183
+		self::getApp()->saveTimestamp($stamp1, 'file');
184
+	}
185
+
186
+	/**
187
+	 * Critical conditions.
188
+	 * @see LoggerInterface::critical()
189
+	 *
190
+	 * Example: Application component unavailable, unexpected exception.
191
+	 *
192
+	 * @param string $message
193
+	 * @param array  $context
194
+	 *
195
+	 * @return void
196
+	 *
197
+	 */
198
+	public static function critical($message, $context = [])
199
+	{
200
+		if (!isset(self::$logger)) {
201
+			return;
202
+		}
203
+
204
+		$stamp1 = microtime(true);
205
+		self::$logger->critical($message, $context);
206
+		self::getApp()->saveTimestamp($stamp1, 'file');
207
+	}
208
+
209
+	/**
210
+	 * Runtime errors that do not require immediate action but should typically
211
+	 * be logged and monitored.
212
+	 * @see LoggerInterface::error()
213
+	 *
214
+	 * @param string $message
215
+	 * @param array  $context
216
+	 *
217
+	 * @return void
218
+	 *
219
+	 */
220
+	public static function error($message, $context = [])
221
+	{
222
+		if (!isset(self::$logger)) {
223
+			echo "not set!?\n";
224
+			return;
225
+		}
226
+
227
+		$stamp1 = microtime(true);
228
+		self::$logger->error($message, $context);
229
+		self::getApp()->saveTimestamp($stamp1, 'file');
230
+	}
231
+
232
+	/**
233
+	 * Exceptional occurrences that are not errors.
234
+	 * @see LoggerInterface::warning()
235
+	 *
236
+	 * Example: Use of deprecated APIs, poor use of an API, undesirable things
237
+	 * that are not necessarily wrong.
238
+	 *
239
+	 * @param string $message
240
+	 * @param array  $context
241
+	 *
242
+	 * @return void
243
+	 *
244
+	 */
245
+	public static function warning($message, $context = [])
246
+	{
247
+		if (!isset(self::$logger)) {
248
+			return;
249
+		}
250
+
251
+		$stamp1 = microtime(true);
252
+		self::$logger->warning($message, $context);
253
+		self::getApp()->saveTimestamp($stamp1, 'file');
254
+	}
255
+
256
+	/**
257
+	 * Normal but significant events.
258
+	 * @see LoggerInterface::notice()
259
+	 *
260
+	 * @param string $message
261
+	 * @param array  $context
262
+	 *
263
+	 * @return void
264
+	 *
265
+	 */
266
+	public static function notice($message, $context = [])
267
+	{
268
+		if (!isset(self::$logger)) {
269
+			return;
270
+		}
271
+
272
+		$stamp1 = microtime(true);
273
+		self::$logger->notice($message, $context);
274
+		self::getApp()->saveTimestamp($stamp1, 'file');
275
+	}
276
+
277
+	/**
278
+	 * Interesting events.
279
+	 * @see LoggerInterface::info()
280
+	 *
281
+	 * Example: User logs in, SQL logs.
282
+	 *
283
+	 * @param string $message
284
+	 * @param array  $context
285
+	 *
286
+	 * @return void
287
+	 *
288
+	 */
289
+	public static function info($message, $context = [])
290
+	{
291
+		if (!isset(self::$logger)) {
292
+			return;
293
+		}
294
+
295
+		$stamp1 = microtime(true);
296
+		self::$logger->info($message, $context);
297
+		self::getApp()->saveTimestamp($stamp1, 'file');
298
+	}
299
+
300
+	/**
301
+	 * Detailed debug information.
302
+	 * @see LoggerInterface::debug()
303
+	 *
304
+	 * @param string $message
305
+	 * @param array  $context
306
+	 *
307
+	 * @return void
308
+	 */
309
+	public static function debug($message, $context = [])
310
+	{
311
+		if (!isset(self::$logger)) {
312
+			return;
313
+		}
314
+
315
+		$stamp1 = microtime(true);
316
+		self::$logger->debug($message, $context);
317
+		self::getApp()->saveTimestamp($stamp1, 'file');
318
+	}
33 319
 
34 320
     /**
35 321
      * @brief Logs the given message at the given log level
36 322
      *
37 323
      * @param string $msg
38 324
      * @param int $level
325
+	 *
326
+	 * @deprecated since 2019.03 Use Logger::debug() Logger::info() , ... instead
39 327
      */
40
-    public static function log($msg, $level = self::INFO)
328
+    public static function log($msg, $level = LogLevel::NOTICE)
41 329
     {
42
-        $a = self::getApp();
43
-
44
-        $debugging = Config::get('system', 'debugging');
45
-        $logfile   = Config::get('system', 'logfile');
46
-        $loglevel = intval(Config::get('system', 'loglevel'));
47
-
48
-        if (
49
-            !$debugging
50
-            || !$logfile
51
-            || $level > $loglevel
52
-        ) {
53
-            return;
54
-        }
55
-
56
-        $processId = session_id();
57
-
58
-        if ($processId == '')
59
-        {
60
-            $processId = $a->process_id;
61
-        }
62
-
63
-        $callers = debug_backtrace();
64
-
65
-        if (count($callers) > 1) {
66
-            $function = $callers[1]['function'];
67
-        } else {
68
-            $function = '';
69
-        }
70
-
71
-        $logline = sprintf("%s@%s\t[%s]:%s:%s:%s\t%s\n",
72
-                DateTimeFormat::utcNow(DateTimeFormat::ATOM),
73
-                $processId,
74
-                self::$levels[$level],
75
-                basename($callers[0]['file']),
76
-                $callers[0]['line'],
77
-                $function,
78
-                $msg
79
-            );
330
+		if (!isset(self::$logger)) {
331
+			return;
332
+		}
80 333
 
81 334
         $stamp1 = microtime(true);
82
-        @file_put_contents($logfile, $logline, FILE_APPEND);
83
-        $a->saveTimestamp($stamp1, "file");
335
+		self::$logger->log($level, $msg);
336
+        self::getApp()->saveTimestamp($stamp1, "file");
84 337
     }
85 338
 
86 339
     /**
@@ -90,47 +343,16 @@ class Logger extends BaseObject
90 343
      * personally without background noise
91 344
      *
92 345
      * @param string $msg
346
+	 * @param string $level
93 347
      */
94
-    public static function devLog($msg)
348
+    public static function devLog($msg, $level = LogLevel::DEBUG)
95 349
     {
96
-        $a = self::getApp();
97
-
98
-        $logfile = Config::get('system', 'dlogfile');
99
-
100
-        if (!$logfile) {
101
-            return;
102
-        }
103
-
104
-        $dlogip = Config::get('system', 'dlogip');
105
-
106
-        if (!is_null($dlogip) && $_SERVER['REMOTE_ADDR'] != $dlogip)
107
-        {
108
-            return;
109
-        }
110
-
111
-        $processId = session_id();
112
-
113
-        if ($processId == '')
114
-        {
115
-            $processId = $a->process_id;
116
-        }
117
-
118
-        if (!is_string($msg)) {
119
-        	$msg = var_export($msg, true);
120
-        }
121
-
122
-        $callers = debug_backtrace();
123
-        $logline = sprintf("%s@\t%s:\t%s:\t%s\t%s\t%s\n",
124
-                DateTimeFormat::utcNow(),
125
-                $processId,
126
-                basename($callers[0]['file']),
127
-                $callers[0]['line'],
128
-                $callers[1]['function'],
129
-                $msg
130
-            );
350
+		if (!isset(self::$logger)) {
351
+			return;
352
+		}
131 353
 
132 354
         $stamp1 = microtime(true);
133
-        @file_put_contents($logfile, $logline, FILE_APPEND);
134
-        $a->saveTimestamp($stamp1, "file");
355
+        self::$devLogger->log($level, $msg);
356
+        self::getApp()->saveTimestamp($stamp1, "file");
135 357
     }
136 358
 }

+ 50
- 0
src/Util/Logger/FriendicaDevelopHandler.php View File

@@ -0,0 +1,50 @@
1
+<?php
2
+
3
+namespace Friendica\Util\Logger;
4
+
5
+use Monolog\Handler;
6
+use Monolog\Logger;
7
+
8
+/**
9
+ * Simple handler for Friendica developers to use for deeper logging
10
+ *
11
+ * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
12
+ * you'll use Logger::develop() for the duration of your work, and you clean it up when you're done before submitting your PR.
13
+ */
14
+class FriendicaDevelopHandler extends Handler\AbstractHandler
15
+{
16
+	/**
17
+	 * @var string The IP of the developer who wants to debug
18
+	 */
19
+	private $developerIp;
20
+
21
+	/**
22
+	 * @param string $developerIp  The IP of the developer who wants to debug
23
+	 * @param int    $level        The minimum logging level at which this handler will be triggered
24
+	 * @param bool   $bubble       Whether the messages that are handled can bubble up the stack or not
25
+	 */
26
+	public function __construct($developerIp, $level = Logger::DEBUG, $bubble = true)
27
+	{
28
+		parent::__construct($level, $bubble);
29
+
30
+		$this->developerIp = $developerIp;
31
+	}
32
+
33
+	/**
34
+	 * {@inheritdoc}
35
+	 */
36
+	public function handle(array $record)
37
+	{
38
+		if (!$this->isHandling($record)) {
39
+			return false;
40
+		}
41
+
42
+		/// Just in case the remote IP is the same as the developer IP log the output
43
+		if (!is_null($this->developerIp) && $_SERVER['REMOTE_ADDR'] != $this->developerIp)
44
+		{
45
+			return false;
46
+		}
47
+
48
+		return false === $this->bubble;
49
+	}
50
+}

+ 116
- 0
src/Util/LoggerFactory.php View File

@@ -0,0 +1,116 @@
1
+<?php
2
+
3
+namespace Friendica\Util;
4
+
5
+use Friendica\Network\HTTPException\InternalServerErrorException;
6
+use Friendica\Util\Logger\FriendicaDevelopHandler;
7
+use Monolog;
8
+use Psr\Log\LoggerInterface;
9
+use Psr\Log\LogLevel;
10
+
11
+/**
12
+ * A logger factory
13
+ *
14
+ * Currently only Monolog is supported
15
+ */
16
+class LoggerFactory
17
+{
18
+	/**
19
+	 * Creates a new PSR-3 compliant logger instances
20
+	 *
21
+	 * @param string $channel The channel of the logger instance
22
+	 *
23
+	 * @return LoggerInterface The PSR-3 compliant logger instance
24
+	 */
25
+	public static function create($channel)
26
+	{
27
+		$logger = new Monolog\Logger($channel);
28
+		$logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
29
+		$logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
30
+
31
+		// Add more information in case of a warning and more
32
+		$logger->pushProcessor(new Monolog\Processor\IntrospectionProcessor(LogLevel::WARNING, [], 1));
33
+
34
+		return $logger;
35
+	}
36
+
37
+	/**
38
+	 * Creates a new PSR-3 compliant develop logger
39
+	 *
40
+	 * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
41
+	 * you'll use this logger instance for the duration of your work.
42
+	 *
43
+	 * It should never get filled during normal usage of Friendica
44
+	 *
45
+	 * @param string $channel      The channel of the logger instance
46
+	 * @param string $developerIp  The IP of the developer who wants to use the logger
47
+	 *
48
+	 * @return LoggerInterface The PSR-3 compliant logger instance
49
+	 */
50
+	public static function createDev($channel, $developerIp)
51
+	{
52
+		$logger = new Monolog\Logger($channel);
53
+		$logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
54
+		$logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
55
+
56
+		$logger->pushProcessor(new Monolog\Processor\IntrospectionProcessor(Loglevel::DEBUG, [], 1));
57
+
58
+		$logger->pushHandler(new FriendicaDevelopHandler($developerIp));
59
+
60
+		return $logger;
61
+	}
62
+
63
+	/**
64
+	 * Adding a handler to a given logger instance
65
+	 *
66
+	 * @param LoggerInterface $logger  The logger instance
67
+	 * @param mixed           $stream  The stream which handles the logger output
68
+	 * @param string          $level   The level, for which this handler at least should handle logging
69
+	 *
70
+	 * @return void
71
+	 *
72
+	 * @throws InternalServerErrorException if the logger is incompatible to the logger factory
73
+	 * @throws \Exception in case of general failures
74
+	 */
75
+	public static function addStreamHandler($logger, $stream, $level = LogLevel::NOTICE)
76
+	{
77
+		if ($logger instanceof Monolog\Logger) {
78
+			$fileHandler = new Monolog\Handler\StreamHandler($stream, Monolog\Logger::toMonologLevel($level));
79
+
80
+			$formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
81
+			$fileHandler->setFormatter($formatter);
82
+
83
+			$logger->pushHandler($fileHandler);
84
+		} else {
85
+			throw new InternalServerErrorException('Logger instance incompatible for MonologFactory');
86
+		}
87
+	}
88
+
89
+	/**
90
+	 * This method enables the test mode of a given logger
91
+	 *
92
+	 * @param LoggerInterface $logger The logger
93
+	 *
94
+	 * @return Monolog\Handler\TestHandler the Handling for tests
95
+	 *
96
+	 * @throws InternalServerErrorException if the logger is incompatible to the logger factory
97
+	 */
98
+	public static function enableTest($logger)
99
+	{
100
+		if ($logger instanceof Monolog\Logger) {
101
+			// disable every handler so far
102
+			$logger->pushHandler(new Monolog\Handler\NullHandler());
103
+
104
+			// enable the test handler
105
+			$fileHandler = new Monolog\Handler\TestHandler();
106
+			$formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
107
+			$fileHandler->setFormatter($formatter);
108
+
109
+			$logger->pushHandler($fileHandler);
110
+
111
+			return $fileHandler;
112
+		} else {
113
+			throw new InternalServerErrorException('Logger instance incompatible for MonologFactory');
114
+		}
115
+	}
116
+}

+ 8
- 0
tests/include/ApiTest.php View File

@@ -11,6 +11,8 @@ use Friendica\Core\PConfig;
11 11
 use Friendica\Core\Protocol;
12 12
 use Friendica\Core\System;
13 13
 use Friendica\Network\HTTPException;
14
+use Friendica\Util\LoggerFactory;
15
+use Monolog\Handler\TestHandler;
14 16
 
15 17
 require_once __DIR__ . '/../../include/api.php';
16 18
 
@@ -22,6 +24,11 @@ require_once __DIR__ . '/../../include/api.php';
22 24
  */
23 25
 class ApiTest extends DatabaseTest
24 26
 {
27
+	/**
28
+	 * @var TestHandler Can handle log-outputs
29
+	 */
30
+	protected $logOutput;
31
+
25 32
 	/**
26 33
 	 * Create variables used by tests.
27 34
 	 */
@@ -30,6 +37,7 @@ class ApiTest extends DatabaseTest
30 37
 		parent::setUp();
31 38
 
32 39
 		$this->app = BaseObject::getApp();
40
+		$this->logOutput = LoggerFactory::enableTest($this->app->getLogger());
33 41
 
34 42
 		// User data that the test database is populated with
35 43
 		$this->selfUser = [

+ 4
- 1
tests/src/BaseObjectTest.php View File

@@ -7,6 +7,7 @@ namespace Friendica\Test;
7 7
 
8 8
 use Friendica\App;
9 9
 use Friendica\BaseObject;
10
+use Friendica\Util\LoggerFactory;
10 11
 use PHPUnit\Framework\TestCase;
11 12
 
12 13
 /**
@@ -38,7 +39,9 @@ class BaseObjectTest extends TestCase
38 39
 	 */
39 40
 	public function testSetApp()
40 41
 	{
41
-		$app = new App(__DIR__ . '/../../');
42
+		$logger = $logger = LoggerFactory::create('test');
43
+		$app = new App(__DIR__ . '/../../', $logger);
44
+		LoggerFactory::enableTest($logger);
42 45
 		$this->assertNull($this->baseObject->setApp($app));
43 46
 		$this->assertEquals($app, $this->baseObject->getApp());
44 47
 	}

+ 3
- 3
update.php View File

@@ -332,8 +332,8 @@ function update_1298()
332 332
 					$fail++;
333 333
 				} else {
334 334
 					DBA::update('profile', [$translateKey => $key], ['id' => $data['id']]);
335
-					logger::log('Updated contact ' . $data['id'] . " to $translateKey " . $key .
336
-						' (was: ' . $data[$translateKey] . ')');
335
+					Logger::notice('Updated contact', ['action' => 'update', 'contact' => $data['id'], "$translateKey" => $key,
336
+						'was' => $data[$translateKey]]);
337 337
 					Worker::add(PRIORITY_LOW, 'ProfileUpdate', $data['id']);		
338 338
 					Contact::updateSelfFromUserID($data['id']);
339 339
 					GContact::updateForUser($data['id']);
@@ -342,7 +342,7 @@ function update_1298()
342 342
 			}
343 343
 		}
344 344
 
345
-		Logger::log($translateKey . " fix completed. Success: $success. Fail: $fail");	
345
+		Logger::notice($translateKey . " fix completed", ['action' => 'update', 'translateKey' => $translateKey, 'Success' => $success, 'Fail' => $fail ]);
346 346
 	}
347 347
 	return Update::SUCCESS;
348 348
 }

Loading…
Cancel
Save