From 3e18b561159613b668e867213b6eb378686be209 Mon Sep 17 00:00:00 2001 From: Benjamin Friedman Date: Tue, 7 Nov 2017 14:05:57 -0800 Subject: [PATCH 1/7] Adds ParseLogs for checking server logs --- src/Parse/ParseLogs.php | 90 ++++++++++++++++++++++++++++++ tests/Parse/ParseLogsTest.php | 102 ++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 src/Parse/ParseLogs.php create mode 100644 tests/Parse/ParseLogsTest.php diff --git a/src/Parse/ParseLogs.php b/src/Parse/ParseLogs.php new file mode 100644 index 00000000..fbd802ff --- /dev/null +++ b/src/Parse/ParseLogs.php @@ -0,0 +1,90 @@ + + * @package Parse + */ +class ParseLogs +{ + + /** + * Requests script logs from the server + * + * @param string $level Level of logs to return (info/error), default is info + * @param int $size Number of rows to return, default is 100 + * @param null $from Earliest logs to return from, defaults to 1 week ago + * @param null $until Latest logs to return from, defaults to current time + * @param null $order Order to sort logs by (asc/desc), defaults to descending + * @return array + */ + public static function getScriptLogs( + $level = 'info', // info/error + $size = 100, + $from = null, + $until = null, + $order = null + ) + { + $data = [ + 'level' => $level, + 'size' => $size, + ]; + + if(isset($from) && $from instanceof \DateTime) { + $data['from'] = ParseClient::getProperDateFormat($from); + } + + if(isset($until) && $until instanceof \DateTime) { + $data['until'] = ParseClient::getProperDateFormat($until); + } + + if(isset($order)) { + $data['order'] = $order; + } + + $response = ParseClient::_request( + 'GET', + 'scriptlog', + null, + $data, + true + ); + + return $response; + } + + /** + * Returns info logs + * + * @param int $size Lines to return, 100 by default + * @param null $from Earliest logs to return from, default is 1 week ago + * @param null $until Latest logs to return from, defaults to current time + * @param null $order Order to sort logs by (asc/desc), defaults to descending + * @return array + */ + public static function getInfoLogs($size = 100, $from = null, $until = null, $order = null) + { + return self::getScriptLogs('info', $size, $from, $until, $order); + } + + /** + * Returns error logs + * + * @param int $size Lines to return, 100 by default + * @param null $from Earliest logs to return from, default is 1 week ago + * @param null $until Latest logs to return from, defaults to current time + * @param null $order Order to sort logs by (asc/desc), defaults to descending + * @return array + */ + public static function getErrorLogs($size = 100, $from = null, $until = null, $order = null) + { + return self::getScriptLogs('error', $size, $from, $until, $order); + } +} \ No newline at end of file diff --git a/tests/Parse/ParseLogsTest.php b/tests/Parse/ParseLogsTest.php new file mode 100644 index 00000000..c248f370 --- /dev/null +++ b/tests/Parse/ParseLogsTest.php @@ -0,0 +1,102 @@ +assertNotEmpty($logs); + } + + /** + * @group parse-logs-tests + */ + public function testGettingOneLog() + { + $logs = ParseLogs::getInfoLogs(1); + $this->assertEquals(1, count($logs)); + $this->assertEquals($logs[0]['method'], 'GET'); + $this->assertTrue(isset($logs[0]['url'])); + } + + /** + * @group parse-logs-tests + */ + public function testGettingErrorLogs() + { + // Generate an error by requesting a non-existant password reset, to verify we have at least 1 line in our logs + try { + ParseUser::requestPasswordReset('not_a_real_email'); + } catch (ParseException $pe) { + // do nothing + } + + $logs = ParseLogs::getErrorLogs(1); + $this->assertEquals(1, count($logs)); + $this->assertEquals($logs[0]['code'], 205); + $this->assertEquals($logs[0]['message'], 'No user found with email not_a_real_email.'); + $this->assertEquals($logs[0]['level'], 'error'); + $this->assertTrue(isset($logs[0]['timestamp'])); + } + + /** + * @group parse-logs-tests + */ + public function testFrom() + { + // test getting logs from 4 hours in the future + $date = new \DateTime(); + $date->add(new \DateInterval('PT4H')); + $logs = ParseLogs::getInfoLogs(1, $date); + $this->assertEquals(0, count($logs)); + } + + /** + * @group parse-logs-tests + */ + public function testUntil() + { + // test getting logs from 1950 years in the past (not likely...) + $date = new \DateTime(); + $date->sub(new \DateInterval('P1950Y')); + $logs = ParseLogs::getInfoLogs(1, null, $date); + $this->assertEquals(0, count($logs)); + } + + /** + * @group parse-logs-tests + */ + public function testOrderAscending() + { + $logs = ParseLogs::getInfoLogs(15, null, null, 'asc'); + $this->assertEquals(15, count($logs)); + + $timestamp1 = $logs[0]['timestamp']; + $timestamp2 = $logs[count($logs)-1]['timestamp']; + + $timestamp1 = preg_replace('/Z$/', '', $timestamp1); + $timestamp2 = preg_replace('/Z$/', '', $timestamp2); + + // get first 2 entries + $entryDate1 = \DateTime::createFromFormat('Y-m-d\TH:i:s.u', $timestamp1); + $entryDate2 = \DateTime::createFromFormat('Y-m-d\TH:i:s.u', $timestamp2); + + $this->assertTrue($entryDate1 < $entryDate2); + } +} \ No newline at end of file From 79dd41d6f13c69c0d75917e8c30778cdd6d0c935 Mon Sep 17 00:00:00 2001 From: Benjamin Friedman Date: Tue, 7 Nov 2017 15:18:00 -0800 Subject: [PATCH 2/7] lint --- src/Parse/ParseLogs.php | 13 ++++++------- tests/Parse/ParseLogsTest.php | 3 +-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Parse/ParseLogs.php b/src/Parse/ParseLogs.php index fbd802ff..99ae6bcb 100644 --- a/src/Parse/ParseLogs.php +++ b/src/Parse/ParseLogs.php @@ -25,27 +25,26 @@ class ParseLogs * @return array */ public static function getScriptLogs( - $level = 'info', // info/error + $level = 'info', $size = 100, $from = null, $until = null, $order = null - ) - { + ) { $data = [ 'level' => $level, 'size' => $size, ]; - if(isset($from) && $from instanceof \DateTime) { + if (isset($from) && $from instanceof \DateTime) { $data['from'] = ParseClient::getProperDateFormat($from); } - if(isset($until) && $until instanceof \DateTime) { + if (isset($until) && $until instanceof \DateTime) { $data['until'] = ParseClient::getProperDateFormat($until); } - if(isset($order)) { + if (isset($order)) { $data['order'] = $order; } @@ -87,4 +86,4 @@ public static function getErrorLogs($size = 100, $from = null, $until = null, $o { return self::getScriptLogs('error', $size, $from, $until, $order); } -} \ No newline at end of file +} diff --git a/tests/Parse/ParseLogsTest.php b/tests/Parse/ParseLogsTest.php index c248f370..afc77e81 100644 --- a/tests/Parse/ParseLogsTest.php +++ b/tests/Parse/ParseLogsTest.php @@ -8,7 +8,6 @@ namespace Parse\Test; - use Parse\ParseException; use Parse\ParseLogs; use Parse\ParseUser; @@ -99,4 +98,4 @@ public function testOrderAscending() $this->assertTrue($entryDate1 < $entryDate2); } -} \ No newline at end of file +} From 693e17123fce5984f9518adb21086f9e537d4bb6 Mon Sep 17 00:00:00 2001 From: Benjamin Friedman Date: Tue, 7 Nov 2017 16:25:46 -0800 Subject: [PATCH 3/7] updated tests to provide 'clean' log entries to work on, prevents logs from stacking in 'verbose' --- tests/Parse/ParseLogsTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/Parse/ParseLogsTest.php b/tests/Parse/ParseLogsTest.php index afc77e81..8f2a774b 100644 --- a/tests/Parse/ParseLogsTest.php +++ b/tests/Parse/ParseLogsTest.php @@ -10,17 +10,36 @@ use Parse\ParseException; use Parse\ParseLogs; +use Parse\ParseObject; use Parse\ParseUser; class ParseLogsTest extends \PHPUnit_Framework_TestCase { + public static function setUpBeforeClass() + { + // setup 15 log entries that we can reference + $objs = []; + while(count($objs) < 15) { + $obj = new ParseObject('TestObject'); + $objs[] = $obj; + } + ParseObject::saveAll($objs); + } + + public static function tearDownAfterClass() + { + Helper::clearClass('TestObject'); + } + /** * @group parse-logs-tests */ public function testGettingDefaultLogs() { + $logs = ParseLogs::getScriptLogs('info', 1); $this->assertNotEmpty($logs); + $this->assertEquals(1, count($logs)); } /** From de671d6e74c86ad16e0a782dc10a7541d0906ea8 Mon Sep 17 00:00:00 2001 From: Benjamin Friedman Date: Tue, 7 Nov 2017 16:26:20 -0800 Subject: [PATCH 4/7] fixed small issue in stream client with passing 'GET' params --- src/Parse/HttpClients/ParseStreamHttpClient.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Parse/HttpClients/ParseStreamHttpClient.php b/src/Parse/HttpClients/ParseStreamHttpClient.php index 468a0079..50fd2a8f 100644 --- a/src/Parse/HttpClients/ParseStreamHttpClient.php +++ b/src/Parse/HttpClients/ParseStreamHttpClient.php @@ -209,15 +209,7 @@ public function send($url, $method = 'GET', $data = array()) if ($method == "GET") { // handle GET $query = http_build_query($data, null, '&'); - - if (!defined('HHVM_VERSION')) { - $this->options['http']['content'] = $query; - } else { - // HHVM doesn't reapply 'content' to the url - // have to do it ourselves - $url.='?'.$query; - } - + $url.='?'.$query; $this->addRequestHeader('Content-type', 'application/x-www-form-urlencoded'); } elseif ($method == "POST") { // handle POST From 05ce8918e5dee5c2ece47bb6fbc9a2e9bbdac617 Mon Sep 17 00:00:00 2001 From: Benjamin Friedman Date: Tue, 7 Nov 2017 16:28:10 -0800 Subject: [PATCH 5/7] consolidated 2 -> 1 line --- src/Parse/HttpClients/ParseStreamHttpClient.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Parse/HttpClients/ParseStreamHttpClient.php b/src/Parse/HttpClients/ParseStreamHttpClient.php index 50fd2a8f..61d033c2 100644 --- a/src/Parse/HttpClients/ParseStreamHttpClient.php +++ b/src/Parse/HttpClients/ParseStreamHttpClient.php @@ -208,8 +208,7 @@ public function send($url, $method = 'GET', $data = array()) if (isset($data) && $data != "{}") { if ($method == "GET") { // handle GET - $query = http_build_query($data, null, '&'); - $url.='?'.$query; + $url.='?'.http_build_query($data, null, '&'); $this->addRequestHeader('Content-type', 'application/x-www-form-urlencoded'); } elseif ($method == "POST") { // handle POST From 72a973de3f45c3c441b338ea86efb9d65887474f Mon Sep 17 00:00:00 2001 From: Benjamin Friedman Date: Tue, 7 Nov 2017 16:31:57 -0800 Subject: [PATCH 6/7] lint --- tests/Parse/ParseLogsTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Parse/ParseLogsTest.php b/tests/Parse/ParseLogsTest.php index 8f2a774b..eb1b5aad 100644 --- a/tests/Parse/ParseLogsTest.php +++ b/tests/Parse/ParseLogsTest.php @@ -19,7 +19,7 @@ public static function setUpBeforeClass() { // setup 15 log entries that we can reference $objs = []; - while(count($objs) < 15) { + while (count($objs) < 15) { $obj = new ParseObject('TestObject'); $objs[] = $obj; } @@ -36,7 +36,6 @@ public static function tearDownAfterClass() */ public function testGettingDefaultLogs() { - $logs = ParseLogs::getScriptLogs('info', 1); $this->assertNotEmpty($logs); $this->assertEquals(1, count($logs)); From 1388995dba5f88f596e3c97c78da483fbd7d2c9a Mon Sep 17 00:00:00 2001 From: Benjamin Friedman Date: Tue, 7 Nov 2017 22:35:48 -0800 Subject: [PATCH 7/7] updated README --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index bf3365d4..83ff9164 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ from your PHP app or script. Designed to work with the self-hosted Parse Server - [Features](#features) - [Schema](#schema) - [Purge](#purge) + - [Logs](#logs) - [Contributing / Testing](#contributing--testing) ## Installation @@ -214,6 +215,7 @@ use Parse\ParseCloud; use Parse\ParseClient; use Parse\ParsePushStatus; use Parse\ParseServerInfo; +use Parse\ParseLogs; ``` ### Parse Objects @@ -575,6 +577,25 @@ Only do this if you _really_ need to delete all objects from a class, such as wh $mySchema->purge(); ``` +### Logs +`ParseLogs` allows info and error logs to be retrieved from the server as JSON. +Using the same approach as that which is utilized in the [dashboard](https://github.com/parse-community/parse-dashboard) you can view your logs with specific ranges in time, type and order. +Note that this requires the correct masterKey to be set during your initialization for access. +```php +// get last 100 info logs, sorted in descending order +$logs = ParseLogs::getInfoLogs(); + +// get last 100 info logs, sorted in descending order +$logs = ParseLogs::getErrorLogs(); + +// logs can be retrieved with further specificity +// get 10 logs from a date up to a date in ascending order +$logs = ParseLogs::getInfoLogs(10, $fromDate, $untilDate, 'asc'); + +// above can be done for 'getErrorLogs' as well +``` + + ## Contributing / Testing See [CONTRIBUTING](CONTRIBUTING.md) for information on testing and contributing to