Como gerar um log de todas as tabelas abertas em memória

Às vezes precisamos criar um log para saber as tabelas que estavam abertas e em quais registros estavam, hoje iremos demonstrar em como fazer isso.

Existem alguns processos no sistema, que acabam rodando e para rastrearmos algo, fica um pouco oneroso, como por exemplo, o da contabilização.

Então pensando nisso, como poderíamos gravar um log genérico, para saber em quais tabelas o sistema esta posicionado? A lógica seria:

  • Na CT5, no campo desejado, colocar uma fórmula, por exemplo, u_zSuaFuncao()
  • Dentro dessa função, acionar a chamada de uma rotina que irá gerar o log, por exemplo, MemoWrite(cPastaNoServidor, u_zLogAlias(1))
  • Na função zLogAlias, pegue o conteúdo da variável pública cFOpened
  • Faça um For, percorrendo até 511 alias (conforme documentação do TDN: https://tdn.totvs.com/display/tec/Alias)
  • Através do comando Select() verifique se o alias está aberto
  • Se sim, grave o conteúdo no log com o nome do alias e o recno posicionado (também com o índice usado e o conteúdo do índice)

Abaixo a função zLogAlias desenvolvida conforme a lógica acima (ela também foi adaptada para retornar um array, caso precisem):

//Bibliotecas
#Include "TOTVS.ch"
   
/*/{Protheus.doc} User Function zLogAlias
Função que percorre todos os alias em memória para gravar em log
@type  Function
@author Atilio
@since 02/06/2022
@param nTipo, Numérico, Se for 1 irá retornar um texto de log e se não for irá retornar um array
@obs Posições do array:
 [1] = Tabela (ex.: SB1)
 [2] = RecNo (ex.: 1342)
 [3] = Índice usado (ex.: 1)
 [4] = Campos que compõem o índice (ex.: B1_FILIAL + B1_COD)
 [5] = Chave do registro posicionado (ex.: '  000001')
/*/
   
User Function zLogAlias(nTipo)
    Local aArea      := FWGetArea()
    Local cAbertos   := cFOpened
    Local nAtual     := 0
    Local xLog       := Nil
    Local cAliasAtu  := ""
    Local nAliasRec  := 0
    Local nIndUsado  := 0
    Local cIndCampos := ""
    Local cIndChave  := ""
    Local nMaximo    := 511
    Default nTipo    := 1
   
    If nTipo == 1
        xLog := "Alias abertos (cFOpened): " + cAbertos + CRLF + CRLF
        xLog += "Alias encontrados na WorkArea: " + CRLF
    Else
        xLog := {}
    EndIf
   
    //Percorre 511 alias (conforme documentação em https://tdn.totvs.com/display/tec/Alias)
    For nAtual := 0 To nMaximo
        //Pega o alias da area atual
        cAliasAtu := Upper(Alias(nAtual))
   
        //Somente se houver alias e Garantia para prevenir se realmente ta aberto, para não confiar apenas na variável pública
        If ! Empty(cAliasAtu) .And. Select(cAliasAtu) > 0
            nIndUsado  := (cAliasAtu)->(IndexOrd())
            cIndCampos := StrTran((cAliasAtu)->(IndexKey(nIndUsado)), "+", " + ")
            cIndChave  := (cAliasAtu)->( &(cIndCampos) )
            nAliasRec  := (cAliasAtu)->(RecNo())
   
            //Pula o registro caso seja tabelas internas
            If Left(cAliasAtu, 3) == "MP_" .Or. ;
               Left(cAliasAtu, 6) == "MPUSR_" .Or. ;
               Left(cAliasAtu, 7) == "MPMENU_" .Or. ;
               Left(cAliasAtu, 6) == "MPGRP_" .Or. ;
               Left(cAliasAtu, 1) == "X" .Or. ;
               Left(cAliasAtu, 4) == "TPH_" .Or. ;
               Left(cAliasAtu, 9) == "PROFALIAS"
                Loop
            EndIf
   
            If nTipo == 1
                xLog += "Tabela: " + cAliasAtu + ;
                "; Recno: " + cValToChar(nAliasRec) + ;
                "; Ordem: " + cValToChar(nIndUsado) +;
                "; Índice: " + cIndCampos +;
                "; Chave: '" + cIndChave + "'" +;
                CRLF
            Else
                aAdd(xLog, {;
                    cAliasAtu,;
                    nAliasRec,;
                    nIndUsado,;
                    cIndCampos,;
                    cIndChave;
                })
            EndIf
        EndIf
    Next
   
    FWRestArea(aArea)
Return xLog

Abaixo um print de como é o resultado, por exemplo, acionando na tela de cadastro de produtos.

Exemplo de tela com as tabelas e índices

Uma dica interessante, seria aproveitar a ideia do Canivete de Atalhos, e adicionar essa função em um atalho para já exibir em tela as tabelas abertas, conforme exemplo abaixo:

SetKey(K_SH_F12, { || ShowLog(u_zLogAlias()) })

Bom pessoal, por hoje é só.

Abraços e até a próxima.

Dan (Daniel Atilio)
Cristão de ramificação protestante. Especialista em Engenharia de Software pela FIB, graduado em Banco de Dados pela FATEC Bauru e técnico em informática pelo CTI da Unesp. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor e mantenedor do portal Terminal de Informação.

2 Responses

  1. Klaus Schneider Peres disse:

    Bom dia Daniel, só uma observação, como ainda não executei seu exemplo, não sei se há relevância, mas no TDN sobre o comando Alias(), ele vai de 0 (zero) até 511, mas no seu fonte, você inicia de 1, então a posição 0 (zero) nunca será pesquisada. Também não entendi onde deve ser colocada a função. Seria no campo X2_ROTINA da CT5 ou em algum ponto de entrada?

    • Bom dia Klaus, tudo joia?
      Opa, obrigado pelo aviso, já atualizei o exemplo para começar com 0 ao invés de 1.
      Quanto ao exemplo, vamos supor que dentro de um registro seu da CT5, no campo CT5_DEBITO tem a função u_zDebito(). Ai dentro dessa função, você adicionaria o comando para ver as tabelas que estão na memória, por exemplo:

      User Function zDebito()
      
         /* aqui os comandos da sua função */
      
         //Ai aciona a função para gravar as tabelas que estão na memória em um log dentro da Protheus Data
         MemoWrite("\x_pasta\arquivo_log_ct5_debito.txt", u_zLogAlias(1))
      Return xSeuRetorno
      

      Mas você pode acionar também em pontos de entrada ou em outras rotinas, pois ela funciona de forma genérica.

      Grande abraço.

Deixe uma resposta para Dan (Daniel Atilio)Cancelar resposta

Terminal de Informação