clock-work
This commit is contained in:
36
vendor/itsgoingd/clockwork/Clockwork/Helpers/Concerns/ResolvesViewName.php
vendored
Normal file
36
vendor/itsgoingd/clockwork/Clockwork/Helpers/Concerns/ResolvesViewName.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php namespace Clockwork\Helpers\Concerns;
|
||||
|
||||
use Clockwork\Helpers\StackFrame;
|
||||
|
||||
// Replaces the first stack frame rendering a Laravel view with a duplicate with a resolved original view path (instead
|
||||
// of the compiled view path)
|
||||
trait ResolvesViewName
|
||||
{
|
||||
public function resolveViewName()
|
||||
{
|
||||
$viewFrame = $this->first(function ($frame) {
|
||||
return $frame->shortPath ? preg_match('#^/storage/framework/views/[a-z0-9]+\.php$#', $frame->shortPath) : false;
|
||||
});
|
||||
|
||||
if (! $viewFrame) return $this;
|
||||
|
||||
$renderFrame = $this->first(function ($frame) {
|
||||
return $frame->call == 'Illuminate\View\View->getContents()'
|
||||
&& $frame->object instanceof \Illuminate\View\View;
|
||||
});
|
||||
|
||||
if (! $renderFrame) return $this;
|
||||
|
||||
$resolvedViewFrame = new StackFrame(
|
||||
[ 'file' => $renderFrame->object->getPath(), 'line' => $viewFrame->line ],
|
||||
$this->basePath,
|
||||
$this->vendorPath
|
||||
);
|
||||
|
||||
return $this->copy(array_merge(
|
||||
array_slice($this->frames, 0, array_search($viewFrame, $this->frames)),
|
||||
[ $resolvedViewFrame ],
|
||||
array_slice($this->frames, array_search($viewFrame, $this->frames) + 2)
|
||||
));
|
||||
}
|
||||
}
|
139
vendor/itsgoingd/clockwork/Clockwork/Helpers/Serializer.php
vendored
Normal file
139
vendor/itsgoingd/clockwork/Clockwork/Helpers/Serializer.php
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php namespace Clockwork\Helpers;
|
||||
|
||||
// Prepares various types of data for serialization
|
||||
class Serializer
|
||||
{
|
||||
// Serialized objects cache by object hash
|
||||
protected $cache = [];
|
||||
|
||||
// Options for the current instance
|
||||
protected $options = [];
|
||||
|
||||
// Default options for new instances
|
||||
protected static $defaults = [
|
||||
'blackbox' => [
|
||||
\Illuminate\Container\Container::class,
|
||||
\Illuminate\Foundation\Application::class,
|
||||
\Laravel\Lumen\Application::class
|
||||
],
|
||||
'limit' => 10,
|
||||
'toArray' => false,
|
||||
'toString' => false,
|
||||
'debugInfo' => true,
|
||||
'jsonSerialize' => false,
|
||||
'traces' => true,
|
||||
'tracesFilter' => null,
|
||||
'tracesSkip' => null,
|
||||
'tracesLimit' => null
|
||||
];
|
||||
|
||||
// Create a new instance optionally with options overriding defaults
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->options = $options + static::$defaults;
|
||||
}
|
||||
|
||||
// Set default options for all new instances
|
||||
public static function defaults(array $defaults)
|
||||
{
|
||||
static::$defaults = $defaults + static::$defaults;
|
||||
}
|
||||
|
||||
// Prepares the passed data to be ready for serialization, takes any kind of data to normalize as the first
|
||||
// argument, other arguments are used internally in recursion
|
||||
public function normalize($data, $context = null, $limit = null)
|
||||
{
|
||||
if ($context === null) $context = [ 'references' => [] ];
|
||||
if ($limit === null) $limit = $this->options['limit'];
|
||||
|
||||
if (is_array($data)) {
|
||||
if ($limit === 0) return [ '__type__' => 'array', '__omitted__' => 'limit' ];
|
||||
|
||||
return [ '__type__' => 'array' ] + $this->normalizeEach($data, $context, $limit - 1);
|
||||
} elseif (is_object($data)) {
|
||||
if ($data instanceof \Closure) return [ '__type__' => 'anonymous function' ];
|
||||
|
||||
$className = get_class($data);
|
||||
$objectHash = spl_object_hash($data);
|
||||
|
||||
if ($limit === 0) return [ '__class__' => $className, '__omitted__' => 'limit' ];
|
||||
|
||||
if (isset($context['references'][$objectHash])) return [ '__type__' => 'recursion' ];
|
||||
|
||||
$context['references'][$objectHash] = true;
|
||||
|
||||
if (isset($this->cache[$objectHash])) return $this->cache[$objectHash];
|
||||
|
||||
if ($this->options['blackbox'] && in_array($className, $this->options['blackbox'])) {
|
||||
return $this->cache[$objectHash] = [ '__class__' => $className, '__omitted__' => 'blackbox' ];
|
||||
} elseif ($this->options['toString'] && method_exists($data, '__toString')) {
|
||||
return $this->cache[$objectHash] = (string) $data;
|
||||
}
|
||||
|
||||
if ($this->options['debugInfo'] && method_exists($data, '__debugInfo')) {
|
||||
$data = (array) $data->__debugInfo();
|
||||
} elseif ($this->options['jsonSerialize'] && method_exists($data, 'jsonSerialize')) {
|
||||
$data = (array) $data->jsonSerialize();
|
||||
} elseif ($this->options['toArray'] && method_exists($data, 'toArray')) {
|
||||
$data = (array) $data->toArray();
|
||||
} else {
|
||||
$data = (array) $data;
|
||||
}
|
||||
|
||||
$data = array_combine(
|
||||
array_map(function ($key) {
|
||||
// replace null-byte prefixes of protected and private properties used by php with * (protected)
|
||||
// and ~ (private)
|
||||
return preg_replace('/^\0.+?\0/', '~', str_replace("\0*\0", '*', $key));
|
||||
}, array_keys($data)),
|
||||
$this->normalizeEach($data, $context, $limit - 1)
|
||||
);
|
||||
|
||||
return $this->cache[$objectHash] = [ '__class__' => $className ] + $data;
|
||||
} elseif (is_resource($data)) {
|
||||
return [ '__type__' => 'resource' ];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Normalize each member of an array (doesn't add metadata for top level)
|
||||
public function normalizeEach($data, $context = null, $limit = null) {
|
||||
return array_map(function ($item) use ($context, $limit) {
|
||||
return $this->normalize($item, $context, $limit);
|
||||
}, $data);
|
||||
}
|
||||
|
||||
// Normalize a stack trace instance
|
||||
public function trace(StackTrace $trace)
|
||||
{
|
||||
if (! $this->options['traces']) return null;
|
||||
|
||||
if ($this->options['tracesFilter']) $trace = $trace->filter($this->options['tracesFilter']);
|
||||
if ($this->options['tracesSkip']) $trace = $trace->skip($this->options['tracesSkip']);
|
||||
if ($this->options['tracesLimit']) $trace = $trace->limit($this->options['tracesLimit']);
|
||||
|
||||
return array_map(function ($frame) {
|
||||
return [
|
||||
'call' => $frame->call,
|
||||
'file' => $frame->file,
|
||||
'line' => $frame->line,
|
||||
'isVendor' => (bool) $frame->vendor
|
||||
];
|
||||
}, $trace->frames());
|
||||
}
|
||||
|
||||
// Normalize an exception instance
|
||||
public function exception(/* Throwable */ $exception)
|
||||
{
|
||||
return [
|
||||
'type' => get_class($exception),
|
||||
'message' => $exception->getMessage(),
|
||||
'code' => $exception->getCode(),
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
'trace' => (new Serializer([ 'tracesLimit' => false ]))->trace(StackTrace::from($exception->getTrace())),
|
||||
'previous' => $exception->getPrevious() ? $this->exception($exception->getPrevious()) : null
|
||||
];
|
||||
}
|
||||
}
|
45
vendor/itsgoingd/clockwork/Clockwork/Helpers/ServerTiming.php
vendored
Normal file
45
vendor/itsgoingd/clockwork/Clockwork/Helpers/ServerTiming.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php namespace Clockwork\Helpers;
|
||||
|
||||
use Clockwork\Request\Request;
|
||||
|
||||
// Generates Server-Timing header value
|
||||
class ServerTiming
|
||||
{
|
||||
// Performance metrics to include
|
||||
protected $metrics = [];
|
||||
|
||||
// Add a performance metric
|
||||
public function add($metric, $value, $description)
|
||||
{
|
||||
$this->metrics[] = [ 'metric' => $metric, 'value' => $value, 'description' => $description ];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Generate the header value
|
||||
public function value()
|
||||
{
|
||||
return implode(', ', array_map(function ($metric) {
|
||||
return "{$metric['metric']}; dur={$metric['value']}; desc=\"{$metric['description']}\"";
|
||||
}, $this->metrics));
|
||||
}
|
||||
|
||||
// Create a new instance from a Clockwork request
|
||||
public static function fromRequest(Request $request, $eventsCount = 10)
|
||||
{
|
||||
$header = new static;
|
||||
|
||||
$header->add('app', $request->getResponseDuration(), 'Application');
|
||||
|
||||
if ($request->getDatabaseDuration()) {
|
||||
$header->add('db', $request->getDatabaseDuration(), 'Database');
|
||||
}
|
||||
|
||||
// add timeline events limited to a set number so the header doesn't get too large
|
||||
foreach (array_slice($request->timeline()->events, 0, $eventsCount) as $i => $event) {
|
||||
$header->add("timeline-event-{$i}", $event->duration(), $event->description);
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
}
|
148
vendor/itsgoingd/clockwork/Clockwork/Helpers/StackFilter.php
vendored
Normal file
148
vendor/itsgoingd/clockwork/Clockwork/Helpers/StackFilter.php
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php namespace Clockwork\Helpers;
|
||||
|
||||
// Filter stack traces
|
||||
class StackFilter
|
||||
{
|
||||
protected $classes = [];
|
||||
protected $notClasses = [];
|
||||
|
||||
protected $files = [];
|
||||
protected $notFiles = [];
|
||||
|
||||
protected $functions = [];
|
||||
protected $notFunctions = [];
|
||||
|
||||
protected $namespaces = [];
|
||||
protected $notNamespaces = [];
|
||||
|
||||
protected $vendors = [];
|
||||
protected $notVendors = [];
|
||||
|
||||
public static function make()
|
||||
{
|
||||
return new static;
|
||||
}
|
||||
|
||||
public function isClass($classes)
|
||||
{
|
||||
$this->classes = array_merge($this->classes, is_array($classes) ? $classes : [ $classes ]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isNotClass($classes)
|
||||
{
|
||||
$this->notClasses = array_merge($this->notClasses, is_array($classes) ? $classes : [ $classes ]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isFile($files)
|
||||
{
|
||||
$this->files = array_merge($this->files, is_array($files) ? $files : [ $files ]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isNotFile($files)
|
||||
{
|
||||
$this->notFiles = array_merge($this->notFiles, is_array($files) ? $files : [ $files ]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isFunction($functions)
|
||||
{
|
||||
$this->functions = array_merge($this->functions, is_array($functions) ? $functions : [ $functions ]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isNotFunction($functions)
|
||||
{
|
||||
$this->notFunctions = array_merge($this->notFunctions, is_array($functions) ? $functions : [ $functions ]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isNamespace($namespaces)
|
||||
{
|
||||
$this->namespaces = array_merge($this->namespaces, is_array($namespaces) ? $namespaces : [ $namespaces ]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isNotNamespace($namespaces)
|
||||
{
|
||||
$this->notNamespaces = array_merge($this->notNamespaces, is_array($namespaces) ? $namespaces : [ $namespaces ]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isVendor($vendors)
|
||||
{
|
||||
$this->vendors = array_merge($this->vendors, is_array($vendors) ? $vendors : [ $vendors ]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isNotVendor($vendors)
|
||||
{
|
||||
$this->notVendors = array_merge($this->notVendors, is_array($vendors) ? $vendors : [ $vendors ]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Apply the filter to a stack frame
|
||||
public function filter(StackFrame $frame)
|
||||
{
|
||||
return $this->matchesClass($frame)
|
||||
&& $this->matchesFile($frame)
|
||||
&& $this->matchesFunction($frame)
|
||||
&& $this->matchesNamespace($frame)
|
||||
&& $this->matchesVendor($frame);
|
||||
}
|
||||
|
||||
// Return a closure calling this filter
|
||||
public function closure()
|
||||
{
|
||||
return function ($frame) { return $this->filter($frame); };
|
||||
}
|
||||
|
||||
protected function matchesClass(StackFrame $frame)
|
||||
{
|
||||
if (count($this->classes) && ! in_array($frame->class, $this->classes)) return false;
|
||||
if (count($this->notClasses) && in_array($frame->class, $this->notClasses)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function matchesFile(StackFrame $frame)
|
||||
{
|
||||
if (count($this->files) && ! in_array($frame->file, $this->files)) return false;
|
||||
if (count($this->notFiles) && in_array($frame->file, $this->notFiles)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function matchesFunction(StackFrame $frame)
|
||||
{
|
||||
if (count($this->functions) && ! in_array($frame->function, $this->functions)) return false;
|
||||
if (count($this->notFunctions) && in_array($frame->function, $this->notFunctions)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function matchesNamespace(StackFrame $frame)
|
||||
{
|
||||
foreach ($this->notNamespaces as $namespace) {
|
||||
if ($frame->class !== null && strpos($frame->class, "{$namespace}\\") !== false) return false;
|
||||
}
|
||||
|
||||
if (! count($this->namespaces)) return true;
|
||||
|
||||
foreach ($this->namespaces as $namespace) {
|
||||
if ($frame->class !== null && strpos($frame->class, "{$namespace}\\") !== false) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function matchesVendor(StackFrame $frame)
|
||||
{
|
||||
if (count($this->vendors) && ! in_array($frame->vendor, $this->vendors)) return false;
|
||||
if (count($this->notVendors) && in_array($frame->vendor, $this->notVendors)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
38
vendor/itsgoingd/clockwork/Clockwork/Helpers/StackFrame.php
vendored
Normal file
38
vendor/itsgoingd/clockwork/Clockwork/Helpers/StackFrame.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php namespace Clockwork\Helpers;
|
||||
|
||||
// A single frame of a stack trace
|
||||
class StackFrame
|
||||
{
|
||||
public $call;
|
||||
public $function;
|
||||
public $line;
|
||||
public $file;
|
||||
public $class;
|
||||
public $object;
|
||||
public $type;
|
||||
public $args = [];
|
||||
public $shortPath;
|
||||
public $vendor;
|
||||
|
||||
public function __construct(array $data = [], $basePath = '', $vendorPath = '')
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
$this->$key = $value;
|
||||
}
|
||||
|
||||
$this->call = $this->formatCall();
|
||||
|
||||
$this->shortPath = $this->file ? str_replace($basePath, '', $this->file) : null;
|
||||
$this->vendor = ($this->file && strpos($this->file, $vendorPath) === 0)
|
||||
? explode(DIRECTORY_SEPARATOR, str_replace($vendorPath, '', $this->file))[0] : null;
|
||||
}
|
||||
|
||||
protected function formatCall()
|
||||
{
|
||||
if ($this->class) {
|
||||
return "{$this->class}{$this->type}{$this->function}()";
|
||||
} else {
|
||||
return "{$this->function}()";
|
||||
}
|
||||
}
|
||||
}
|
127
vendor/itsgoingd/clockwork/Clockwork/Helpers/StackTrace.php
vendored
Normal file
127
vendor/itsgoingd/clockwork/Clockwork/Helpers/StackTrace.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php namespace Clockwork\Helpers;
|
||||
|
||||
// A stack trace
|
||||
class StackTrace
|
||||
{
|
||||
use Concerns\ResolvesViewName;
|
||||
|
||||
protected $frames;
|
||||
|
||||
protected $basePath;
|
||||
protected $vendorPath;
|
||||
|
||||
// Capture a new stack trace, accepts an array of options, "arguments" to include arguments in the trace and "limit"
|
||||
// to limit the trace length
|
||||
public static function get($options = [])
|
||||
{
|
||||
$backtraceOptions = isset($options['arguments'])
|
||||
? DEBUG_BACKTRACE_PROVIDE_OBJECT : DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
$limit = isset($options['limit']) ? $options['limit'] : 0;
|
||||
|
||||
return static::from(debug_backtrace($backtraceOptions, $limit));
|
||||
}
|
||||
|
||||
// Create a stack trace from an existing debug_backtrace output
|
||||
public static function from(array $trace)
|
||||
{
|
||||
$basePath = static::resolveBasePath();
|
||||
$vendorPath = static::resolveVendorPath();
|
||||
|
||||
return new static(array_map(function ($frame, $index) use ($basePath, $vendorPath, $trace) {
|
||||
return new StackFrame(
|
||||
static::fixCallUserFuncFrame($frame, $trace, $index), $basePath, $vendorPath
|
||||
);
|
||||
}, $trace, array_keys($trace)), $basePath, $vendorPath);
|
||||
}
|
||||
|
||||
public function __construct(array $frames, $basePath, $vendorPath)
|
||||
{
|
||||
$this->frames = $frames;
|
||||
$this->basePath = $basePath;
|
||||
$this->vendorPath = $vendorPath;
|
||||
}
|
||||
|
||||
// Get all frames
|
||||
public function frames()
|
||||
{
|
||||
return $this->frames;
|
||||
}
|
||||
|
||||
// Get the first frame, optionally filtered by a stack filter or a closure
|
||||
public function first($filter = null)
|
||||
{
|
||||
if (! $filter) return reset($this->frames);
|
||||
|
||||
if ($filter instanceof StackFilter) $filter = $filter->closure();
|
||||
|
||||
foreach ($this->frames as $frame) {
|
||||
if ($filter($frame)) return $frame;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the last frame, optionally filtered by a stack filter or a closure
|
||||
public function last($filter = null)
|
||||
{
|
||||
if (! $filter) return $this->frames[count($this->frames) - 1];
|
||||
|
||||
if ($filter instanceof StackFilter) $filter = $filter->closure();
|
||||
|
||||
foreach (array_reverse($this->frames) as $frame) {
|
||||
if ($filter($frame)) return $frame;
|
||||
}
|
||||
}
|
||||
|
||||
// Get trace filtered by a stack filter or a closure
|
||||
public function filter($filter = null)
|
||||
{
|
||||
if ($filter instanceof StackFilter) $filter = $filter->closure();
|
||||
|
||||
return $this->copy(array_values(array_filter($this->frames, $filter)));
|
||||
}
|
||||
|
||||
// Get trace skipping a number of frames or frames matching a stack filter or a closure
|
||||
public function skip($count = null)
|
||||
{
|
||||
if ($count instanceof StackFilter) $count = $count->closure();
|
||||
if ($count instanceof \Closure) $count = array_search($this->first($count), $this->frames);
|
||||
|
||||
return $this->copy(array_slice($this->frames, $count));
|
||||
}
|
||||
|
||||
// Get trace with a number of frames from the top
|
||||
public function limit($count = null)
|
||||
{
|
||||
return $this->copy(array_slice($this->frames, 0, $count));
|
||||
}
|
||||
|
||||
// Get a copy of the trace
|
||||
public function copy($frames = null)
|
||||
{
|
||||
return new static($frames ?: $this->frames, $this->basePath, $this->vendorPath);
|
||||
}
|
||||
|
||||
protected static function resolveBasePath()
|
||||
{
|
||||
return substr(__DIR__, 0, strpos(__DIR__, DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR));
|
||||
}
|
||||
|
||||
protected static function resolveVendorPath()
|
||||
{
|
||||
return static::resolveBasePath() . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
// Fixes call_user_func stack frames missing file and line
|
||||
protected static function fixCallUserFuncFrame($frame, array $trace, $index)
|
||||
{
|
||||
if (isset($frame['file'])) return $frame;
|
||||
|
||||
$nextFrame = isset($trace[$index + 1]) ? $trace[$index + 1] : null;
|
||||
|
||||
if (! $nextFrame || ! in_array($nextFrame['function'], [ 'call_user_func', 'call_user_func_array' ])) return $frame;
|
||||
|
||||
$frame['file'] = $nextFrame['file'];
|
||||
$frame['line'] = $nextFrame['line'];
|
||||
|
||||
return $frame;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user