Depuração
De DTI Wiki
Para depuração de códigos PL/SQL NÃO use DBMS_OUTPUT, utilize as ferramentas do LOG4PLSQL instalado no esquema DLOG. Nenhum código que contenha instruções DBMS_OUTPUT será passado para a base de homologação (TEST) ou produção (SUN) mesmo que o código esteja comentado.
Tabela de conteúdo |
LOG4PLSQL - Oracle Database Logging Tools
LOG4PLSQL is developed by the LOG4PLSQL project team, see http://log4plsql.sourceforge.net.
Destino dos logs
O destino padrão dos logs gerados pela ferramenta é a tabela TLOG (DLOG.TLOG), opcionalmente podem ser direcionados também para a saída padrão (DBMS_OUTPUT), porém isso só poderá ser feito na base de desenvolvimento (LNX).
Os registros podem ser consultados na tabela TLOG (DLOG.TLOG) ou na view VLOG (DLOG.VLOG) e ficarão armazenados por 7 dias.
Procedimentos
A ferramenta disponibiliza alguns procedimentos para depuração dependendo do tipo de mensagem.
- debug - valor 60 - Mensagens informativas para depuração de um aplicativo em nível refinado.
- info - valor 50 - Mensagens informativas para acompanhamento da execução de um aplicativo em nivel menos refinado.
- waring - valor 40 - Mensagens para situações potencialmente prejudiciais.
- error - valor 30 - Mensagens para eventos de erro mas que ainda permitam que o aplicativo continue executando.
- fatal - valor 20 - Mensagens para eventos de erro muito grave que, presumivelmente, façam com que a aplicação seja abortada.
Nas bases de desenvolvimento e homologação todas as mensagens serão gravadas, na base de produção somente serão gravadas as mensagens a partir de warnig.
Uso básico
Os procedimentos podem ser chamados sem passagem de parâmetros, neste caso a mensagem padrão será SQLCODE SQLERRM, como mostrado no exemplo abaixo.
PROCEDURE prc_basico IS BEGIN dlog.plog.debug; dlog.plog.info; dlog.plog.warn; dlog.plog.error; dlog.plog.fatal; END prc_basico;
Neste caso o resultado é gravado na tabela TLOG. O resultado mostrado abaixo é uma consulta a view VLOG.
[Ago 12, 16:22:22:89][DEBUG][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][SQLCODE:0 SQLERRM:ORA-0000: normal, successful completion]
[Ago 12, 16:22:22:89][INFO][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][SQLCODE:0 SQLERRM:ORA-0000: normal, successful completion]
[Ago 12, 16:22:22:89][WARN][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][SQLCODE:0 SQLERRM:ORA-0000: normal, successful completion]
[Ago 12, 16:22:22:89][ERROR][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][SQLCODE:0 SQLERRM:ORA-0000: normal, successful completion]
[Ago 12, 16:22:22:89][FATAL][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][SQLCODE:0 SQLERRM:ORA-0000: normal, successful completion]
A mensagem pode ser passada por parâmetro, como mostrado abaixo.
PROCEDURE prc_basico IS BEGIN dlog.plog.debug('Mensagem de depuração'); dlog.plog.info('Mensagem de informação'); dlog.plog.warn('Mensagem de atenção'); dlog.plog.error('Mensagem de erro'); dlog.plog.fatal('Mensagem de erro fatal'); END prc_basico;
Desta forma o resultado obtido será como mostrado abaixo. Consulta a view VLOG.
[Ago 12, 16:22:22:89][DEBUG][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Mensagem de depuração]
[Ago 12, 16:22:22:89][INFO][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Mensagem de informação]
[Ago 12, 16:22:22:89][WARN][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Mensagem de atenção]
[Ago 12, 16:22:22:89][ERROR][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Mensagem de erro]
[Ago 12, 16:22:22:89][FATAL][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Mensagem de erro fatal]
Assertings
O uso de assert pode ser útil para verificar os valores de variáveis ou parâmetros da aplicação. Os parâmetros para assert são:
- condicao - boolean, obrigatório, se for falso a mensgaem será gravada;
- mensagem - varchar2, opcional, default assert condition error;
- codigo - number, opcional, default -20000, valores possíveis entre -20000 a -20999;
- raise - boolean, opcional, default FALSE, se verdadeiro um RAISE será executado utilizando codigo e mensagem.
A mensagem do assert só é gravada se a condição passada por parâemtro for falsa, veja exemplos abaixo.
PROCEDURE prc_asserts(in_dtinicial IN DATE, in_dtfinal IN DATE, in_coderro IN NUMBER DEFAULT -20999, in_raise IN BOOLEAN DEFAULT FALSE) IS BEGIN dlog.plog.assert(in_dtinicial <= in_dtfinal); dlog.plog.assert(in_dtinicial <= in_dtfinal, 'Data inicial maior que data final'); dlog.plog.assert(in_dtinicial <= in_dtfinal, 'Data inicial maior que data final', in_coderro, in_raise); END prc_asserts; -- Chamando o procedimento. BEGIN pkg_log4plsql.prc_asserts(SYSDATE, SYSDATE - 1, -20199); END;
Cada chamada a assert grava uma mensagem de erro de acordo com os parâmetros passados. Se for passado TRUE como quarto parâmetro será executado um RAISE_APPLICATION_ERROR com o código informado no terceiro parâmetro e a aplicação será abotrada.
Observe as mensagens abaixo (VLOG).
[Ago 15, 10:34:58:21][ALL][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][AAS-20000: assert condition error]
[Ago 15, 10:34:58:21][ALL][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][AAS-20000: Data inicial maior que data final]
[Ago 15, 10:34:58:21][ALL][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][AAS-20199: Data inicial maior que data final]
Usando variável de contexto
Os logs podem ser configurados por uma variável de contexto. Esta variável permite ao desenvolvedor alterar os valores default de configuração para uma seção, como por exemplo o nível de mensagens a gravar e o local de saída das mensagens.
Para utilizar vairáveis de contexto o desenvolvedor deve chamar o procedimento init() como nos exemplos abaixo.
Inicializando variável de contexto com valores padrão.
PROCEDURE prc_contexto IS v_ctx dlog.plogparam.log_ctx := dlog.plog.init(); BEGIN dlog.plog.info('Usando variáveis de contexto'); dlog.plog.debug(v_ctx, 'Mensagem de depuração com variável de contexto'); dlog.plog.info(v_ctx, 'Mensagem de informação com variável de contexto'); dlog.plog.warn(v_ctx, 'Mensagem de atenção com variável de contexto'); dlog.plog.error(v_ctx, 'Mensagem de erro com variável de contexto'); dlog.plog.fatal(v_ctx, 'Mensagem de erro fatal com variável de contexto'); END prc_contexto;
Mensagens gravadas com inicialização padrão (VLOG).
[Ago 15, 16:11:02:49][INFO][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Usando variáveis de contexto]
[Ago 15, 16:11:02:49][DEBUG][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Mensagem de depuração com variável de contexto]
[Ago 15, 16:11:02:49][INFO][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Mensagem de informação com variável de contexto]
[Ago 15, 16:11:02:49][WARN][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Mensagem de atenção com variável de contexto]
[Ago 15, 16:11:02:49][ERROR][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Mensagem de erro com variável de contexto]
[Ago 15, 16:11:02:49][FATAL][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Mensagem de erro fatal com variável de contexto]
Inicializando variável de contexto com valores diferentes do padrão, onde foram alterados a seção, o nível e saída.
PROCEDURE prc_contexto IS /* Valores default para as bases de desenvolvimento e homologação v_ctx dlog.plogparam.log_ctx := dlog.plog.init(psection => NULL, (Nome da seção) plevel => dlog.plog.ldebug, (Maior nível de depuração) plog4j => FALSE, (Não instalado - Advanced Queue) plogtable => TRUE, (Grava log na tabela de TLOG) pout_trans => TRUE, (Transação autônoma) palert => FALSE, (Não habilitado - alert.log) ptrace => FALSE, (Não habilitado - trace file) pdbms_output => FALSE, (Gera log na saída padrão DBMS_OUTPUT) psession => FALSE, (Não habilitado - v$session) pdbms_output_wrap => 100); (Comprimento da saída no DBMS_OUTPUT) Na base de produção a diferença está em plevel => dlog.plog.lwarn */ v_ctx dlog.plogparam.log_ctx := dlog.plog.init(psection => 'prc_contexto', plevel => LOG.plog.lwarn, pdbms_output => TRUE); BEGIN dlog.plog.info('Usando variáveis de contexto'); dlog.plog.debug(v_ctx, 'Mensagem de depuração com variável de contexto'); dlog.plog.info(v_ctx, 'Mensagem de informação com variável de contexto'); dlog.plog.warn(v_ctx, 'Mensagem de atenção com variável de contexto'); dlog.plog.error(v_ctx, 'Mensagem de erro com variável de contexto'); dlog.plog.fatal(v_ctx, 'Mensagem de erro fatal com variável de contexto'); END prc_contexto;
Mensagens gravadas com inicialização diferente do padrão.
Observe que a chamada a INFO não utiliza a variável de contexto, por este motivo foi gravada na tabela de log mas não foi apresentada no DBMS_OUTPUT.
As chamadas com utilização da variável de contexto só foram geradas a partir do nível warining e foram apresentadas também na saída padrão DBMS_OUTPUT.
Mensagens gravadas na tabela de log (VLOG).
[Ago 15, 16:48:56:16][INFO][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Usando variáveis de contexto]
[Ago 15, 16:48:56:16][WARN][ADDESENV][prc_contexto][Mensagem de atenção com variável de contexto]
[Ago 15, 16:48:56:20][ERROR][ADDESENV][prc_contexto][Mensagem de erro com variável de contexto]
[Ago 15, 16:48:56:20][FATAL][ADDESENV][prc_contexto][Mensagem de erro fatal com variável de contexto]
Saída no DBMS_OUTPUT.
16:48:56:16-WARN-prc_contexto Mensagem de atenção com variável de contexto
16:48:56:20-ERROR-prc_contexto Mensagem de erro com variável de contexto
16:48:56:20-FATAL-prc_contexto Mensagem de erro fatal com variável de contexto
Teste de nível de depuração
A melhor maneira de codificar as chamadas de depuração é fazendo um teste antes da chamada com a função isEnabled.
- isDebugEnabled
- isInfoEnabled
- isWarnEnabled
- isErrorEnabled
- isFatalEnabled
Esta forma de codificação será exigida quando a depuração for em cálculos, relatórios complexos ou processamentos com laços, pois os testes feitos antes da chamada ao procedimento de depuração diminuem consideravelmente o custo e o tempo de processamento.
PROCEDURE prc_contexto IS v_ctx dlog.plogparam.log_ctx := dlog.plog.init(psection => 'prc_contexto', plevel => LOG.plog.lwarn, pdbms_output => TRUE, pdbms_output_wrap => 150); BEGIN dlog.plog.info('Usando variáveis de contexto com teste antes da chamada'); IF dlog.plog.isdebugenabled(v_ctx) THEN dlog.plog.debug(v_ctx, 'Mensagem de depuração com variável de contexto'); END IF; IF dlog.plog.isinfoenabled(v_ctx) THEN dlog.plog.info(v_ctx, 'Mensagem de informação com variável de contexto'); END IF; IF dlog.plog.iswarnenabled(v_ctx) THEN dlog.plog.warn(v_ctx, 'Mensagem de atenção com variável de contexto'); END IF; IF dlog.plog.iserrorenabled(v_ctx) THEN dlog.plog.error(v_ctx, 'Mensagem de erro com variável de contexto'); END IF; IF dlog.plog.isfatalenabled(v_ctx) THEN dlog.plog.fatal(v_ctx, 'Mensagem de erro fatalcom variável de contexto'); END IF; END prc_contexto;
Mensagens gravadas na tabela de log (VLOG).
[Ago 15, 16:48:56:16][INFO][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][Usando variáveis de contexto com teste antes da chamada]
[Ago 15, 16:48:56:16][WARN][ADDESENV][prc_contexto][Mensagem de atenção com variável de contexto]
[Ago 15, 16:48:56:20][ERROR][ADDESENV][prc_contexto][Mensagem de erro com variável de contexto]
[Ago 15, 16:48:56:20][FATAL][ADDESENV][prc_contexto][Mensagem de erro fatal com variável de contexto]
Saída no DBMS_OUTPUT.
16:48:56:16-WARN-prc_contexto Mensagem de atenção com variável de contexto
16:48:56:20-ERROR-prc_contexto Mensagem de erro com variável de contexto
16:48:56:20-FATAL-prc_contexto Mensagem de erro fatal com variável de contexto
Concatenando mensagem de erro
Também podem ser criadas mensagens concantenando os retornos de erro do banco de dados.
PROCEDURE prc_getanomes(in_ano IN anomes.ano%TYPE, in_mes IN anomes.mes%TYPE) IS v_ctx dlog.plogparam.log_ctx := dlog.plog.init(psection => 'prc_contexto', plevel => dlog.plog.lwarn, pdbms_output => TRUE, pdbms_output_wrap => 150); v_encctb anomes.enccontabil%TYPE; BEGIN SELECT am.enccontabil INTO v_encctb FROM anomes am WHERE am.ano = in_ano AND am.mes = in_mes; EXCEPTION WHEN NO_DATA_FOUND THEN dlog.plog.error(v_ctx, 'Ano informado não cadastrado. Esta mensagem tem mais de 150 caracteres e ' || 'está concatenada com a mensagem de erro do banco de dados. ' || SQLERRM); END prc_getanomes; -- Chamando o procedimento BEGIN pkg_log4plsql.prc_getanomes(2011, 15); END;
Mensagens gravadas na tabela de log (VLOG).
[Ago 16, 10:29:46:24][ERROR][ADDESENV][prc_contexto][Ano informado não cadastrado. Esta mensagem tem mais de 150 caracteres e está concatenada com a mensagem de erro do banco de dados. ORA-01403: dados não encontrados]
Saída no DBMS_OUTPUT.
10:14:49:30-ERROR-prc_contexto Ano informado não cadastrado. Esta mensagem tem mais de 150 caracteres e está concatenada com a mensagem de erro do ba
nco de dados. ORA-01403: dados não encontrados
Criando mensagens com hierarquia
É possível criar mensagens com hierarquia.
- SetBeginSection - para criação de um novo nível na hierarquia.
- SetEndSection - para fechar um nível da hierarquia.
- GetSection - Retorna o nome da seção.
PROCEDURE prc_hierarquia IS v_ctx dlog.plogparam.log_ctx := dlog.plog.init(psection => 'prc_hierarquia'); BEGIN dlog.plog.debug(v_ctx, 'Usando log hierárquico'); dlog.plog.debug(v_ctx, 'Seção: ' || dlog.plog.getsection(v_ctx)); dlog.plog.setbeginsection(v_ctx, 'Nível 0'); dlog.plog.debug(v_ctx, 'Mensagem 1'); dlog.plog.setbeginsection(v_ctx, 'Nível 1'); dlog.plog.debug(v_ctx, 'Mensagem 2'); dlog.plog.setbeginsection(v_ctx, 'Nível 2'); dlog.plog.debug(v_ctx, 'Mensagem 3'); dlog.plog.debug(v_ctx, 'Mensagem 4'); dlog.plog.setendsection(v_ctx, 'Nível 2'); dlog.plog.debug(v_ctx, 'Mensagem 5'); dlog.plog.setendsection(v_ctx); dlog.plog.debug(v_ctx, 'Mensagem 6'); END prc_hierarquia;
Mensagens gravadas na tabela de log (VLOG).
[Ago 16, 10:35:58:02][DEBUG][ADDESENV][prc_hierarquia][Usando log hierárquico]
[Ago 16, 10:35:58:02][DEBUG][ADDESENV][prc_hierarquia][Seção: prc_hierarquia]
[Ago 16, 10:35:58:02][DEBUG][ADDESENV][prc_hierarquia.Nível 0][Mensagem 1]
[Ago 16, 10:35:58:02][DEBUG][ADDESENV][prc_hierarquia.Nível 0.Nível 1][Mensagem 2]
[Ago 16, 10:35:58:02][DEBUG][ADDESENV][prc_hierarquia.Nível 0.Nível 1.Nível 2][Mensagem 3]
[Ago 16, 10:35:58:02][DEBUG][ADDESENV][prc_hierarquia.Nível 0.Nível 1.Nível 2][Mensagem 4]
[Ago 16, 10:35:58:02][DEBUG][ADDESENV][prc_hierarquia.Nível 0.Nível 1][Mensagem 5]
[Ago 16, 10:35:58:02][DEBUG][ADDESENV][prc_hierarquia][Mensagem 6]
Backtrace
É possível gravar erros não tratados em procedimentos chamados usando a função full_error_backtrace.
Esta função faz o rastreamento do erro desde o procedimento onde ele ocorreu (exceção não tratada no procedimento) até o primeiro procedimento onde o erro for tratado.
O exemplo abaixo mostra que o erro ocorrido no procedimento prc_getano é propagado para o tratamento de exceção do procedimento prc_backtrace onde a função dlog.plog.full_error_backtrace é chamada.
PROCEDURE prc_getano(in_ano ano.ano%TYPE) IS v_encctb ano.enccontabil%TYPE; BEGIN SELECT a.enccontabil INTO v_encctb FROM ano a WHERE a.ano = in_ano; END prc_getano; PROCEDURE prc_chamagetano(in_ano ano.ano%TYPE) IS BEGIN prc_getano(in_ano); END prc_chamagetano; PROCEDURE prc_backtrace(in_ano ano.ano%TYPE) IS BEGIN prc_chamagetano(in_ano); dlog.plog.info('Procedimento executado com sucesso'); EXCEPTION WHEN OTHERS THEN dlog.plog.full_error_backtrace; END prc_backtrace; -- Chamada do procedimento BEGIN pkg_log4plsql.prc_backtrace(2158); END;
Mensagens gravadas na tabela de log (VLOG).
"[Ago 16, 11:14:42:09][ALL][ADDESENV][block-->ADDESENV.PKG_LOG4PLSQL][SQLCODE:100 SQLERRM:ORA-01403: dados não encontrados Error back trace:
em ""ADDESENV.PKG_LOG4PLSQL"", line 193
em ""ADDESENV.PKG_LOG4PLSQL"", line 214
em ""ADDESENV.PKG_LOG4PLSQL"", line 231
]"
Padrão de utilização na DTI
O uso na DTI foi padronizado para que as alterações do contexto de depuração possam ser feitas sem a necessidade de alteração e recompilação do código PL/SQL.
As chamadas aos procedimentos de depuração serão feitas sempre utilizando uma variável de contexto que será inicializada como mostrado abaixo.
PROCEDURE prc_contexto; /* Variável de contexto para depuração */ v_ctx dlog.plogparam.log_ctx := dlog.fun_getctx(dlog.plog.init(), sys.fun_whoami); BEGIN dlog.plog.debug(v_ctx, 'Exemplo de mensagem de depuração com variável de contexto'); /* É recomendada esta forma de codificação porque há menor impacto na performance da aplicação */ IF dlog.plog.isdebugenabled(v_ctx) THEN dlog.plog.debug(v_ctx, 'Exemplo de mensagem de depuração com variável de contexto'); END IF; END prc_contexto;
Foi criado uma tabela para armazenar as configurações de contexto individual por objeto a ser depurado. Desta forma é possível configurar um contexto diferente do contexto padrão do servidor, para um objeto específico e por tempo determinado.
Esta configuração permite a alteração do nome da seção, nível de depuração, exibição na saída padrão, tamanho da linha na saída padrão e ainda a data e hora final do contexto.
A configuração pode ser feita para procedures, functions, triggers ou packages. Para os packages a configuração pode ser feita tanto para o package como um todo ou para procedures ou functions internas.
Os objetos que não estiverem cadastrados ou estiverem com a data limite vencida serão depurados de acordo com a configuração padrão do servidor.
A manutenção pode ser acessada somente pelos analistas e desenvolvedores da DTI e está disponível no Menu Geral dos Sistemas Informatizados em Administrativo >> Suporte >> Depuração de código Pl/Sql.