Skip to content

Instantly share code, notes, and snippets.

@rjz
Created March 17, 2012 05:38
Show Gist options
  • Save rjz/2055426 to your computer and use it in GitHub Desktop.
Save rjz/2055426 to your computer and use it in GitHub Desktop.
Heroku log parser
<?php
if (!class_exists('HerokuParser')):
/**
* A super-quick parser for Heroku logfiles
*/
class HerokuParser {
/**
* Filter a string against the specified criteria
*
* @param string the input string
* @param string (optional) the source of the message (e.g., "app")
* @param string (optional) the process (e.g., "web.1")
* @return string the line, or blank if the filter failed
*/
protected function filter ($line, $source = '', $process = '') {
$source_test = $process_test = '.*?';
if ($source) {
$source_test = "$source";
}
if ($process) {
$process_test = "$process\.?[0-9]*";
}
$test = sprintf('#\s%s\[%s\]\:\s#', $source_test, $process_test);
if (preg_match($test, $line)) {
return $line;
}
return '';
}
/**
* Parse the contents of a single line
*
* Returns an associative array describing the contents of the line:
*
* - timestamp: when the message was logged
* - source: the source of the message
* - process: the source process logging the message
* - message: the message
*
* @param string the input string
* @return array
*/
protected function parse ($line) {
// timestamp source[process]: message
$components = explode(' ', $line);
$timestamp = array_shift($components);
$dyno = explode('[', array_shift($components));
$message = implode(' ', $components);
return array(
'timestamp' => strtotime($timestamp),
'source' => $dyno[0],
'process' => substr($dyno[1], 0, -2),
'message' => trim($message)
);
}
/**
* Parse a Heroku log file
*
* @param string the source of the message (e.g. "app")
* @param string the process ID (e.g., "web.1")
* @return an array of entries matching the filter criteria
*/
public function run ($logfile, $source = '', $process = '') {
$entries = array();
if (!($fp = fopen($logfile, 'r'))) {
die('failed opening logfile:' . $fp);
}
while(($line = fgets($fp)) !== false) {
// compare the current line against any source/process filters
if ($line = $this->filter($line, $source, $process)) {
// parse coarse
$line = $this->parse($line);
if ($line['message']) {
$entries[] = $line;
}
}
}
return $entries;
fclose($fp);
}
}
endif; // class_exists
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment