O contexto: estamos trabalhando em um aplicativo multithread (Linux-C) que segue um modelo de pipeline.
Cada módulo possui um encadeamento privado e objetos encapsulados que processam dados; e cada estágio possui uma forma padrão de troca de dados com a próxima unidade.
O aplicativo está livre de vazamento de memória e é seguro para threads usando bloqueios no ponto em que eles trocam dados. O número total de threads é de cerca de 15 - e cada thread pode ter de 1 a 4 objetos. Criar cerca de 25 a 30 objetos estranhos, todos com alguns registros críticos a serem feitos.
A maioria das discussões que eu vi sobre diferentes níveis, como no Log4J e em outras traduções. A grande questão é sobre como o registro geral deve realmente acontecer?
Uma abordagem é toda exploração madeireira local faz fprintf
para stderr
. O stderr é redirecionado para algum arquivo. Essa abordagem é muito ruim quando os logs se tornam muito grandes.
Se todos os objetos instanciarem seus loggers individuais - (cerca de 30 a 40 deles), haverá muitos arquivos. E, ao contrário do descrito acima, não se tem a ideia da verdadeira ordem dos eventos. O registro de data e hora é uma possibilidade - mas ainda é uma bagunça para agrupar.
Se houver um único padrão de logger global (singleton) - ele bloqueia indiretamente tantos threads enquanto um está ocupado colocando logs. Isso é inaceitável quando o processamento dos threads é pesado.
Então, qual deve ser a maneira ideal de estruturar os objetos de log? Quais são algumas das melhores práticas em aplicativos reais de larga escala?
Eu também adoraria aprender com alguns dos projetos reais de aplicativos de larga escala para obter inspirações!
======
EDITAR:
Com base nas duas respostas, aqui está a pergunta que me resta agora:
Qual é a melhor prática para atribuir loggers (filas de log) ao objeto: eles devem chamar algum global_api () ou o logger deve ser atribuído a eles no construtor. Quando os objetos estão em uma hierarquia profunda, essa abordagem posterior se torna tediosa. Se eles estão chamando algum global_api (), é meio que um acoplamento com o Aplicativo, portanto, tentar usar esse objeto em outro aplicativo gera essa dependência. Existe uma maneira mais limpa para isso?
fonte
Respostas:
uma maneira aceitável de usar o log singleton que delega o log real para seu próprio encadeamento
você pode usar qualquer solução eficiente produtor / consumidor (como uma lista vinculada sem bloqueio baseada no CaS atômico) para reunir as mensagens de log sem se preocupar com o fato de ser um bloqueio global implícito
a chamada de log irá primeiro filtrar e criar a mensagem de log e depois passá-la para o consumidor, o consumidor pegará e gravará (e liberará os recursos da mensagem individual)
fonte
A resposta de Ratchet Freak é o que inicialmente pensei também.
Um método alternativo pode ser fornecer a cada um dos seus módulos sua própria fila produtor-consumidor e, em seguida, fazer com que o mecanismo do seu logger verifique essas filas em seu próprio encadeamento.
Isso pode acabar sendo mais flexível, porque você pode alternar quantos criadores de logs você usa - você pode ter um para tudo, um para cada módulo ou dividir os módulos em grupos e ter um para cada grupo.
Edit: Elaboração
(não se importe com o meu C - foi o que você disse que está codificando, certo?)
Portanto, essa ideia está tendo uma fila / lista produtor-consumidor para cada um dos seus módulos. Essa fila provavelmente seria algo como isto:
Cada módulo precisará inicializar sua própria fila ou ser passado pelo código de inicialização que configura os encadeamentos etc. O código de inicialização provavelmente deve manter referências a todas as filas:
Dentro dos módulos, você deve criar LogItems e colocá-los na fila para cada mensagem.
Então, você teria um ou mais consumidores das filas que receberiam as mensagens e, na verdade, gravariam o log em um loop principal da seguinte maneira:
ou algo assim.
Isso seria flexível para permitir que você tenha diferentes consumidores das filas, por exemplo:
Nota: Suponho que você deseje alocar a memória para uma mensagem de log no momento da fila e desalocá-la no tempo de consumo (supondo que suas mensagens contenham conteúdo dinâmico).
Outra edição:
Esqueci de mencionar: se você espera muita atividade nos encadeamentos do módulo, poderá ver se é possível fazer gravações de log de forma assíncrona para que as coisas não bloqueiem.
Mais uma edição:
Você provavelmente também desejará colocar um registro de data e hora como parte do LogItem; com o (s) encadeamento (s) do criador de logs passando pelas filas sequencialmente, as instruções de log podem ficar fora de ordem a partir de quando ocorrerem cronologicamente nos módulos.
E ainda outra edição:
Com essa configuração, seria bastante fácil passar todos os módulos pela mesma fila e apenas fazer com que o consumidor olhasse para aquela fila, o que o levaria de volta à resposta do Ratchet Freak.
Nossa, você vai parar de editar!?:
Além disso, você pode ter uma fila para cada grupo de módulos e um criador de logs para cada fila.
Ok, eu vou parar agora.
fonte