Nesta primeira parte estou levando em conta a mesma pergunta que vc fez no Stack Overflow…
Faltou uma coisa importante: um exemplo de como exatamente estão os arquivos.
E aí pra testar eu tive que “adivinhar”, criei dois arquivos assim para testes:
arquivo-1.log
:
2022/01/31 07:15:17 - Extração Tabela.0 - ERROR (version 7.1.0.0-12, build 1 from 2017-05-16 17.18.02 by buildguy) : An error occurred, processing will be stopped:
detalhe
mais detalhes
e mais
2022/01/31 07:15:17 - Extração Tabela.0 - Error occurred while trying to connect to the database
nao vi nada
sei la
sai daqui
arquivo-2.log
:
2022/01/31 08:15:17 - Extração Tabela.1 - Error occurred while trying to connect to the database
detalhe do erro
outro detalhe
Eu entendi que as linhas que começam com uma data são as mensagens de erro, e as outras são detalhes do erro. É isso mesmo? Ou as 3 linhas que vêm depois do erro também têm a data?
Enfim, eu fiz baseado no arquivo acima, mas se o formato for outro, basta adaptar:
from glob import glob
from datetime import date
# abre o arquivo de saída apenas uma vez (afinal, todo mundo vai escrever nele, não tem porque ficar abrindo toda hora)
with open(f'error_{date.today()}.txt', 'w') as saida:
# i é o contador do arquivo
for i, file in enumerate(glob('jobs/*.*'), start=1):
erro = 0 # contador do erro dentro de um arquivo, por isso zera a cada novo arquivo
with open(file, 'r') as arquivo:
for linha in arquivo:
if 'error' in linha.lower():
erro += 1
data = linha[0:19]
msg = linha[22:]
msg_count = 0 # contador de mensagens relativas a este erro (zera a cada novo erro)
saida.write(f'{i}.{erro} - {file} {data} - {msg}')
else: # se não é erro, então é uma das linhas de detalhe
msg_count += 1
saida.write(f'{i}.{erro}.{msg_count} - {linha}')
Repare que há 3 contadores independentes. O i
é o contador do arquivo, e como esse contador itera junto com os arquivos, posso usar um enumerate
no glob
. Já os outros (do erro dentro de um arquivo, e da mensagem de cada erro), tem que ser independente, já que depende das condições (se tem “error” na linha ou não). O resultado ficou assim:
1.1 - jobs/arquivo-1.log 2022/01/31 07:15:17 - Extração Tabela.0 - ERROR (version 7.1.0.0-12, build 1 from 2017-05-16 17.18.02 by buildguy) : An error occurred, processing will be stopped:
1.1.1 - detalhe
1.1.2 - mais detalhes
1.1.3 - e mais
1.2 - jobs/arquivo-1.log 2022/01/31 07:15:17 - Extração Tabela.0 - Error occurred while trying to connect to the database
1.2.1 - nao vi nada
1.2.2 - sei la
1.2.3 - sai daqui
2.1 - jobs/arquivo-2.log 2022/01/31 08:15:17 - Extração Tabela.1 - Error occurred while trying to connect to the database
2.1.1 - detalhe do erro
2.1.2 - outro detalhe
Agora, outra forma que eu entendi que talvez quem sabe possa ser, é que os arquivos estejam assim:
arquivo-1.log
:
2022/01/31 07:15:17 - Extração Tabela.0 - ERROR (version 7.1.0.0-12, build 1 from 2017-05-16 17.18.02 by buildguy) : An error occurred, processing will be stopped:
2022/01/31 07:15:17 - Extração Tabela.0 - Error occurred while trying to connect to the database
arquivo-2.log
:
2022/01/31 08:15:17 - Extração Tabela.1 - Error occurred while trying to connect to the database
E cada trecho da linha é uma mensagem diferente (por exemplo, separados por hífen). Ou seja, para a linha acima, a mensagem “Extração Tabela.1” é o erro, e “Error occurred while etc…” são os detalhes. Neste caso poderia ser:
from glob import glob
from datetime import date
with open(f'error_{date.today()}.txt', 'w') as saida:
# i é o contador do arquivo
for i, file in enumerate(glob('jobs/*.*'), start=1):
erro = 0 # contador do erro dentro de um arquivo, por isso zera a cada novo arquivo
with open(file, 'r') as arquivo:
for linha in arquivo:
# quebra a linha em partes
data, msg, *detalhes = linha.strip().split(' - ')
erro += 1
saida.write(f'{i}.{erro} - {file} {data} - {msg}\n')
for msg_count, detalhe in enumerate(detalhes, start=1):
saida.write(f'{i}.{erro}.{msg_count} - {detalhe}\n')
E o resultado ficaria:
1.1 - jobs/arquivo-1.log 2022/01/31 07:15:17 - Extração Tabela.0
1.1.1 - ERROR (version 7.1.0.0-12, build 1 from 2017-05-16 17.18.02 by buildguy) : An error occurred, processing will be stopped:
1.2 - jobs/arquivo-1.log 2022/01/31 07:15:17 - Extração Tabela.0
1.2.1 - Error occurred while trying to connect to the database
2.1 - jobs/arquivo-2.log 2022/01/31 08:15:17 - Extração Tabela.1
2.1.1 - Error occurred while trying to connect to the database
Outra abordagem
Se o formato do arquivo for diferente disso, ou se você quer outro formato no resultado, melhor informar com mais detalhes (coloque várias linhas do mesmo arquivo, por exemplo, e como deveria ser a respectiva saída - de preferência como texto, pois o link com as imagens está bem lento pra mim). Sem contar que com texto é mais fácil a gente copiar e criar um arquivo para testes.
Por exemplo, lendo a pergunta de novo, dá a entender que talvez você queira o número da linha em que o erro ocorreu. Se for isso, poderia gravar apenas a linha e o arquivo, sem precisar dessa numeração mais complicada.
Assumindo que todas as linhas têm data e cada linha é uma mensagem, seria algo assim:
from glob import glob
from datetime import date
with open(f'error_{date.today()}.txt', 'w') as saida:
for nome_arquivo in glob('jobs/*.*'):
with open(nome_arquivo, 'r') as arquivo:
for numero_linha, linha in enumerate(arquivo, start=1):
saida.write(f'{numero_linha} - {nome_arquivo} - {linha}')
E aí ficaria:
1 - jobs/arquivo-1.log - 2022/01/31 07:15:17 - Extração Tabela.0 - ERROR (version 7.1.0.0-12, build 1 from 2017-05-16 17.18.02 by buildguy) : An error occurred, processing will be stopped:
2 - jobs/arquivo-1.log - 2022/01/31 07:15:17 - Extração Tabela.0 - Error occurred while trying to connect to the database
1 - jobs/arquivo-2.log - 2022/01/31 08:15:17 - Extração Tabela.1 - Error occurred while trying to connect to the database
Ou seja, nas linhas 1 e 2 do arquivo 1, e na linha 1 do arquivo 2, ocorreram erros.
Ou ainda, se a mensagem do erro é “tudo que vem depois da data”:
from glob import glob
from datetime import date
with open(f'error_{date.today()}.txt', 'w') as saida:
for i, file in enumerate(sorted(glob('jobs/*.*')), start=1):
with open(file, 'r') as arquivo:
for erro, linha in enumerate(arquivo, start=1):
data, msg = linha.split(' - ', maxsplit=1)
saida.write(f'{i} - {file}\n')
saida.write(f'{i}.{erro} - {data} - {msg}')
E o resultado é:
1 - jobs/arquivo-1.log
1.1 - 2022/01/31 07:15:17 - Extração Tabela.0 - ERROR (version 7.1.0.0-12, build 1 from 2017-05-16 17.18.02 by buildguy) : An error occurred, processing will be stopped:
1 - jobs/arquivo-1.log
1.2 - 2022/01/31 07:15:17 - Extração Tabela.0 - Error occurred while trying to connect to the database
2 - jobs/arquivo-2.log
2.1 - 2022/01/31 08:15:17 - Extração Tabela.1 - Error occurred while trying to connect to the database