Definitivamente, você pode dedicar muito tempo à engenharia deste problema.
Para idiomas com implementações de log canônico, instancie o logon canônico diretamente em todas as classes.
Para idiomas sem uma implementação canônica, tente encontrar uma estrutura de fachada de log e atenha-se a ela. slf4j é uma boa escolha em Java.
Pessoalmente, prefiro manter uma única implementação concreta de log e enviar tudo para o syslog. Todas as boas ferramentas de análise de log são capazes de combinar logs de sysout de vários servidores de aplicativos em um relatório abrangente.
Quando uma assinatura de função inclui um ou dois serviços de dependência, além de alguns argumentos "reais", coloco as dependências por último:
int calculateFooBarSum(int foo, int bar, IntegerSummationService svc)
Como meus sistemas tendem a ter apenas cinco ou menos desses serviços, sempre asseguro que os serviços sejam incluídos na mesma ordem em todas as assinaturas de funções. A ordem alfabética é tão boa quanto qualquer outra. (Além disso: a manutenção dessa abordagem metodológica para o manuseio de mutex também reduzirá suas chances de desenvolver impasses.)
Se você estiver injetando mais de uma dúzia de dependências em seu aplicativo, o sistema provavelmente precisará ser dividido em subsistemas separados (ouso dizer microsserviços?).