A generic logger in modern C++
Stop using double underscore.
The double underscore is reserved for the implementation it definitely should not be used in "user code".

See: What are the rules about using an underscore in a C++ identifier?

Recursive template Call.

You use a recursive technique to call the Write() method for all your sinks. I prefer to use the loop technique (I would say this is a more modern approach but I have no reference for that). But I find it clearer as you don't need the empty terminating function call.

private:
    using Tuple=std::tuple&lt;Sinks...&gt;;

    template&lt;std::size_t... index&gt;
    static void writeToLogs(char const* m, std::integer_sequence&lt;std::size_t, index...&gt; const&amp;)
    {
        auto ignore = {(std::get&lt;index&gt;(s_Sinks).Write(m),true)...};
    }

public:
    static void Log(const char* msg)
    {
        writeToLogs(msg, std::make_index_sequence&lt;std::tuple_size&lt;Tuple&gt;::value&gt;());
    }


Design

Everybody and their grandson tends to want to write a logger at some point in time. The trouble is we already have a good logger built into the *nix world (syslog). If you are not using syslog to do your logging you are doing it wrong.

It (syslog) already does everything you need to do and more and there is a whole ecosystem built around it for monitoring. Now there is nothing wrong with writing a wrapper around syslog but you have to be smart about it (the current ones are very smart).

Log(debug, getSomeMessage());


This should not call the function getMessage() if the debugging level is set to production. That would be a complete wast of time and resources as debug messages are currently being ignored.