src/Logger.php
public function log( $level, $message, array $context = array() ) {

		if ( ! in_array( $level, array(
			LogLevel::ALERT,
			LogLevel::CRITICAL,
			LogLevel::DEBUG,
			LogLevel::EMERGENCY,
			LogLevel::ERROR,
			LogLevel::INFO,
			LogLevel::NOTICE,
			LogLevel::WARNING
		) )
		) {
			throw new InvalidArgumentException( sprintf( "Invalid log level '%s'", $level ) );
		}

		$message      = (string) $message;
		$interpolated = $this->interpolate( $message, $context );

		if ( isset( $context['exception'] ) && $context['exception'] instanceof \Exception ) {

			/** @var \Exception $exception */
			$exception = $context['exception'];

			$class = get_class( $context['exception'] );
			$trace = $exception->getTraceAsString();

			unset( $context['exception'] );
		} else {
			$class = '';
			$trace = '';
		}

		$data = array(
			'level'     => $level,
			'message'   => $interpolated,
			'lgroup'    => isset( $context['_group'] ) ? substr( $context['_group'], 0, 20 ) : '',
			'time'      => date( 'Y-m-d H:i:s' ),
			'ip'        => $this->get_ip(),
			'exception' => $class,
			'trace'     => $trace,
			'context'   => @wp_json_encode( $context )
		);

		$valid_columns = $this->table->get_columns();

		foreach ( $context as $key => $value ) {

			if ( strpos( $key, '_' ) === 0 ) {

				$context_column_name = substr( $key, 1 );

				if ( isset( $valid_columns[ $context_column_name ] ) ) {
					$data[ $context_column_name ] = $value;
				}
			}
		}

		if ( ! isset( $data['user'] ) && is_user_logged_in() ) {
			$data['user'] = get_current_user_id();
		}

		$this->query->insert( $data );
	}
public function log( $level, $message, array $context = array() ) {

		if ( ! in_array( $level, array(
			LogLevel::ALERT,
			LogLevel::CRITICAL,
			LogLevel::DEBUG,
			LogLevel::EMERGENCY,
			LogLevel::ERROR,
			LogLevel::INFO,
			LogLevel::NOTICE,
			LogLevel::WARNING
		) )
		) {
			throw new InvalidArgumentException( sprintf( "Invalid log level '%s'", $level ) );
		}

		$message      = (string) $message;
		$interpolated = $this->interpolate( $message, $context );

		if ( isset( $context['exception'] ) && $context['exception'] instanceof \Exception ) {

			/** @var \Exception $exception */
			$exception = $context['exception'];

			$class = get_class( $context['exception'] );
			$trace = $exception->getTraceAsString();

			unset( $context['exception'] );
		} else {
			$class = '';
			$trace = '';
		}

		$data = array(
			'level'     => $level,
			'message'   => $interpolated,
			'lgroup'    => isset( $context['_group'] ) ? substr( $context['_group'], 0, 20 ) : '',
			'time'      => date( 'Y-m-d H:i:s' ),
			'ip'        => $this->get_ip(),
			'exception' => $class,
			'trace'     => $trace,
			'context'   => @wp_json_encode( $context )
		);

		$valid_columns = $this->table->get_columns();

		foreach ( $context as $key => $value ) {

			if ( strpos( $key, '_' ) === 0 ) {

				$context_column_name = substr( $key, 1 );

				if ( isset( $valid_columns[ $context_column_name ] ) ) {
					$data[ $context_column_name ] = $value;
				}
			}
		}

		if ( ! isset( $data['user'] ) && is_user_logged_in() ) {
			$data['user'] = get_current_user_id();
		}

		$this->query->insert( $data );
	}
Logs with an arbitrary level.

The current user ID will be automatically logged.
To bypass this pass `false` for `_user` in `$context`.

To assign the log to a group, pass the group name ( up to 20 chars ) for `_group` in `$context`.

Any additional columns in the db can be passed in `$context` by prefixing the column name with `_`.
For example, passing a key `_product_id` in `$context` will save whatever value given in the column
named `product_id`. If the column does not exist the value will be silently discarded.

The he context array will be recorded as JSON, sans the `exception` if passed and an Exception object.

@param mixed  $level
@param string $message
@param array  $context

@return null