Логирование Событий И Yii2

Добрый день.

Есть проект, в котором необходимо логировать различного рода действия:

  • попытка подбора пароля пользователя

  • попытка доступа к запрещеному ресурсу

  • изменение пользователем платёжных реквизитов

  • создание пользователем счетов

  • пополнение пользователем баланса одного из счетов

  • изменен статус пользователя

так же есть бекенд и фронтенд. Необходимо научится определять кто (менеджер) или сам пользователь изменил эти данные.

в логе необходимо знать:

  • кто инициатор действия

  • кто владелец сущности

  • информаци о сущности

  • источник действия (backend/frontend)

  • вид действия

  • текст сообщения (в тексте могут быть ссылки на объекты)

Какой по вашему мнению наиболее правильный путь реализации подобной системы логирования?

стоит ли использовать нативные способы логирования или для таких задач данный механизм не подходит?

п.с.

еще очень мучает вопрос, должны ли мы сохранять в лог (например: создание пользователем счетов) если по какойто причине при создания дополнительной информации к счету пришлось откатывать всю транзакцию.

Стандартные методы для такого не подходят. Я бы делал так:

  1. Таблица со всеми необходимыми полями.

  2. Модель для таблицы с методом сохранения в лог (function saveLog($attributes)), она же пригодится нам для вывода.

  3. Добавим вызов данной функции и передадим параметры в тех действиях где нужно логирование.

Насчет вопросов, инициатора можно узнать вытянув параметры Yii::app()->user->identity например. Информацию о сущности и владельца собственно берем из сущности, так как мы в ней находимся, проблем не возникает. backend/frontend - ну где находимся, то и отправляем. Ну и собственно все остальное так же.

Насчет транзакций уточняйте в тз или менеджера, тут уже что кому нужно. У меня например стояло требование логировать все независимо от того даже изменилось ли что то (жестко, зато видно кто и что пытается править).




namespace backend\models\Order;


class Order extends ActiveRecord

{


	private $attributes_diff = [];


	private function addEventLog($action, $data = [])

	{

		$data = array_merge($data, [

			'order_id' => $this->id

		]);

		EventLog::addMsg($action, $data);

	}


	public function beforeSave($insert)

	{

		if ($insert) {

			$this->addEventLog(EventLog::ACTION_ADD_ORDER);

		} else {

			$old = $this->getOldAttributes();

			$new = $this->getAttributes();

			$this->attributes_diff = array_diff_assoc($new, $old);

		}

		return parent::beforeSave($insert);

	}


	public function afterSave($insert, $changedAttributes)

	{

		/** Если при редактировании были изменены поля */

		if ($this->attributes_diff && $insert == false) {

			$this->addEventLog(EventLog::ACTION_EDIT_ORDER, [

				'diff' => Json::encode($this->attributes_diff)

			]);

		}


		parent::afterSave($insert, $changedAttributes);

	}


}






namespace backend\models\EventLog;


class EventLog extends ActiveRecord

{

	/** Order */

	const ACTION_ADD_ORDER = 10;

	const ACTION_EDIT_ORDER = 11;

	const ACTION_DELETE_ORDER = 12;


	const ACTION_ADD_ORDER_PRODUCT = 13;

	const ACTION_EDIT_ORDER_PRODUCT = 14;

	const ACTION_DELETE_ORDER_PRODUCT = 15;


	public function behaviors()

	{

		return [

			'timestamp' => [

				'class' => TimestampBehavior::className(),

				'attributes' => [

					ActiveRecord::EVENT_BEFORE_INSERT => ['create_at'],

				],

			],

		];

	}


	public function rules()

	{

		return [

			[['action', 'user_id'], 'required'],

			[['action', 'user_id', 'create_at'], 'integer'],

			[['data'], 'string']

		];

	}


	public static function addMsg($action, $params)

	{

		$model = new self;

		$model->attributes = [

			'action' => $action,

			'user_id' => \Yii::$app->user->id,

			'data' => Json::encode($params),

		];

		$model->insert(true);

	}


	public static function getMsg($action, $params)

	{

		return \Yii::t('EventLog', $action, Json::decode($params));

	}

}



backend/messages/ru/EventLog.php




use backend\models\EventLog;


return [

	/** Order */

	EventLog::ACTION_ADD_ORDER => 'Добавлен новый заказ #{order_id}',

	EventLog::ACTION_EDIT_ORDER => 'Заказ #{order_id} был измен ({diff})',

	EventLog::ACTION_DELETE_ORDER => 'Заказ #{order_id} был удален',


	EventLog::ACTION_ADD_ORDER_PRODUCT => 'Товар #{product_id}, добавлен в заказ #{order_id}',

	EventLog::ACTION_EDIT_ORDER_PRODUCT => 'Товар #{product_id}, в заказе #{order_id}, был изменен ({diff})',

	EventLog::ACTION_DELETE_ORDER_PRODUCT => 'Товар #{product_id}, в заказе #{order_id}, был удален',

];



backend/config/main.php




return [

	'components' => [

		'i18n' => [

			'translations' => [

				'EventLog' => [

					'class' => 'yii\i18n\PhpMessageSource',

					'sourceLanguage' => 'ru-RU',

					'basePath' => '@app/messages',

				],

			]

		],

	],

];



Единственный недостаток приходится выводить ({diff}) - ассоциативный массив со значениями old и new для пользователя тут нужна будет что-то более симпатичное придумать.

Как я понимаю, вы привели пример своего готового решения?

на заметку: нет необходимости делать дивв old и new. параметр $changedAttributes как раз содержит старые данные которые изменились.

СПС, на тот момент когда все это писалось такого метода ещё не было.

Как раз нужна будет переписать все что я там "накодил".