Skip to content

Commit 01889eb

Browse files
committed
Additional logging placeholders are now replaced, and filenames are cleaned.
1 parent 4cb5eb0 commit 01889eb

File tree

2 files changed

+148
-1
lines changed

2 files changed

+148
-1
lines changed

system/Log/Logger.php

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,10 @@ public function log($level, $message, array $context = []): bool
319319
* {session_vars}
320320
* {post_vars}
321321
* {get_vars}
322+
* {env}
323+
* {env:foo}
324+
* {file}
325+
* {line}
322326
*
323327
* @param $message
324328
* @param array $context
@@ -336,7 +340,7 @@ protected function interpolate($message, array $context = [])
336340
// or error, both of which implement the 'Throwable' interface.
337341
if ($key == 'exception' && $val instanceof \Throwable)
338342
{
339-
$val = $val->getMessage().' '.$val->getFile().':'. $val->getLine();
343+
$val = $val->getMessage().' '.$this->cleanFileNames($val->getFile()).':'. $val->getLine();
340344
}
341345

342346
// todo - sanitize input before writing to file?
@@ -346,6 +350,31 @@ protected function interpolate($message, array $context = [])
346350
// Add special placeholders
347351
$replace['{post_vars}'] = '$_POST: '.print_r($_POST, true);
348352
$replace['{get_vars}'] = '$_GET: '.print_r($_GET, true);
353+
$replace['{env}'] = ENVIRONMENT;
354+
355+
// Allow us to log the file/line that we are logging from
356+
if (strpos($message, '{file}') !== false)
357+
{
358+
list($file, $line) = $this->determineFile();
359+
360+
$replace['{file}'] = $file;
361+
$replace['{line}'] = $line;
362+
}
363+
364+
// Match up environment variables in {env:foo} tags.
365+
if (strpos($message, 'env:') !== false)
366+
{
367+
preg_match('/env:[^}]+/', $message, $matches);
368+
369+
if (count($matches))
370+
{
371+
foreach ($matches as $str)
372+
{
373+
$key = str_replace('env:', '', $str);
374+
$replace["{{$str}}"] = $_ENV[$key] ?? 'n/a';
375+
}
376+
}
377+
}
349378

350379
if (isset($_SESSION))
351380
{
@@ -358,4 +387,63 @@ protected function interpolate($message, array $context = [])
358387

359388
//--------------------------------------------------------------------
360389

390+
/**
391+
* Determines the current file/line that the log method was called from.
392+
* by analyzing the backtrace.
393+
*
394+
* @return array
395+
*/
396+
public function determineFile()
397+
{
398+
// Determine the file and line by finding the first
399+
// backtrace that is not part of our logging system.
400+
$trace = debug_backtrace();
401+
$file = null;
402+
$line = null;
403+
404+
foreach ($trace as $row)
405+
{
406+
if (in_array($row['function'], ['interpolate', 'determineFile', 'log', 'log_message']))
407+
{
408+
continue;
409+
}
410+
411+
$file = $row['file'] ?? isset($row['object']) ? get_class($row['object']) : 'unknown';
412+
$line = $row['line'] ?? $row['function'] ?? 'unknown';
413+
break;
414+
}
415+
416+
return [
417+
$file,
418+
$line
419+
];
420+
}
421+
422+
//--------------------------------------------------------------------
423+
424+
425+
/**
426+
* Cleans the paths of filenames by replacing APPPATH, BASEPATH, FCPATH
427+
* with the actual var. i.e.
428+
*
429+
* /var/www/site/application/controllers/Home.php
430+
* becomes:
431+
* APPPATH/controllers/Home.php
432+
*
433+
* @param $file
434+
*
435+
* @return mixed
436+
*/
437+
protected function cleanFileNames($file)
438+
{
439+
$file = str_replace(APPPATH, 'APPPATH/', $file);
440+
$file = str_replace(BASEPATH, 'BASEPATH/', $file);
441+
$file = str_replace(FCPATH, 'FCPATH/', $file);
442+
443+
return $file;
444+
}
445+
446+
//--------------------------------------------------------------------
447+
448+
361449
}

tests/Log/LoggerTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,65 @@ public function testLogInterpolatesSession()
162162

163163
//--------------------------------------------------------------------
164164

165+
public function testLogInterpolatesCurrentEnvironment()
166+
{
167+
$config = new LoggerConfig();
168+
169+
$logger = new Logger($config);
170+
171+
$expected = 'DEBUG - '.date('Y-m-d').' --> Test message '. ENVIRONMENT;
172+
173+
$logger->log('debug', 'Test message {env}');
174+
175+
$logs = TestHandler::getLogs();
176+
177+
$this->assertEquals(1, count($logs));
178+
$this->assertEquals($expected, $logs[0]);
179+
}
180+
181+
//--------------------------------------------------------------------
182+
183+
public function testLogInterpolatesEnvironmentVars()
184+
{
185+
$config = new LoggerConfig();
186+
187+
$logger = new Logger($config);
188+
189+
$_ENV['foo'] = 'bar';
190+
191+
$expected = 'DEBUG - '.date('Y-m-d').' --> Test message bar';
192+
193+
$logger->log('debug', 'Test message {env:foo}');
194+
195+
$logs = TestHandler::getLogs();
196+
197+
$this->assertEquals(1, count($logs));
198+
$this->assertEquals($expected, $logs[0]);
199+
}
200+
201+
//--------------------------------------------------------------------
202+
203+
public function testLogInterpolatesFileAndLine()
204+
{
205+
$config = new LoggerConfig();
206+
207+
$logger = new Logger($config);
208+
209+
$_ENV['foo'] = 'bar';
210+
211+
// For whatever reason, this will often be the class/function instead of file and line.
212+
$expected = 'DEBUG - '.date('Y-m-d').' --> Test message LoggerTest testLogInterpolatesFileAndLine';
213+
214+
$logger->log('debug', 'Test message {file} {line}');
215+
216+
$logs = TestHandler::getLogs();
217+
218+
$this->assertEquals(1, count($logs));
219+
$this->assertEquals($expected, $logs[0]);
220+
}
221+
222+
//--------------------------------------------------------------------
223+
165224
public function testEmergencyLogsCorrectly()
166225
{
167226
$config = new LoggerConfig();

0 commit comments

Comments
 (0)