No vídeo de hoje, vamos demonstrar em como criar uma tela em AdvPL que mostre um texto de log (similar a ShowLog e MostraErro) mas com número de linhas e opção de pesquisar com Ctrl+F.
A dúvida de hoje, nos perguntaram, se seria possível criar uma tela para visualizar logs de forma mais amigável, com pesquisa e número de linhas.
Pensando nisso, montamos esse exemplo, onde demonstramos em como criar a tela usando recursos de navegação HTML.
Segue abaixo o vídeo exemplificando:
E abaixo o código fonte desenvolvido:
//Bibliotecas
#Include "TOTVS.ch"
/*/{Protheus.doc} zVid0112
Fonte demonstrando em como acionar a zTiLog
@type user function
@author Atilio
@since 25/01/2024
/*/
User Function zVid0112()
Local aArea := FWGetArea()
Local cTexto := ""
Local cQuery := ""
//Primeiro teste, vamos acionar sem nada
u_zTiLog()
//Segundo teste, montando um texto qualquer
cTexto += "O Terminal de Informação nasceu em 2012." + CRLF
cTexto += "De lá para cá, foram vários artigos e conteúdos compartilhados com a comunidade." + CRLF
cTexto += "Agradecemos sempre o carinho e o feedback recebido dos internautas." + CRLF
cTexto += "Um grande abraço!" + CRLF
cTexto += CRLF
cTexto += "Dan"
u_zTiLog(cTexto)
//Terceiro teste, forçando um erro (update em tabela que não existe)
cQuery := " UPDATE TABELA_AAA_BBB_CCC " + CRLF
cQuery += " SET CAMPO_1 = 'ZZ" + Time() + "' " + CRLF
cQuery += " WHERE CAMPO_2 = 'F0001' " + CRLF
If TCSqlExec(cQuery) < 0
cTexto := "Houve uma falha no sistema!" + CRLF + CRLF
cTexto += "Query executada:" + CRLF
cTexto += cQuery + CRLF
cTexto += "Mensagem de erro:" + CRLF + CRLF
cTexto += TCSQLError() + CRLF
u_zTiLog(cTexto)
EndIf
FWRestArea(aArea)
Return
/*/{Protheus.doc} zTiLog
Exemplo de tela para análise de logs com opção como Ctrl+F e número de linhas
@type user function
@author Atilio
@since 25/01/2024
@version version
@param cTextoLog, Caractere, Conteúdo textual que será demonstrado no log
@example
u_zTiLog("beluguinha, belugão, acesse Terminal de Informação")
/*/
User Function zTiLog(cTextoLog)
Local aArea := FWGetArea()
Local oDlgAux
Local cJanTitulo := "Análise de Logs do Sistema"
//Tamanho da janela
Local aTamanho := FwGetDialogSize()
Local nJanLarg := aTamanho[4] / 2
Local nJanAltu := aTamanho[3] / 2
//Blocos de código dos botões
Local bBlocoCopi := {|| fCopiar(cTextoLog)}
Local bBlocoSalv := {|| fSalvar(cTextoLog)}
Local bBlocoFech := {|| oDlgAux:DeActivate()}
//Variáveis dos objetos de navegação de páginas
Local cHtmlText := ""
Local nPort := 0
Local oPanelHtml
Local oWebChannel
Local oWebEngine
//Parâmetros vindos
Default cTextoLog := "Não veio nenhum texto..."
//Cria o HTML base
cHtmlText := fMontaHtml(cTextoLog)
//Instancia a classe, criando uma janela
oDlgAux := FWDialogModal():New()
oDlgAux:SetTitle(cJanTitulo)
oDlgAux:SetSize(nJanAltu, nJanLarg)
oDlgAux:EnableFormBar(.T.)
oDlgAux:CreateDialog()
oDlgAux:CreateFormBar()
oDlgAux:AddButton("Fechar", bBlocoFech, "Fechar", , .T., .F., .T., )
oDlgAux:AddButton("Copiar", bBlocoCopi, "Copiar", , .T., .F., .T., )
oDlgAux:AddButton("Salvar", bBlocoSalv, "Salvar", , .T., .F., .T., )
//Busca o painel principal da dialog
oPanelHtml := oDlgAux:GetPanelMain()
//Prepara o conector WebSocket
oWebChannel := TWebChannel():New()
nPort := oWebChannel::connect()
//Cria componente
oWebEngine := TWebEngine():New(oPanelHtml, 0, 0, 100, 100, , nPort)
oWebEngine:SetHtml(cHtmlText)
oWebEngine:Align := CONTROL_ALIGN_ALLCLIENT
//Abre a janela
oDlgAux:Activate()
FWRestArea(aArea)
Return
//Referência: https://stackoverflow.com/questions/1995370/adding-line-numbers-to-html-textarea
Static Function fMontaHtml(cTexto)
Local cHtml := ""
cHtml += '<html>' + CRLF
cHtml += '<head>' + CRLF
cHtml += ' <meta charset="UTF-8">' + CRLF
cHtml += ' <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.js"></script>' + CRLF
cHtml += ' <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/perl/perl.min.js"></script>' + CRLF
cHtml += ' <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.css"></link>' + CRLF
cHtml += ' <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/theme/abbott.min.css"></link>' + CRLF
cHtml += '' + CRLF
cHtml += ' <style>' + CRLF
cHtml += ' .CodeMirror {' + CRLF
cHtml += ' width: 100%;' + CRLF
cHtml += ' height: 90%;' + CRLF
cHtml += ' border: 1px #000 solid;' + CRLF
cHtml += ' border-radius: 8px;' + CRLF
cHtml += ' }' + CRLF
cHtml += ' </style>' + CRLF
cHtml += '</head>' + CRLF
cHtml += '<body>' + CRLF
cHtml += '' + CRLF
cHtml += ' <textarea id="code" name="code" wrap="hard" readonly>' + cTexto + '</textarea>' + CRLF
cHtml += ' <p><font color="red">Observação:</font> Para pesquisar, clique em alguma parte do texto e pressione <strong>Ctrl+F</strong></p>' + CRLF
cHtml += '' + CRLF
cHtml += ' <script>' + CRLF
cHtml += ' var editor = CodeMirror.fromTextArea(document.getElementById("code"), {' + CRLF
cHtml += ' lineNumbers: true,' + CRLF
cHtml += ' lineWrapping: true,' + CRLF
cHtml += ' mode: "text",' + CRLF
cHtml += ' theme: "",' + CRLF
cHtml += ' });' + CRLF
cHtml += ' </script>' + CRLF
cHtml += '</body>' + CRLF
cHtml += '</html>' + CRLF
Return cHtml
Static Function fSalvar(cTexto)
Local cTipArq := "Arquivos texto (*.txt) | Arquivos de log (*.log)"
Local cTitulo := "Gravação de arquivo"
Local cDirIni := GetTempPath()
Local lSalvar := .T.
Local cArqSel := ""
//Aciona a tela para gravar o arquivo
cArqSel := tFileDialog(;
cTipArq,; // Filtragem de tipos de arquivos que serão selecionados
cTitulo,; // Título da Janela para seleção dos arquivos
,; // Compatibilidade
cDirIni,; // Diretório inicial da busca de arquivos
lSalvar,; // Se for .T., será uma Save Dialog, senão será Open Dialog
; // Se não passar parâmetro, irá pegar apenas 1 arquivo; Se for informado GETF_MULTISELECT será possível pegar mais de 1 arquivo; Se for informado GETF_RETDIRECTORY será possível selecionar o diretório
)
//Efetua a gravação do arquivo
If ! Empty(cArqSel)
MemoWrite(cArqSel, cTexto)
EndIf
Return
Static Function fCopiar(cTexto)
//Copia o texto para a área de transferência em memória (similar a selecionar tudo e apertar Ctrl+C)
CopyToClipBoard(cTexto)
FWAlertSuccess("Texto copiado para área de transferência, agora basta você usar o atalho Ctrl+V para colar onde você deseja.", "Sucesso")
Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.