コード例 #1
0
        /** ********************************************************************************************
         *  Parses the #Format string and logs meta information into the log buffer. For each
         *  variable found, method #processVariable is invoked. Hence, to add new variables,
         *  the latter method can be overwritten by descendants. Overwriting this method is
         *  recommended for formatter classes that do not rely on format strings.
         * @param logger    The logger that we are embedded in.
         * @param buffer    The buffer to write meta information into.
         * @param domain    The <em>Log Domain</em>.
         * @param verbosity The verbosity. This has been checked to be active already on this
         *                  stage and is provided to be able to be logged out only.
         * @param scope     Information about the scope of the <em>Log Statement</em>..
         *
         * @return The number of tab sequences that were written (by adding ESC::TAB to the buffer).
         **********************************************************************************************/
        public virtual int Write(TextLogger logger, AString buffer, Domain domain, Verbosity verbosity, ScopeInfo scope)
        {
            int qtyTabStops = 0;

            // check
            if (Format == null || Format.IsEmpty())
            {
                return(0);
            }

            // clear DateTime singleton
            callerDateTime = null;

            // loop/switch over content specified in configuration array
            tTok.Set(Format, '%');

            while (true)
            {
                // get next and log substring between commands
                if (tTok.Next(Whitespaces.Keep).IsNotEmpty())
                {
                    buffer._(tTok.Actual);
                }

                // previous next did not find a delimiter
                if (!tTok.HasNext())
                {
                    break;
                }

                // process the found variable
                qtyTabStops += processVariable(logger, domain, verbosity, scope, buffer, tTok.Rest);
            }

            return(qtyTabStops);
        }
コード例 #2
0
        /** ********************************************************************************************
         *  Processes the next command found in the format string, by writing formatted information
         *  into the given buffer.
         *  The given Substring holds the next command. When method returns, the command is cut
         *  from the front.
         *
         * @param logger    The logger that we are embedded in.
         * @param domain    The <em>Log Domain</em>.
         * @param verbosity The verbosity. This has been checked to be active already on this
         *                  stage and is provided to be able to be logged out only.
         * @param scope     Information about the scope of the <em>Log Statement</em>..
         * @param dest      The buffer to write meta information into.
         * @param variable  The variable to read (may have more characters appended)
         *
         * @return The number of tab sequences that were written (by adding ESC::TAB to the buffer).
         **********************************************************************************************/
        protected virtual int processVariable(TextLogger logger, Domain domain, Verbosity verbosity,
                                              ScopeInfo scope, AString dest, Substring variable)
        {
            // process commands
            char c2;

            switch (variable.Consume())
            {
            // scope info
            case 'S':
            {
                // read sub command
                AString val;
                switch (c2 = variable.Consume())
                {
                case 'P':       // SP: full path
                {
                    int    length;
                    String path = scope.GetFullPath(out length);
                    if (length > 0)
                    {
                        dest._(path, 0, length);
                        return(0);
                    }
                    val = NoSourceFileInfo;
                } break;

                case 'p':       // Sp: trimmed path
                {
                    val = scope.GetTrimmedPath();
                    if (val.IsEmpty())
                    {
                        val = NoSourceFileInfo;
                    }
                } break;

                case 'F':       // file name
                {
                    val = scope.GetFileName();
                    if (val.IsEmpty())
                    {
                        val = NoSourceFileInfo;
                    }
                } break;

                case 'f':       // file name without extension
                {
                    val = scope.GetFileNameWithoutExtension();
                    if (val.IsEmpty())
                    {
                        val = NoSourceFileInfo;
                    }
                } break;


                case 'M':       // method name
                {
                    String method = scope.GetMethod();
                    if (method.Length == 0)
                    {
                        dest._(NoMethodInfo);
                    }
                    else
                    {
                        dest._(method);
                    }
                    return(0);
                }

                case 'L':      // line number
                {
                    dest._(scope.GetLineNumber());
                    return(0);
                }

                default:
                {
                    if (!warnedOnce)
                    {
                        warnedOnce = true;
                        ALIB.WARNING("Unknown format variable '%S" + c2 + "\' (only one warning)");
                    }
                    dest._("%ERROR");
                    return(0);
                }
                }
                dest._(val);
                return(0);
            }

            // %Tx: Time
            case 'T':
            {
                // read sub command
                c2 = variable.Consume();

                // %TD: Date
                if (c2 == 'D')
                {
                    // get time stamp as DateTime once
                    if (callerDateTime == null)
                    {
                        callerDateTime = scope.GetTimeStamp().InDotNetDateTime();
                    }

                    // avoid the allocation of a) a StringBuilder (yes, a string builder is allocated inside StringBuilder.AppendFormat!)
                    // and b) a DateTime object, if the format is the unchanged standard. And it is faster anyhow.
                    if (DateFormat.Equals("yyyy-MM-dd"))
                    {
                        dest._(callerDateTime.Value.Year, 4)._('-')
                        ._(callerDateTime.Value.Month, 2)._('-')
                        ._(callerDateTime.Value.Day, 2);
                    }

                    // support user defined standards
                    else
                    {
                        // detect changes of format string since last log
                        if (detectDateFormatChanges != DateFormat)
                        {
                            detectDateFormatChanges = DateFormat;
                            dateFormatString        = "{0:" + DateFormat + "}";
                        }

                        // get date string from system and append to log buffer
                        formatSB.Clear();
                        formatSB.AppendFormat(CultureInfo.InvariantCulture, dateFormatString, callerDateTime);
                        dest._(formatSB);
                    }
                }

                // %TT: Time of Day
                else if (c2 == 'T')
                {
                    // get time stamp as DateTime once
                    if (callerDateTime == null)
                    {
                        callerDateTime = scope.GetTimeStamp().InDotNetDateTime();
                    }

                    // avoid the allocation of a) a StringBuilder (yes, a string builder is allocated inside StringBuilder.AppendFormat!)
                    // and b) a DateTime object, if the format is the unchanged standard. And it is faster anyhow.
                    if (TimeOfDayFormat.Equals("HH:mm:ss"))
                    {
                        dest._(callerDateTime.Value.Hour, 2)._(':')
                        ._(callerDateTime.Value.Minute, 2)._(':')
                        ._(callerDateTime.Value.Second, 2);
                    }

                    // support user defined standards
                    else
                    {
                        // detect changes of format string since last log
                        if (detectTimeOfDayFormatChanges != TimeOfDayFormat)
                        {
                            detectTimeOfDayFormatChanges = TimeOfDayFormat;
                            timeOfDayFormatString        = "{0:" + TimeOfDayFormat + "}";
                        }

                        // get time string from system and append to log buffer
                        formatSB.Clear();
                        formatSB.AppendFormat(CultureInfo.InvariantCulture, timeOfDayFormatString, callerDateTime);
                        dest._(formatSB);
                    }
                }

                // %TC: Time elapsed since created
                else if (c2 == 'C')
                {
                    // create TimeSpan object (on the stack by using new! :)
                    TimeSpan elapsed = new TimeSpan(scope.GetTimeStamp().Raw() - logger.TimeOfCreation.Raw());

                    if (elapsed.Days > 0)
                    {
                        dest._(elapsed.Days)._(TimeElapsedDays);
                    }

                    if (elapsed.Hours > 0)
                    {
                        dest._(elapsed.Hours)._(':');
                    }

                    dest._(elapsed.Minutes, 2)._(':')
                    ._(elapsed.Seconds, 2)._('.')
                    ._(elapsed.Milliseconds, 3);
                }

                // %TL: Time elapsed since last log call
                else if (c2 == 'L')
                {
                    writeTimeDiff(dest, scope.GetTimeStamp().Since(logger.TimeOfLastLog).InNanos());
                }

                else
                {
                    if (!warnedOnce)
                    {
                        warnedOnce = true;
                        ALIB.WARNING("Unknown format variable '%T" + c2 + "\' (only one warning)");
                    }
                    dest._("%ERROR");
                }
                return(0);
            }


            // thread name / ID
            case 't':
            {
                c2 = variable.Consume();

                if (c2 == 'N')
                {
                    dest.Field()
                    ._(scope.GetThreadName())
                    .Field(logger.AutoSizes.Next(scope.GetThreadName().Length(), 0), Alignment.Center);
                }
                else if (c2 == 'I')
                {
                    tmpAString._()._(scope.GetThreadID());
                    dest.Field()
                    ._(tmpAString)
                    .Field(logger.AutoSizes.Next(tmpAString.Length(), 0), Alignment.Center);
                }
                else
                {
                    if (!warnedOnce)
                    {
                        warnedOnce = true;
                        ALIB.WARNING("Unknown format variable '%t" + c2 + "\' (only one warning)");
                    }
                    dest._("%ERROR");
                }
                return(0);
            }

            case 'L':
            {
                c2 = variable.Consume();
                if (c2 == 'G')
                {
                    dest._NC(logger.GetName());
                }
                else if (c2 == 'X')
                {
                    dest._NC(scope.GetLoxName());
                }
                else
                {
                    if (!warnedOnce)
                    {
                        warnedOnce = true;
                        ALIB.WARNING("Unknown format variable '%L" + c2 + "\' (only one warning)");
                    }
                    dest._("%ERROR");
                    return(0);
                }
                return(0);
            }

            case 'P':
            {
                dest._NC(Util.GetProcessName());
                return(0);
            }

            case 'V':   dest._(verbosity == Verbosity.Error    ? VerbosityError
                                  : verbosity == Verbosity.Warning  ? VerbosityWarning
                                  : verbosity == Verbosity.Info     ? VerbosityInfo
                                  :                               VerbosityVerbose);
                return(0);

            case 'D':
            {
                dest.Field()._(domain.FullPath).Field(logger.AutoSizes.Next(domain.FullPath.Length(), 0), Alignment.Left);
                return(0);
            }

            case '#':    dest._(logger.CntLogs, LogNumberMinDigits);
                return(0);

            // A: Auto tab
            case 'A':
            {
                // read extra space from format string
                int oldStart = variable.Start;
                int extraSpace;  variable.ConsumeInteger(out extraSpace);
                if (oldStart == variable.Start)
                {
                    extraSpace = 1;
                }

                // insert ESC code to jump to next tab level
                extraSpace = Math.Min(extraSpace, 10 + ('Z' - 'A'));
                char escNo = extraSpace < 10 ?   (char)('0' + extraSpace)
                                            :   (char)('A' + extraSpace);

                dest._("\x1Bt")._(escNo);
                return(1);
            }

            default:
            {
                if (!warnedOnce)
                {
                    warnedOnce = true;
                    ALIB.WARNING("Unknown format variable \'" + variable.Buf[variable.Start - 1] + "\'");
                }
                dest._("%ERROR");
            }
                return(0);
            }
        }
コード例 #3
0
ファイル: Log.cs プロジェクト: AlexWorx/ALox-Logging-Library
 public static void Reset()
 {
     #if ALOX_DBG_LOG
         if ( Log.DebugLogger != null )
             Log.RemoveDebugLogger();
         if ( Log.LOX != null )
             ALox.Register( Log.LOX, ContainerOp.Remove );
         Log.LOX= new Lox("Log", true );
         Log.ClearSourcePathTrimRules( Reach.Global, true );
         Log.DebugLogger= null;
         Log.IDELogger  = null;
         ALox.ConfigCategoryName._()._( "ALOX" );
     #endif
 }
コード例 #4
0
ファイル: Log.cs プロジェクト: AlexWorx/ALox-Logging-Library
        public static void RemoveDebugLogger( Lox lox= null,
        [CallerLineNumber] int cln= 0,[CallerFilePath] String csf="",[CallerMemberName] String cmn="" )
        {
            #if ALOX_DBG_LOG
                // replace the report writer (if we replaced it before)
                Log.RemoveALibReportWriter();

                // remove debug logger(s)
                ALIB.ASSERT_WARNING( DebugLogger != null, "No debug logger to remove." );

                if ( lox == null )
                    lox= LOX;

                if ( DebugLogger != null )
                {
                    lox.RemoveLogger( DebugLogger,  cln,csf,cmn );
                    DebugLogger= null;
                }

                if ( IDELogger != null )
                {
                    lox.RemoveLogger( IDELogger,  cln,csf,cmn );
                    IDELogger= null;
                }

            #endif
        }
コード例 #5
0
ファイル: Log.cs プロジェクト: AlexWorx/ALox-Logging-Library
        public static void AddDebugLogger( Lox lox= null,
        [CallerLineNumber] int cln= 0,[CallerFilePath] String csf="",[CallerMemberName] String cmn="" )
        {
            #if ALOX_DBG_LOG

                if ( lox == null )
                    lox= LOX;

                ALIB.ASSERT_ERROR( DebugLogger == null, "Illeagal repeated invocation." );

                // add a CLR logger if this a debug session
                if( System.Diagnostics.Debugger.IsAttached )
                {
                    Variable variable= new Variable(ALox.NO_IDE_LOGGER);
                    variable.Load();
                    if( !variable.IsTrue() )
                    {
                        IDELogger= new CLRDebuggerLogger( "IDE_LOGGER" );

                        // add logger
                        lox.SetVerbosity( IDELogger  , Verbosity.Verbose, "/"                 , Configuration.PrioDefault ,cln,csf,cmn );
                        lox.SetVerbosity( IDELogger  , Verbosity.Warning, ALox.InternalDomains, Configuration.PrioDefault ,cln,csf,cmn );
                    }
                }

                // add a default console logger
                DebugLogger= Lox.CreateConsoleLogger("DEBUG_LOGGER");

                lox.SetVerbosity( DebugLogger, Verbosity.Verbose, "/"                 , Configuration.PrioDefault ,cln,csf,cmn );
                lox.SetVerbosity( DebugLogger, Verbosity.Warning, ALox.InternalDomains, Configuration.PrioDefault ,cln,csf,cmn );

                // replace the ReportWriter
                Log.AddALibReportWriter( lox );

            #endif
        }
コード例 #6
0
    /** ********************************************************************************************
     *  Processes the next command found in the format string, by writing formatted information
     *  into the given buffer.
     *  The given Substring holds the next command. When method returns, the command is cut
     *  from the front.
     *
     * @param logger    The logger that we are embedded in.
     * @param domain    The <em>Log Domain</em>.
     * @param verbosity The verbosity. This has been checked to be active already on this
     *                  stage and is provided to be able to be logged out only.
     * @param scope     Information about the scope of the <em>Log Statement</em>..
     * @param dest      The buffer to write meta information into.
     * @param variable  The variable to read (may have more characters appended)
     *
     * @return The number of tab sequences that were written (by adding ESC::TAB to the buffer).
     **********************************************************************************************/
    protected virtual int processVariable( TextLogger logger, Domain  domain, Verbosity verbosity,
                                           ScopeInfo  scope,  AString dest,   Substring variable )
    {
        // process commands
        char c2;
        switch ( variable.Consume() )
        {
            // scope info
            case 'S':
            {
                    // read sub command
                AString val;
                switch( c2= variable.Consume() )
                {
                    case 'P':   // SP: full path
                    {
                        int    length;
                        String path= scope.GetFullPath( out length );
                        if ( length > 0 )
                        {
                            dest._( path, 0, length );
                            return 0;
                        }
                        val= NoSourceFileInfo;

                    } break;

                    case 'p':   // Sp: trimmed path
                    {
                        val= scope.GetTrimmedPath();
                        if ( val.IsEmpty() )
                            val= NoSourceFileInfo;
                    } break;

                    case 'F':   // file name
                    {
                        val= scope.GetFileName();
                        if ( val.IsEmpty() )
                            val= NoSourceFileInfo;
                    } break;

                    case 'f':   // file name without extension
                    {
                        val= scope.GetFileNameWithoutExtension();
                        if ( val.IsEmpty() )
                            val= NoSourceFileInfo;
                    } break;


                    case 'M':   // method name
                    {
                        String method= scope.GetMethod();
                        if ( method.Length == 0 )
                            dest._( NoMethodInfo );
                        else
                            dest._( method );
                        return 0;
                    }

                    case 'L':  // line number
                    {
                        dest._( scope.GetLineNumber() );
                        return 0;
                    }

                    default:
                    {
                        if( !warnedOnce )
                        {
                            warnedOnce= true;
                            ALIB.WARNING( "Unknown format variable '%S" + c2 + "\' (only one warning)" );
                        }
                        dest._( "%ERROR" );
                        return 0;
                    }
                }
                dest._( val );
                return 0;
            }

            // %Tx: Time
            case 'T':
            {
                // read sub command
                c2= variable.Consume();

                // %TD: Date
                if ( c2 == 'D' )
                {
                    // get time stamp as DateTime once
                    if ( callerDateTime == null )
                        callerDateTime= scope.GetTimeStamp().InDotNetDateTime();

                    // avoid the allocation of a) a StringBuilder (yes, a string builder is allocated inside StringBuilder.AppendFormat!)
                    // and b) a DateTime object, if the format is the unchanged standard. And it is faster anyhow.
                    if ( DateFormat.Equals( "yyyy-MM-dd" ) )
                    {
                        dest ._( callerDateTime.Value.Year,  4 )._( '-' )
                             ._( callerDateTime.Value.Month, 2 )._( '-' )
                             ._( callerDateTime.Value.Day,   2 );
                    }

                    // support user defined standards
                    else
                    {
                        // detect changes of format string since last log
                        if ( detectDateFormatChanges != DateFormat )
                        {
                            detectDateFormatChanges= DateFormat;
                            dateFormatString= "{0:" + DateFormat + "}";
                        }

                        // get date string from system and append to log buffer
                        formatSB.Clear();
                        formatSB.AppendFormat( CultureInfo.InvariantCulture, dateFormatString, callerDateTime );
                        dest._( formatSB );
                    }
                }

                // %TT: Time of Day
                else if ( c2 == 'T' )
                {
                    // get time stamp as DateTime once
                    if ( callerDateTime == null )
                        callerDateTime= scope.GetTimeStamp().InDotNetDateTime();

                    // avoid the allocation of a) a StringBuilder (yes, a string builder is allocated inside StringBuilder.AppendFormat!)
                    // and b) a DateTime object, if the format is the unchanged standard. And it is faster anyhow.
                    if ( TimeOfDayFormat.Equals( "HH:mm:ss" ) )
                    {
                        dest ._( callerDateTime.Value.Hour,   2 )._( ':' )
                             ._( callerDateTime.Value.Minute, 2 )._( ':' )
                             ._( callerDateTime.Value.Second, 2 );
                    }

                    // support user defined standards
                    else
                    {
                        // detect changes of format string since last log
                        if ( detectTimeOfDayFormatChanges != TimeOfDayFormat )
                        {
                            detectTimeOfDayFormatChanges= TimeOfDayFormat;
                            timeOfDayFormatString= "{0:" + TimeOfDayFormat + "}";
                        }

                        // get time string from system and append to log buffer
                        formatSB.Clear();
                        formatSB.AppendFormat( CultureInfo.InvariantCulture, timeOfDayFormatString, callerDateTime);
                        dest     ._( formatSB );
                    }
                }

                // %TC: Time elapsed since created
                else if ( c2 == 'C' )
                {
                    elapsedTime.Set( scope.GetTimeStamp()  );
                    elapsedTime.Sub( logger.TimeOfCreation );

                    if( MaxElapsedTime.Raw() < elapsedTime.Raw() )
                        MaxElapsedTime.Set( elapsedTime );

                    long      maxElapsedSecs= MaxElapsedTime.InSeconds();
                    TimeSpan  elapsed= new TimeSpan( elapsedTime.Raw() );

                    if ( maxElapsedSecs >= 60*60*24 )  dest._( elapsed.Days  )._NC( TimeElapsedDays );
                    if ( maxElapsedSecs >= 60*60    )  dest._( elapsed.Hours  ,  maxElapsedSecs >= 60*60*10 ?  2 : 1 )._( ':' );
                    if ( maxElapsedSecs >= 60       )  dest._( elapsed.Minutes,  maxElapsedSecs >= 10*60    ?  2 : 1 )._( ':' );
                    dest._( elapsed.Seconds,  maxElapsedSecs > 9 ? 2 : 1          )._NC( '.' );
                    dest._( elapsed.Milliseconds,  3 );
                }

                // %TL: Time elapsed since last log call
                else if ( c2 == 'L' )
                    writeTimeDiff( dest, scope.GetTimeStamp().Since(logger.TimeOfLastLog).InNanos() );

                else
                {
                    if( !warnedOnce )
                    {
                        warnedOnce= true;
                        ALIB.WARNING( "Unknown format variable '%T" + c2 + "\' (only one warning)" );
                    }
                    dest._( "%ERROR" );
                }
                return 0;
            }


            // thread name / ID
            case 't':
            {
                c2= variable.Consume();

                if ( c2 == 'N' )
                {
                    dest.Field()
                        ._( scope.GetThreadName() )
                        .Field( logger.AutoSizes.Next( scope.GetThreadName().Length(), 0 ), Alignment.Center );
                }
                else if ( c2 == 'I' )
                {
                    tmpAString._()._( scope.GetThreadID() );
                    dest.Field()
                        ._( tmpAString )
                        .Field( logger.AutoSizes.Next( tmpAString           .Length(), 0 ), Alignment.Center );
                }
                else
                {
                    if( !warnedOnce )
                    {
                        warnedOnce= true;
                        ALIB.WARNING( "Unknown format variable '%t" + c2 + "\' (only one warning)" );
                    }
                    dest._( "%ERROR" );
                }
                return 0;
            }

            case 'L':
            {
                c2= variable.Consume();
                     if ( c2 == 'G' )     dest._NC( logger.GetName() );
                else if ( c2 == 'X' )     dest._NC( scope.GetLoxName() );
                else
                {
                    if( !warnedOnce )
                    {
                        warnedOnce= true;
                        ALIB.WARNING( "Unknown format variable '%L" + c2 + "\' (only one warning)" );
                    }
                    dest._( "%ERROR" );
                    return 0;
                }
                return 0;
            }

            case 'P':
            {
                dest._NC( Util.GetProcessName() );
                return 0;
            }

            case 'V':   dest._ (    verbosity == Verbosity.Error    ? VerbosityError
                                  : verbosity == Verbosity.Warning  ? VerbosityWarning
                                  : verbosity == Verbosity.Info     ? VerbosityInfo
                                  :                               VerbosityVerbose    );
                        return 0;

            case 'D':
            {
                dest.Field()._( domain.FullPath ).Field( logger.AutoSizes.Next( domain.FullPath.Length(), 0 ), Alignment.Left );
                return 0;
            }

            case '#':    dest._( logger.CntLogs, LogNumberMinDigits );
                         return 0;

            // A: Auto tab
            case 'A':
            {
                // read extra space from format string
                int oldStart=    variable.Start;
                int extraSpace;  variable.ConsumeInteger( out extraSpace );
                if ( oldStart == variable.Start )
                    extraSpace=         1;

                // insert ESC code to jump to next tab level
                extraSpace= Math.Min( extraSpace, 10 + ('Z'-'A') );
                char escNo= extraSpace < 10 ?   (char) ( '0' + extraSpace )
                                            :   (char) ( 'A' + extraSpace );

                dest._( "\x1Bt" )._( escNo );
                return 1;
            }

            default:
            {
                if( !warnedOnce )
                {
                    warnedOnce= true;
                    ALIB.WARNING( "Unknown format variable \'" + variable.Buf[variable.Start - 1] + "\'" );
                }
                dest._( "%ERROR" );
            }
            return 0;
        }

    }
コード例 #7
0
    /** ********************************************************************************************
     *  Parses the #Format string and logs meta information into the log buffer. For each
     *  variable found, method #processVariable is invoked. Hence, to add new variables,
     *  the latter method can be overwritten by descendants. Overwriting this method is
     *  recommended for formatter classes that do not rely on format strings.
     * @param logger    The logger that we are embedded in.
     * @param buffer    The buffer to write meta information into.
     * @param domain    The <em>Log Domain</em>.
     * @param verbosity The verbosity. This has been checked to be active already on this
     *                  stage and is provided to be able to be logged out only.
     * @param scope     Information about the scope of the <em>Log Statement</em>..
     *
     * @return The number of tab sequences that were written (by adding ESC::TAB to the buffer).
     **********************************************************************************************/
    public virtual int Write( TextLogger logger, AString buffer, Domain domain, Verbosity verbosity, ScopeInfo scope )
    {
        int qtyTabStops= 0;

        // check
        if ( Format == null || Format.IsEmpty() )
            return 0;

        // clear DateTime singleton
        callerDateTime= null ;

        // loop/switch over content specified in configuration array
        tTok.Set( Format, '%' );

        while ( true )
        {
            // get next and log substring between commands
            if ( tTok.Next(Whitespaces.Keep).IsNotEmpty() )
                buffer._( tTok.Actual );

            // previous next did not find a delimiter
            if ( !tTok.HasNext() )
                break;

            // process the found variable
            qtyTabStops+= processVariable( logger, domain, verbosity, scope, buffer, tTok.Rest );
        }

        return qtyTabStops;
    }
コード例 #8
0
    public UTWriter()
    {
        lox= new Lox( "UTLox" );
        #if ALIB_MONO_DEVELOP
            logger= new ConsoleLogger( "UT ALib ReportWriter" );
        #else
            logger= Lox.CreateConsoleLogger( "UT ALib ReportWriter" );
        #endif

        lox.SetVerbosity( logger, Verbosity.Verbose, "UT" );
        lox.SetVerbosity( logger, Verbosity.Verbose, ALox.InternalDomains);
        lox.SetPrefix( ESC.BG_GRAY, "/" );

        cs.aworx.lib.Report.GetDefault().PushWriter( this );
    }