# Log ¶

O Yii fornece um poderoso framework de log que é altamente personalizável e extensível. Utilizando este framework, você pode facilmente gerar logs de vários tipos de mensagens, filtrá-las, e salva-las em diferentes meios, tais como arquivos, banco de dados, e-mails.

Usar o Yii framework Log envolve os seguintes passos:

- Registrar mensagens de log de vários lugares do seu código;
- Configurar o destino de log na configuração da aplicação para filtrar e exportar mensagens de log;
- Examinar as mensagens de erro exportadas (ex.: Yii debugger).

Nesta seção, vamos descrever principalmente os dois primeiros passos.

## Gravar Mensagens ¶

Gravar mensagens de log é tão simples como chamar um dos seguintes métodos de registro:

- Yii::debug(): gravar uma mensagem para rastrear como um determinado trecho de código é executado. Isso é principalmente para o uso de desenvolvimento.
- Yii::info(): gravar uma mensagem que transmite algumas informações úteis.
- Yii::warning(): gravar uma mensagem de aviso que indica que algo inesperado aconteceu.
- Yii::error(): gravar um erro fatal que deve ser investigado o mais rápido possível.

Estes métodos gravam mensagens de log em vários níveis e categorias. Eles compartilham a mesma assinatura de função `function ($message, $category = 'application')`, onde `$message` significa a mensagem de log a ser gravada, enquanto `$category` é a categoria da mensagem de log. O código no exemplo a seguir registra uma mensagem de rastreamento sob a categoria padrão `application`:

    Yii::debug('start calculating average revenue');

> Observação: Mensagens de log podem ser strings, bem como dados complexos, tais como arrays ou objetos. É da responsabilidade dos destinos de log lidar adequadamente com as mensagens de log. Por padrão, se uma mensagem de log não for uma string, ela será exportada como uma string chamando yii\helpers\VarDumper::export().

Para melhor organizar e filtrar as mensagens de log, é recomendável que você especifique uma categoria apropriada para cada mensagem de log. Você pode escolher um esquema de nomenclatura hierárquica para as categorias, o que tornará mais fácil para os destinos de log filtrar mensagens com base em suas categorias. Um esquema de nomes simples, mas eficaz é usar a constante mágica PHP `__METHOD__` para os nomes das categorias. Esta é também a abordagem utilizada no código central do framework Yii. Por exemplo,

    Yii::debug('start calculating average revenue', __METHOD__);

A constante `__METHOD__` corresponde ao nome do método (prefixado com o caminho completo do nome da classe) onde a constante aparece. Por exemplo, é igual a string `'app\controllers\RevenueController::calculate'` se o código acima for chamado dentro deste método.

> Observação: Os métodos de registro descritos acima são na verdade atalhos para o método log() do logger object que é um singleton acessível através da expressão `Yii::getLogger()`. Quando um determinado número de mensagens são logadas ou quando a aplicação termina, o objeto logger irá chamar um message dispatcher para enviar mensagens de log gravadas destinos de log.

## Destinos de Log ¶

Um destino de log é uma instância da classe yii\log\Target ou uma classe filha. Ele filtra as mensagens de log por seus níveis e categorias e, em seguida, às exportam para algum meio. Por exemplo, um banco de dados de destino exporta as mensagens de log para uma tabela no banco de dados, enquanto um e-mail de destino exporta as mensagens de log para algum e-mail especificado.

Você pode registrar vários destinos de log em uma aplicação configurando-os através do componente da aplicação `log` na configuração da aplicação, como a seguir:

    return [
      // o componente  "log" deve ser carregado durante o tempo de inicialização
      'bootstrap' => ['log'],

      'components' => [
          'log' => [
              'targets' => [
                  [
                      'class' => 'yii\log\DbTarget',
                      'levels' => ['error', 'warning'],
                  ],
                  [
                      'class' => 'yii\log\EmailTarget',
                      'levels' => ['error'],
                      'categories' => ['yii\db\*'],
                      'message' => [
                         'from' => ['log@example.com'],
                         'to' => ['admin@example.com', 'developer@example.com'],
                         'subject' => 'Database errors at example.com',
                      ],
                  ],
              ],
          ],
      ],
    ];

> Observação: O componente `log` deve ser carregado durante a inicialização para que ele possa enviar mensagens de log para alvos prontamente. É por isso que ele está listado no array `bootstrap` como mostrado acima.

No código acima, dois destinos de log são registrados na propriedade yii\log\Dispatcher::$targets:

- o primeiro seleciona mensagens de erro e de advertência e os salva em uma tabela de banco de dados;
- o segundo seleciona mensagens de erro sob as categorias cujos nomes começam com `yii\db\`, e as envia para os e-mails `admin@example.com` e `developer@example.com`.

Yii vem com os seguintes destinos de log preparados. Por favor consulte a documentação da API sobre essas classes para aprender como configurar e usá-los.

- yii\log\DbTarget: armazena mensagens de log em uma tabela de banco de dados.
- yii\log\EmailTarget: envia mensagens de log para um endereço de e-mail pré-definido.
- yii\log\FileTarget: salva mensagens de log em arquivos.
- yii\log\SyslogTarget: salva mensagens de log para o syslog chamando a função PHP `syslog()`.

A seguir, vamos descrever as características comuns a todos os destinos de log.

### Filtragem de Mensagem ¶

Para cada destino de log, você pode configurar suas propriedades levels e categories para especificar que os níveis e categorias das mensagens o destino de log deve processar.

A propriedade levels é um array que consiste em um ou vários dos seguintes valores:

- `error`: corresponde a mensagens logadas por Yii::error().
- `warning`: corresponde a mensagens logadas por Yii::warning().
- `info`: corresponde a mensagens logadas por Yii::info().
- `trace`: corresponde a mensagens logadas por Yii::debug().
- `profile`: corresponde a mensagens logadas por Yii::beginProfile() e Yii::endProfile(), que será explicado em mais detalhes na subseção Perfil de Desempenho.

Se você não especificar a propriedade levels, significa que o alvo de log processará mensagens de qualquer nível.

A propriedade categories é um array que consiste em categorias de mensagens ou padrões. Um destino de log irá processar apenas mensagens cuja categoria possa ser encontrada ou corresponder a um dos padrões do array. Um padrão de categoria é um prefixo de nome de categoria com um asterisco `*` na sua extremidade. Um nome de categoria corresponde a um padrão de categoria se ela iniciar com o mesmo prefixo do padrão. Por exemplo, `yii\db\Command::execute` e `yii\db\Command::query` são usados como nome de categoria para as mensagens de log gravadas na classe yii\db\Command. Ambos correspondem ao padrão `yii\db\*`. Se você não especificar a propriedade categories, significa que o destino de log processará mensagens de qualquer categoria.

Além de criar uma whitelist de categorias através da propriedade categories, você também pode criar uma blacklist de categorias através da propriedade except. Se a categoria da mensagem for encontrada ou corresponder a um dos padrões desta propriedade, ela não será processada pelo destino de log.

A próxima configuração de destino de log especifica que o destino deve processar somente mensagens de erro e alertas das categorias cujos nomes correspondam a `yii\db\*` ou `yii\web\HttpException:*`, mas não correspondam a `yii\web\HttpException:404`.

    [
      'class' => 'yii\log\FileTarget',
      'levels' => ['error', 'warning'],
      'categories' => [
          'yii\db\*',
          'yii\web\HttpException:*',
      ],
      'except' => [
          'yii\web\HttpException:404',
      ],
    ]

> Observação: Quando uma exceção HTTP é capturada pelo error handler, uma mensagem de erro será logada com o nome da categoria no formato de `yii\web\HttpException:ErrorCode`. Por exemplo, o yii\web\NotFoundHttpException causará uma mensagem de erro da categoria `yii\web\HttpException:404`.

### Formatando Mensagem ¶

Destinos de log exportam as mensagens de logs filtradas em um determinado formato. Por exemplo, se você instalar um destino de log da classe yii\log\FileTarget, você pode encontrar uma mensagem de log semelhante à seguinte no `runtime/log/app.log` file:

    2014-10-04 18:10:15 [::1][][-][trace][yii\base\Module::getModule] Loading module: debug

Por padrão, mensagens de log serão formatadas do seguinte modo pelo yii\log\Target::formatMessage():

    Timestamp [IP address][User ID][Session ID][Severity Level][Category] Message Text

Você pode personalizar este formato configurando a propriedade yii\log\Target::$prefix que recebe um PHP callable retornando um prefixo de mensagem personalizado. Por exemplo, o código a seguir configura um destino de log para prefixar cada mensagem de log com o ID do usuário corrente (Endereço IP e ID da sessão são removidos por razões de privacidade).

    [
      'class' => 'yii\log\FileTarget',
      'prefix' => function ($message) {
          $user = Yii::$app->has('user', true) ? Yii::$app->get('user') : null;
          $userID = $user ? $user->getId(false) : '-';
          return "[$userID]";
      }
    ]

Além de prefixos de mensagens, destinos de mensagens também anexa algumas informações de contexto para cada lote de mensagens de log. Por padrão, os valores destas variáveis globais PHP são incluídas: `$_GET`, `$_POST`, `$_FILES`, `$_COOKIE`, `$_SESSION` e `$_SERVER`. Você pode ajustar este comportamento configurando a propriedade yii\log\Target::$logVars com os nomes das variáveis globais que você deseja incluir para o destino de log. Por exemplo, a seguinte configuração de destino de log especifica que somente valores da variável `$_SERVER` seriam anexadas as mensagens de log.

    [
      'class' => 'yii\log\FileTarget',
      'logVars' => ['_SERVER'],
    ]

Você pode configurar `logVars` para ser um array vazio para desativar totalmente a inclusão de informações de contexto. Ou se você quiser implementar sua própria maneira de fornecer informações de contexto, você pode sobrescrever o método yii\log\Target::getContextMessage().

### Nível de Rastreio de Mensagem ¶

Durante o desenvolvimento, é desejável definir de onde cada mensagem de log virá. Isto pode ser conseguido por meio da configuração da propriedade traceLevel do componente `log` como a seguir:

    return [
      'bootstrap' => ['log'],
      'components' => [
          'log' => [
              'traceLevel' => YII_DEBUG ? 3 : 0,
              'targets' => [...],
          ],
      ],
    ];

A configuração da aplicação acima define o traceLevel para ser 3 se `YII_DEBUG` estiver ligado e 0 se `YII_DEBUG` estiver desligado. Isso significa, se `YII_DEBUG` estiver ligado, cada mensagem de log será anexada com no máximo 3 níveis de call stack (pilhas de chamadas) em que a mensagem de log é registrada; e se `YII_DEBUG` estiver desligado, nenhuma informação do call stack será incluída.

> Observação: Obter informação do call stack não é trivial. Portanto, você deverá usar somente este recurso durante o desenvolvimento ou durante o debug da aplicação.

### Libertação e Exportação de Mensagens ¶

Como já mencionado, mensagens de log são mantidas em um array através do objeto logger. Para limitar o consumo de memória por este array, o objeto logger irá liberar as mensagens gravadas para os destinos de log cada vez que o array acumula um certo número de mensagens de log. Você pode personalizar este número configurando a propriedade flushInterval do componente `log`:

    return [
      'bootstrap' => ['log'],
      'components' => [
          'log' => [
              'flushInterval' => 100,   // o padrão é 1000
              'targets' => [...],
          ],
      ],
    ];

> Observação: Liberação de mensagens também acontece quando a aplicação termina, o que garante que alvos de log possam receber as informações completas de mensagens de log.

Quando o logger object libera mensagens de log para os alvos de log, elas não são exportadas imediatamente. Em vez disso, a exportação de mensagem só ocorre quando o alvo de log acumula certo número de mensagens filtradas. Você pode personalizar este número configurando a propriedade exportInterval de cada alvo de log, como a seguir,

    [
      'class' => 'yii\log\FileTarget',
      'exportInterval' => 100,  // default is 1000
    ]

Devido a configuração de nível, liberação e exportação, por padrão quando você chama `Yii::debug()` ou qualquer outro método de log, você NÃO verá a mensagem de log imediatamente no destino. Isto poderia ser um problema para algumas aplicações console de longa execução. Para fazer cada mensagem de log aparecer imediatamente no destino, você deve configurar ambos flushInterval e exportInterval para 1, como mostrado a seguir:

    return [
      'bootstrap' => ['log'],
      'components' => [
          'log' => [
              'flushInterval' => 1,
              'targets' => [
                  [
                      'class' => 'yii\log\FileTarget',
                      'exportInterval' => 1,
                  ],
              ],
          ],
      ],
    ];

> Observação: A frequente liberação e exportação de mensagens irá degradar o desempenho da sua aplicação.

### Alternando Destinos de Log ¶

Você pode habilitar ou desabilitar um destino de log configurando a propriedade enabled. Você pode fazê-lo através da configuração do destino de log ou pela seguinte declaração em seu código PHP:

    Yii::$app->log->targets['file']->enabled = false;

O código acima requer que você nomeie um destino como`file`, como mostrado acima usando chaves de string no array `targets`:

    return [
      'bootstrap' => ['log'],
      'components' => [
          'log' => [
              'targets' => [
                  'file' => [
                      'class' => 'yii\log\FileTarget',
                  ],
                  'db' => [
                      'class' => 'yii\log\DbTarget',
                  ],
              ],
          ],
      ],
    ];

### Criando Novos Destinos ¶

Criar uma nova classe de destino de log é muito simples. Você primeiramente precisa implementar o método yii\log\Target::export() enviando o conteúdo do array yii\log\Target::$messages para o meio designado. Você pode chamar o método yii\log\Target::formatMessage() para formatar cada mensagem. Para mais detalhes, você pode consultar qualquer uma das classes de destino de log incluído na versão Yii.

## Perfil de Desempenho ¶

Perfil de desempenho é um tipo especial de log de mensagem que é usado para medir o tempo que certos blocos de código demora e para descobrir quais são os gargalos de desempenho. Por exemplo, a classe yii\db\Command utiliza perfil de desempenho para descobrir o tempo que cada db query leva.

Para usar perfil de desempenho, primeiro identifique o bloco de código que precisa ser analisado. Então, encapsula cada bloco de código como o seguinte:

    \Yii::beginProfile('myBenchmark');

    ...code block being profiled...

    \Yii::endProfile('myBenchmark');

onde `myBenchmark` representa um token único de identificação de um bloco de código. Mais tarde quando você for examinar o resultado, você usará este token para localizar o tempo gasto pelo determinado bloco de código.

É importante certificar-se de que os pares de `beginProfile` e `endProfile` estão corretamente aninhadas. Por exemplo,

    \Yii::beginProfile('block1');

      // algum código a ser analizado

      \Yii::beginProfile('block2');
          // algum outro código a ser analizado
      \Yii::endProfile('block2');

    \Yii::endProfile('block1');

Se você esquecer `\Yii::endProfile('block1')` ou trocar a ordem de `\Yii::endProfile('block1')` e `\Yii::endProfile('block2')`, o perfil de desempenho não funcionará.

Para cada bloco de código iniciado com `beginProfile`, uma mensagem de log com o nível `profile` é registrada. Você pode configurar um destino de log para coletar tais mensagens e exportá-las. O Yii debugger implementa um painel de perfil de desempenho mostrando os seus resultados.