I prepared the code for the same purpose - maybe you will find it useful.
Override getContextMessage() in chosen target class like:
<?php
namespace your\namespace\here;
use yii\helpers\ArrayHelper;
class FileTarget extends \yii\log\FileTarget
{
protected function getContextMessage()
{
$context = ArrayHelper::filter($GLOBALS, $this->logVars);
$result = [];
foreach ($context as $key => $value) {
if (\is_string($value) && stripos($key, 'password') !== false) {
$result[] = "\${$key} = '** PASSWORD HIDDEN **'";
} else {
$result[] = "\${$key} = " . \your\namespace\here\LogVarDumper::dumpAsString($value);
}
}
return implode("\n\n", $result);
}
}
Override VarDumper class with LogVarDumper (used above):
<?php
namespace your\namespace\here;
use yii\base\InvalidValueException;
/**
* Class LogVarDumper
* Extended to handle logs password fields darkening.
*/
class LogVarDumper extends \yii\helpers\VarDumper
{
private static $_objects;
private static $_output;
private static $_depth;
public static function dumpAsString($var, $depth = 10, $highlight = false)
{
self::$_output = '';
self::$_objects = [];
self::$_depth = $depth;
self::dumpInternal($var, 0);
if ($highlight) {
$result = highlight_string("<?php\n" . self::$_output, true);
self::$_output = preg_replace('/<\\?php<br \\/>/', '', $result, 1);
}
return self::$_output;
}
/**
* @param mixed $var variable to be dumped
* @param int $level depth level
* @param bool $passwordKey whether password related key was present in previous iteration
*/
private static function dumpInternal($var, $level, $passwordKey = false)
{
switch (gettype($var)) {
case 'boolean':
self::$_output .= $var ? 'true' : 'false';
break;
case 'integer':
self::$_output .= "$var";
break;
case 'double':
self::$_output .= "$var";
break;
case 'string':
if ($passwordKey) {
self::$_output .= "'** PASSWORD HIDDEN **'";
} else {
self::$_output .= "'" . addslashes($var) . "'";
}
break;
case 'resource':
self::$_output .= '{resource}';
break;
case 'NULL':
self::$_output .= 'null';
break;
case 'unknown type':
self::$_output .= '{unknown}';
break;
case 'array':
if (self::$_depth <= $level) {
self::$_output .= '[...]';
} elseif (empty($var)) {
self::$_output .= '[]';
} else {
$keys = array_keys($var);
$spaces = str_repeat(' ', $level * 4);
self::$_output .= '[';
foreach ($keys as $key) {
self::$_output .= "\n" . $spaces . ' ';
self::dumpInternal($key, 0);
self::$_output .= ' => ';
self::dumpInternal($var[$key], $level + 1, strpos(strtolower($key), 'password') !== false);
}
self::$_output .= "\n" . $spaces . ']';
}
break;
case 'object':
if (($id = array_search($var, self::$_objects, true)) !== false) {
self::$_output .= get_class($var) . '#' . ($id + 1) . '(...)';
} elseif (self::$_depth <= $level) {
self::$_output .= get_class($var) . '(...)';
} else {
$id = array_push(self::$_objects, $var);
$className = get_class($var);
$spaces = str_repeat(' ', $level * 4);
self::$_output .= "$className#$id\n" . $spaces . '(';
if ('__PHP_Incomplete_Class' !== get_class($var) && method_exists($var, '__debugInfo')) {
$dumpValues = $var->__debugInfo();
if (!is_array($dumpValues)) {
throw new InvalidValueException('__debuginfo() must return an array');
}
} else {
$dumpValues = (array) $var;
}
foreach ($dumpValues as $key => $value) {
$keyDisplay = strtr(trim($key), "\0", ':');
self::$_output .= "\n" . $spaces . " [$keyDisplay] => ";
self::dumpInternal($value, $level + 1);
}
self::$_output .= "\n" . $spaces . ')';
}
break;
}
}
}
And use your\namespace\here\FileTarget in configuration for logs. You can use all properties available for the selected target and now all fields containing password in their name with field value being string will log ** PASSWORD HIDDEN ** instead of actual password.