Yes, it is correct to say that the username is logged only when there is an account matching that username. That is what UserLoginForm::validateFinal()
does.
// Use $form_state->getUserInput() in the error message to guarantee
// that we send exactly what the user typed in. The value from
// $form_state->getValue() may have been modified by validation
// handlers that ran earlier than this one.
$user_input = $form_state->getUserInput();
$query = isset($user_input['name']) ? ['name' => $user_input['name']] : [];
$form_state->setErrorByName('name', $this->t('Unrecognized username or password. <a href=":password">Forgot your password?</a>', [':password' => Url::fromRoute('user.pass', [], ['query' => $query])->toString()]));
$accounts = $this->userStorage->loadByProperties(['name' => $form_state->getValue('name')]);
if (!empty($accounts)) {
$this->logger('user')
->notice('Login attempt failed for %user.', ['%user' => $form_state->getValue('name')]);
}
else {
// If the username entered is not a valid user,
// only store the IP address.
$this->logger('user')
->notice('Login attempt failed from %ip.', ['%ip' => $this->getRequest()->getClientIp()]);
}
To log what has been entered in the login form as username, you can add a validation handler that contains code similar to the following one.
if (!$form_state->get('uid')) {
// The login attempt failed.
$user_input = $form_state->getUserInput();
$ip = Drupal::request()->getClientIp();
\Drupal::logger('mymodule')->notice('Login attempt failed (user: "%user", IP: %ip).', ['%user' => $user_input['name'] ?? '', '%ip' => $ip]);
}
I used $form_state->getUserInput()
for the same reason given in the UserLoginForm::validateFinal()
comment: $form_state->getUserInput()
returns exactly what has been entered in the form, while the value returned by $form_state->getValue()
could have been modified by any validation handler.