Skip to content

Commit f72cc45

Browse files
authored
Adds ParseLogs (#370)
* Adds ParseLogs for checking server logs * lint * updated tests to provide 'clean' log entries to work on, prevents logs from stacking in 'verbose' * fixed small issue in stream client with passing 'GET' params * consolidated 2 -> 1 line * lint * updated README
1 parent bbcec8d commit f72cc45

File tree

4 files changed

+230
-10
lines changed

4 files changed

+230
-10
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ from your PHP app or script. Designed to work with the self-hosted Parse Server
3636
- [Features](#features)
3737
- [Schema](#schema)
3838
- [Purge](#purge)
39+
- [Logs](#logs)
3940
- [Contributing / Testing](#contributing--testing)
4041

4142
## Installation
@@ -214,6 +215,7 @@ use Parse\ParseCloud;
214215
use Parse\ParseClient;
215216
use Parse\ParsePushStatus;
216217
use Parse\ParseServerInfo;
218+
use Parse\ParseLogs;
217219
```
218220

219221
### Parse Objects
@@ -575,6 +577,25 @@ Only do this if you _really_ need to delete all objects from a class, such as wh
575577
$mySchema->purge();
576578
```
577579

580+
### Logs
581+
`ParseLogs` allows info and error logs to be retrieved from the server as JSON.
582+
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.
583+
Note that this requires the correct masterKey to be set during your initialization for access.
584+
```php
585+
// get last 100 info logs, sorted in descending order
586+
$logs = ParseLogs::getInfoLogs();
587+
588+
// get last 100 info logs, sorted in descending order
589+
$logs = ParseLogs::getErrorLogs();
590+
591+
// logs can be retrieved with further specificity
592+
// get 10 logs from a date up to a date in ascending order
593+
$logs = ParseLogs::getInfoLogs(10, $fromDate, $untilDate, 'asc');
594+
595+
// above can be done for 'getErrorLogs' as well
596+
```
597+
598+
578599
## Contributing / Testing
579600

580601
See [CONTRIBUTING](CONTRIBUTING.md) for information on testing and contributing to

src/Parse/HttpClients/ParseStreamHttpClient.php

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,7 @@ public function send($url, $method = 'GET', $data = array())
208208
if (isset($data) && $data != "{}") {
209209
if ($method == "GET") {
210210
// handle GET
211-
$query = http_build_query($data, null, '&');
212-
213-
if (!defined('HHVM_VERSION')) {
214-
$this->options['http']['content'] = $query;
215-
} else {
216-
// HHVM doesn't reapply 'content' to the url
217-
// have to do it ourselves
218-
$url.='?'.$query;
219-
}
220-
211+
$url.='?'.http_build_query($data, null, '&');
221212
$this->addRequestHeader('Content-type', 'application/x-www-form-urlencoded');
222213
} elseif ($method == "POST") {
223214
// handle POST

src/Parse/ParseLogs.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
/**
3+
* Class ParseLogs | Parse/ParseLogs.php
4+
*/
5+
6+
namespace Parse;
7+
8+
/**
9+
* Class ParseLogs - Allows access to server side parse script logs
10+
*
11+
* @author Ben Friedman <friedman.benjamin@gmail.com>
12+
* @package Parse
13+
*/
14+
class ParseLogs
15+
{
16+
17+
/**
18+
* Requests script logs from the server
19+
*
20+
* @param string $level Level of logs to return (info/error), default is info
21+
* @param int $size Number of rows to return, default is 100
22+
* @param null $from Earliest logs to return from, defaults to 1 week ago
23+
* @param null $until Latest logs to return from, defaults to current time
24+
* @param null $order Order to sort logs by (asc/desc), defaults to descending
25+
* @return array
26+
*/
27+
public static function getScriptLogs(
28+
$level = 'info',
29+
$size = 100,
30+
$from = null,
31+
$until = null,
32+
$order = null
33+
) {
34+
$data = [
35+
'level' => $level,
36+
'size' => $size,
37+
];
38+
39+
if (isset($from) && $from instanceof \DateTime) {
40+
$data['from'] = ParseClient::getProperDateFormat($from);
41+
}
42+
43+
if (isset($until) && $until instanceof \DateTime) {
44+
$data['until'] = ParseClient::getProperDateFormat($until);
45+
}
46+
47+
if (isset($order)) {
48+
$data['order'] = $order;
49+
}
50+
51+
$response = ParseClient::_request(
52+
'GET',
53+
'scriptlog',
54+
null,
55+
$data,
56+
true
57+
);
58+
59+
return $response;
60+
}
61+
62+
/**
63+
* Returns info logs
64+
*
65+
* @param int $size Lines to return, 100 by default
66+
* @param null $from Earliest logs to return from, default is 1 week ago
67+
* @param null $until Latest logs to return from, defaults to current time
68+
* @param null $order Order to sort logs by (asc/desc), defaults to descending
69+
* @return array
70+
*/
71+
public static function getInfoLogs($size = 100, $from = null, $until = null, $order = null)
72+
{
73+
return self::getScriptLogs('info', $size, $from, $until, $order);
74+
}
75+
76+
/**
77+
* Returns error logs
78+
*
79+
* @param int $size Lines to return, 100 by default
80+
* @param null $from Earliest logs to return from, default is 1 week ago
81+
* @param null $until Latest logs to return from, defaults to current time
82+
* @param null $order Order to sort logs by (asc/desc), defaults to descending
83+
* @return array
84+
*/
85+
public static function getErrorLogs($size = 100, $from = null, $until = null, $order = null)
86+
{
87+
return self::getScriptLogs('error', $size, $from, $until, $order);
88+
}
89+
}

tests/Parse/ParseLogsTest.php

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
/**
3+
* Created by PhpStorm.
4+
* User: Bfriedman
5+
* Date: 11/7/17
6+
* Time: 12:40
7+
*/
8+
9+
namespace Parse\Test;
10+
11+
use Parse\ParseException;
12+
use Parse\ParseLogs;
13+
use Parse\ParseObject;
14+
use Parse\ParseUser;
15+
16+
class ParseLogsTest extends \PHPUnit_Framework_TestCase
17+
{
18+
public static function setUpBeforeClass()
19+
{
20+
// setup 15 log entries that we can reference
21+
$objs = [];
22+
while (count($objs) < 15) {
23+
$obj = new ParseObject('TestObject');
24+
$objs[] = $obj;
25+
}
26+
ParseObject::saveAll($objs);
27+
}
28+
29+
public static function tearDownAfterClass()
30+
{
31+
Helper::clearClass('TestObject');
32+
}
33+
34+
/**
35+
* @group parse-logs-tests
36+
*/
37+
public function testGettingDefaultLogs()
38+
{
39+
$logs = ParseLogs::getScriptLogs('info', 1);
40+
$this->assertNotEmpty($logs);
41+
$this->assertEquals(1, count($logs));
42+
}
43+
44+
/**
45+
* @group parse-logs-tests
46+
*/
47+
public function testGettingOneLog()
48+
{
49+
$logs = ParseLogs::getInfoLogs(1);
50+
$this->assertEquals(1, count($logs));
51+
$this->assertEquals($logs[0]['method'], 'GET');
52+
$this->assertTrue(isset($logs[0]['url']));
53+
}
54+
55+
/**
56+
* @group parse-logs-tests
57+
*/
58+
public function testGettingErrorLogs()
59+
{
60+
// Generate an error by requesting a non-existant password reset, to verify we have at least 1 line in our logs
61+
try {
62+
ParseUser::requestPasswordReset('not_a_real_email');
63+
} catch (ParseException $pe) {
64+
// do nothing
65+
}
66+
67+
$logs = ParseLogs::getErrorLogs(1);
68+
$this->assertEquals(1, count($logs));
69+
$this->assertEquals($logs[0]['code'], 205);
70+
$this->assertEquals($logs[0]['message'], 'No user found with email not_a_real_email.');
71+
$this->assertEquals($logs[0]['level'], 'error');
72+
$this->assertTrue(isset($logs[0]['timestamp']));
73+
}
74+
75+
/**
76+
* @group parse-logs-tests
77+
*/
78+
public function testFrom()
79+
{
80+
// test getting logs from 4 hours in the future
81+
$date = new \DateTime();
82+
$date->add(new \DateInterval('PT4H'));
83+
$logs = ParseLogs::getInfoLogs(1, $date);
84+
$this->assertEquals(0, count($logs));
85+
}
86+
87+
/**
88+
* @group parse-logs-tests
89+
*/
90+
public function testUntil()
91+
{
92+
// test getting logs from 1950 years in the past (not likely...)
93+
$date = new \DateTime();
94+
$date->sub(new \DateInterval('P1950Y'));
95+
$logs = ParseLogs::getInfoLogs(1, null, $date);
96+
$this->assertEquals(0, count($logs));
97+
}
98+
99+
/**
100+
* @group parse-logs-tests
101+
*/
102+
public function testOrderAscending()
103+
{
104+
$logs = ParseLogs::getInfoLogs(15, null, null, 'asc');
105+
$this->assertEquals(15, count($logs));
106+
107+
$timestamp1 = $logs[0]['timestamp'];
108+
$timestamp2 = $logs[count($logs)-1]['timestamp'];
109+
110+
$timestamp1 = preg_replace('/Z$/', '', $timestamp1);
111+
$timestamp2 = preg_replace('/Z$/', '', $timestamp2);
112+
113+
// get first 2 entries
114+
$entryDate1 = \DateTime::createFromFormat('Y-m-d\TH:i:s.u', $timestamp1);
115+
$entryDate2 = \DateTime::createFromFormat('Y-m-d\TH:i:s.u', $timestamp2);
116+
117+
$this->assertTrue($entryDate1 < $entryDate2);
118+
}
119+
}

0 commit comments

Comments
 (0)