std.experimental.logger formal review round 3

Robert burner Schadek via Digitalmars-d digitalmars-d at puremagic.com
Wed Oct 29 16:11:42 PDT 2014


On Tuesday, 28 October 2014 at 22:03:18 UTC, Martin Nowak wrote:
> On 10/28/2014 07:22 PM, Martin Nowak wrote:
>> On Tuesday, 28 October 2014 at 12:02:16 UTC, Robert burner 
>> Schadek wrote:
>>> It is a design goal to disable certain LogLevel at CT of a 
>>> compile
>>> unit (CU).
>>> e.g. make all logs to trace function template do nothing
>>
>> One idea to make this working is to use prefixed version 
>> identifiers.
>> Obviously this is all boilerplate so it could be done in a 
>> mixin
>> template in std.log.
>
> 2nd iteration of that idea.
>
> cat > main.d << CODE
> import std_logger;
>
> LoggerCT!"MyApp" appLogger = new StdoutLogger(LogLevel.info);
> LoggerCT!"MyLib" libLogger = new StdoutLogger(LogLevel.trace);
>
> void main()
> {
>     appLogger.log!(LogLevel.info)("app");
>     appLogger.log!(LogLevel.warning)("app");
>     libLogger.log!(LogLevel.info)("lib");
>     libLogger.log!(LogLevel.warning)("lib");
>
>     Logger rtLogger = appLogger;
>     rtLogger.log!(LogLevel.info)("rt");
>     rtLogger.log!(LogLevel.warning)("rt");
> }
> CODE
>
> cat > std_logger.d << CODE
> enum LogLevel { all, info, trace, warning, error, none }
>
> template minLogLevel(string prefix)
> {
>     mixin("
>     version ("~prefix~"LogAll)
>         enum minLogLevel = LogLevel.all;
>     else version ("~prefix~"LogInfo)
>         enum minLogLevel = LogLevel.info;
>     else version ("~prefix~"LogTrace)
>         enum minLogLevel = LogLevel.trace;
>     else version ("~prefix~"LogWarning)
>         enum minLogLevel = LogLevel.warning;
>     else version ("~prefix~"LogError)
>         enum minLogLevel = LogLevel.error;
>     else version ("~prefix~"LogNone)
>         enum minLogLevel = LogLevel.none;
>     else
>         enum minLogLevel = LogLevel.all;
>     ");
> }
>
> interface Logger
> {
>     @property LogLevel logLevel();
>     void write(LogLevel ll, string msg);
> }
>
> class StdoutLogger : Logger
> {
>     this(LogLevel l) { _logLevel = l; }
>     LogLevel _logLevel;
>     @property LogLevel logLevel() { return _logLevel; }
>     void write(LogLevel ll, string msg) { import std.stdio; 
> writeln(ll, ": ", msg); }
> }
>
> /// used for library/app specific version prefixes
> struct LoggerCT(string prefix)
> {
>     this(Logger logger) { impl = logger; }
>     enum versionPrefix = prefix;
>     Logger impl;
>     alias impl this;
> }
>
> void log(LogLevel ll)(Logger logger, string msg)
> {
>     if (ll >= logger.logLevel) // runtime check
>         logger.write(ll, msg);
> }
>
> /// when using a logger with prefix
> void log(LogLevel ll, L:LoggerCT!pfx, string pfx)(auto ref L 
> logger, string msg)
>     if (ll < minLogLevel!pfx)
> {
> }
>
> void log(LogLevel ll, L:LoggerCT!pfx, string pfx)(auto ref L 
> logger, string msg)
>     if (ll >= minLogLevel!pfx)
> {
>     if (ll >= logger.logLevel) // additional runtime check, 
> because logger might require a higher log level
>         logger.write(ll, msg);
> }
> CODE
>
> dmd std_logger -run main
>
> dmd -version=MyAppLogWarning std_logger.d -run main
> dmd -version=MyAppLogError -version=MyLibLogNone std_logger.d 
> -run main

That can actually be added to the current state of std.logger 
without breaking any api. The string mixin, version string 
matching isn't really pretty, but it gets the job done. Anyway 
IMO your approach presented here and my approach can go hand in 
hang. Yours should be propagated as the idiomatic way and if you 
really need the crowbar, which you need sometimes, use 
StdLoggerDisableXXXXX.


More information about the Digitalmars-d mailing list