À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.
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.

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 xSeuRetornoMas você pode acionar também em pontos de entrada ou em outras rotinas, pois ela funciona de forma genérica.
Grande abraço.