예제 #1
0
    // #############################################################################################
    // Public interface
    // #############################################################################################

    /** ********************************************************************************************
     * Constructor for domain.
     * @param parent     The parent domain. For root domains, this is null.
     * @param name       The name of the domain. For root domains, this is null.
     **********************************************************************************************/
    public Domain( Domain parent,  AString name )
    {
        // store parameters
        this.Name=      name;
        this.Parent=    parent;

        // create fields
        SubDomains=     new List<Domain>(3);
        Data=           new List<LoggerData>( parent == null ? 2 : parent.Data.Count );

        // if we have a parent, we inherit all logger's verbosities
        if( parent != null )
            foreach( LoggerData ldParent in parent.Data )
            {
                LoggerData ld= new LoggerData( ldParent.Logger );
                ld.LoggerVerbosity= ldParent.LoggerVerbosity;
                ld.Priority=        ldParent.Priority;
                Data.Add( ld );
            }

        FullPath= new AString();
        Domain dom= this;
        do
        {
            if ( dom != this || dom.Parent == null )
                FullPath.InsertAt( "/", 0 );
            FullPath.InsertAt( dom.Name, 0 );
            dom= dom.Parent;
        }
        while( dom != null );
    }
예제 #2
0
    // #############################################################################################
    // Abstract methods (introduced)
    // #############################################################################################

        /** ****************************************************************************************
         * This is the central method that derived logger classes have to implement to log a
         * message. When it is invoked the <em>Log Domains' Verbosity</em> was already checked against
         * parameter \p verbosity. The only action to take is to perform the log itself.<br>
         * Parameter \p logables contains at least one object, the one provided with the log
         * statement. Other objects that might be included in the list, are <em>Prefix Objects</em>
         * corresponding to the \p scope.
         *
         * @param domain    The <em>Log Domain</em>.
         * @param verbosity The verbosity.
         * @param logables  The list of objects to log.
         * @param scope     Information about the scope of the <em>Log Statement</em>.
         ******************************************************************************************/
        abstract public void Log( Domain        domain,
                                  Verbosity     verbosity,
                                  List<Object>  logables,
                                  ScopeInfo     scope       );
    /** ********************************************************************************************
     *
     *  The implementation of the abstract method of parent class TextLogger. Logs messages to the
     *  application console and/or the VStudio output window.
     *
     * @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 msg         The log message.
     * @param scope       Information about the scope of the <em>Log Statement</em>..
     * @param lineNumber  The line number of a multi-line message, starting with 0. For
     *                    single line messages this is -1.
     **********************************************************************************************/
    override protected void logText(  Domain     domain,     Verbosity verbosity,
                                      AString    msg,
                                      ScopeInfo  scope,      int       lineNumber)
    {
        // get actual console attributes
        ConsoleColor actualFGCol= Console.ForegroundColor;
        ConsoleColor actualBGCol= Console.BackgroundColor;

        // loop over message, print the parts between the escape sequences
        Tokenizer msgParts= new Tokenizer( msg, '\x1B' );
        Substring actual=   msgParts.Actual;
        Substring rest=     msgParts.Rest;
        int       column=   0;
        for(;;)
        {
            if ( msgParts.Next(Whitespaces.Keep).IsNotEmpty() )
            {
                #if !(ALOX_WP71 || ALOX_WP8)
                    Console.Write( msg.Buffer(), actual.Start, actual.Length() );
                #else
                    Console.Write( msg.ToString( 0, actual.Start, actual.Length() );
                #endif
                column+= actual.Length();
            }

            // end of loop?
            if ( !msgParts.HasNext() )
                break;

            // found an ESC sequence
            char c= rest.Consume();

            // Colors
            bool isForeGround=  true;
            if( c == 'C' || c == 'c' )
            {
                isForeGround=  c== 'c';

                c= rest.Consume();
                int colNo= c - '0';
                ALIB.ASSERT_WARNING( colNo >=0 && colNo <=9, "Unknown ESC-c code" );


                // set color
                if( colNo >= 0 && colNo <= 8 || colNo == 8)
                {
                    ConsoleColor[] cols=  (isForeGround ? !IsBackgroundLight : IsBackgroundLight )  ? lightColors : darkColors;
                    if ( isForeGround )
                        Console.ForegroundColor= cols[ colNo ];
                    else
                        Console.BackgroundColor= cols[ colNo ];
                }
                else if ( colNo == 9 )
                {
                    if ( isForeGround )
                        Console.ForegroundColor= actualFGCol;
                    else
                        Console.BackgroundColor= actualBGCol;
                }

                else
                {
                    ALIB.WARNING( "Unknown ESC- code" );
                }

            }

            // Styles
            else if ( c == 's' )
            {
                // bold/italics style not supported in Windows console

                // reset all
                if ( rest.Consume() == 'a' )
                {
                    Console.ForegroundColor= actualFGCol;
                    Console.BackgroundColor= actualBGCol;
                }
            }

            // auto tab / end of meta
            else if ( c == 't' || c == 'A')
            {
                bool endOfMeta= c == 'A';
                c=  rest.Consume();
                int extraSpace=  c >= '0' && c <= '9' ? (int)  ( c - '0' )
                                                      : (int)  ( c - 'A' ) + 10;

                int tabStop= AutoSizes.Next( column, extraSpace );

                Util.WriteSpaces( Console.Out, tabStop - column );
                column= tabStop;

                if ( endOfMeta )
                {
                    switch ( verbosity )
                    {
                        case Verbosity.Verbose:   Console.ForegroundColor= MsgColorVerbose;     break;
                        case Verbosity.Info:      Console.ForegroundColor= MsgColorInfo;        break;
                        case Verbosity.Warning:   Console.ForegroundColor= MsgColorWarning;     break;
                        case Verbosity.Error:     Console.ForegroundColor= MsgColorError;       break;
                        default:                  break;
                    }
                }
            }

            // Link (we just colorize links here)
            else if ( c == 'l' )
            {
                if ( rest.Consume() == 'S' )
                    Console.ForegroundColor=  IsBackgroundLight ? ConsoleColor.DarkBlue : ConsoleColor.Blue;
                else
                    Console.ForegroundColor=  actualFGCol;
            }

            else
            {
                ALIB.WARNING( "Unknown ESC code" );
            }

        } // write loop

        // reset colors
        Console.ForegroundColor= actualFGCol;
        Console.BackgroundColor= actualBGCol;

        // write NL
        #if !(ALOX_WP71 || ALOX_WP8)
            Console.WriteLine();
        #else
            Console.WriteLine();
        #endif

    }
예제 #4
0
    // #############################################################################################
    // Abstract methods (introduced)
    // #############################################################################################

        /** ****************************************************************************************
         * This abstract method introduced by this class "replaces" the the abstract method #Log
         * of parent class Logger which this class implements. In other words, descendants of this
         * class need to overwrite this method instead of \b %Do. This class %TextLogger is
         * responsible for generating meta information, doing text replacements, handle multi-line
         * messages, etc. and provides the textual representation of the whole log contents
         * to descendants using this method.
         *
         * @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 msg        The log message.
         * @param scope      Information about the scope of the <em>Log Statement</em>..
         * @param lineNumber The line number of a multi-line message, starting with 0.
         *                   For single line messages this is -1.
         ******************************************************************************************/
        abstract protected void logText(  Domain        domain,     Verbosity verbosity,
                                          AString       msg,
                                          ScopeInfo     scope,      int       lineNumber);
예제 #5
0
    // #############################################################################################
    // Abstract method implementations
    // #############################################################################################

        /** ****************************************************************************************
         * This is the implementation of the abstract method inherited from class Logger
         * that executes a log.<br>
         * This class implements this method and but exposes the new abstract method #logText.
         * This mechanism allows this class to do various things that are standard to Loggers
         * of type TextLogger. For example, meta information of the log invocation is formatted and
         * string replacements are performed. This way, descendants of this class will consume
         * a ready to use log buffer with all meta information and contents of all objects to be
         * included and their primary obligation is to copy the content into a corresponding
         * output stream.
         *
         * @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 logables  The list of objects to log.
         * @param scope     Information about the scope of the <em>Log Statement</em>..
         ******************************************************************************************/
        override public void Log(  Domain        domain,
                                   Verbosity     verbosity,
                                   List<Object>  logables,
                                   ScopeInfo     scope  )
        {
            // clear Buffer and reset utility members
            logBuf.Clear();
            AutoSizes.Start();

            //  << meta info << ESC::EOMETA
            int qtyESCTabsWritten=  MetaInfo.Write( this, logBuf, domain, verbosity, scope );

            logBuf._( ESC.EOMETA );

            // convert msg object into an AString representation
            msgBuf._();
            foreach( Object logable in logables )
            {
                int i;
                for( i= ObjectConverters.Count - 1; i >= 0 ; i-- )
                    if ( ObjectConverters[i].ConvertObject( logable, msgBuf ) )
                        break;
                if ( i == -1 )
                {
                    AString msg= new AString( FmtUnknownObject );
                    msg.SearchAndReplace( "%", "" + logable.GetType().ToString() );
                    msgBuf._NC( msg );
                }
            }

            // replace strings in message
            for ( int i= 0; i < replacements.Count ; i+=2 )
                msgBuf.SearchAndReplace( replacements[i], replacements[i + 1] );

            // check for empty messages
            if ( msgBuf.IsEmpty() )
            {
                // log empty msg and quit
                if (usesStdStreams) ALIB.StdOutputStreamsLock.Acquire();
                    logText( domain, verbosity, logBuf, scope, -1 );
                if (usesStdStreams) ALIB.StdOutputStreamsLock.Release();
                return;
            }

            // single line output
            if ( MultiLineMsgMode == 0 )
            {
                // replace line separators
                int cntReplacements=0;
                if ( MultiLineDelimiter != null )
                    cntReplacements+=msgBuf.SearchAndReplace( MultiLineDelimiter,    MultiLineDelimiterRepl );
                else
                {
                    cntReplacements+=msgBuf.SearchAndReplace( "\r\n", MultiLineDelimiterRepl );
                    cntReplacements+=msgBuf.SearchAndReplace( "\r", MultiLineDelimiterRepl );
                    cntReplacements+=msgBuf.SearchAndReplace( "\n", MultiLineDelimiterRepl );
                }

                // append msg to logBuf
                if ( cntReplacements == 0 )
                {
                    logBuf._( msgBuf );
                }
                else
                {
                    logBuf._( FmtMultiLinePrefix );
                    logBuf._( msgBuf );
                    logBuf._( FmtMultiLineSuffix );
                }

                // now do the logging by calling our derived classes' logText
                logText( domain, verbosity, logBuf, scope, -1 );

                // stop here
                return;
            }

            // multiple line output
            int qtyTabStops= AutoSizes.ActualIndex;

            int actStart=0;
            int lineNo=0;
            int lbLenBeforeMsgPart= logBuf.Length();

            // loop over lines in msg
            while ( actStart < msgBuf.Length() )
            {
                // find next end
                int delimLen;
                int actEnd;

                // no delimiter given: search "\r\n", then '\r', then '\n'
                if ( String.IsNullOrEmpty( MultiLineDelimiter ) )
                {
                    delimLen= 1;
                    actEnd= msgBuf.IndexOf( '\n', actStart );
                    if( actEnd > actStart )
                    {
                        if( msgBuf.CharAt(actEnd - 1) == '\r' )
                        {
                            actEnd--;
                            delimLen= 2;
                        }
                    }
                }
                else
                {
                    delimLen=MultiLineDelimiter.Length;
                    actEnd=msgBuf.IndexOf( MultiLineDelimiter, actStart );
                }

                // not found a delimiter? - log the rest
                if ( actEnd < 0 )
                {
                    // single line?
                    if ( lineNo == 0 )
                    {
                        // append msg to logBuf
                        logBuf._( msgBuf );

                        // now do the logging by calling our derived classes' logText
                        if (usesStdStreams) ALIB.StdOutputStreamsLock.Acquire();
                            logText( domain, verbosity, logBuf, scope, -1 );
                        if (usesStdStreams) ALIB.StdOutputStreamsLock.Release();

                        // stop here
                        return;
                    }

                    // store actual end
                    actEnd= msgBuf.Length();
                }

                // found a delimiter

                // signal start of multi line log
                if ( lineNo == 0 )
                {
                    if (usesStdStreams) ALIB.StdOutputStreamsLock.Acquire();
                    notifyMultiLineOp( Phase.Begin );
                }

                // in mode 3, 4, meta info is deleted
                if ( lineNo == 0 && ( MultiLineMsgMode == 3 || MultiLineMsgMode == 4 ) )
                {
                    // log headline in mode 3
                    if ( MultiLineMsgMode == 3 )
                    {
                        logBuf._( FmtMultiLineMsgHeadline );
                        AutoSizes.ActualIndex=  qtyTabStops;
                        logText( domain, verbosity, logBuf, scope, 0 );
                    }

                    // remember zero as offset
                    lbLenBeforeMsgPart=0;
                }

                // blank out meta information? (do this exactly in 2nd line once)
                if ( MultiLineMsgMode == 2 )
                {
                    if (lineNo != 0 )
                    {
                        logBuf.Clear()._( ESC.EOMETA );
                        AutoSizes.ActualIndex=  qtyTabStops + qtyESCTabsWritten;
                    }
                }
                // reset logBuf length to marked position
                else
                {
                    logBuf.SetLength_NC( lbLenBeforeMsgPart );
                    AutoSizes.ActualIndex=  qtyTabStops;
                }

                // append message
                logBuf._( FmtMultiLinePrefix );
                logBuf._NC( msgBuf, actStart, actEnd - actStart  );
                logBuf._( FmtMultiLineSuffix );
                logText( domain, verbosity, logBuf, scope, lineNo );

                // next
                actStart= actEnd + delimLen;
                lineNo++;
            }

            // signal end of multi line log
            if ( lineNo > 0 )
            {
                notifyMultiLineOp( Phase.End );
                if (usesStdStreams) ALIB.StdOutputStreamsLock.Release();
            }
        }
예제 #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
    /** ********************************************************************************************
     * Internal method used by State() to recursively (DFS) log <em>Prefix Logables</em> bound to
     * <em>Log Domains</em>
     *
     * @param domain        The actual domain to check.
     * @param indentSpaces  The number of spaces to write before each line.
     * @param target        The target string.
     **********************************************************************************************/
    protected void logStateCollectPrefixes( Domain domain, int indentSpaces, AString target )
    {
        foreach ( Domain.PL pfl in domain.PrefixLogables )
        {
            target.InsertChars( ' ', indentSpaces );

            target._('\"');
            int idx= target.Length();
            target._NC( pfl.Logable );
            ESC.ReplaceToReadable( target, idx );
            target._('\"');

            if ( pfl.IncludeOtherPLs == Inclusion.Exclude )
                target._NC( " (Excl.)" );
            target.Tab( 25 );
            target._NC( "<domain>           [" )._NC( domain.FullPath )._(']').NewLine();
        }

        foreach( Domain it in domain.SubDomains )
            logStateCollectPrefixes( it, indentSpaces, target );
    }
예제 #8
0
    /** ****************************************************************************************
     * Reads a prefix string from the ALib configuration system.
     * This internal method is used when a new domain is created,
     *
     * @param dom         The domain to set the verbosity for.
     ******************************************************************************************/
    protected void  getDomainPrefixFromConfig( Domain  dom )
    {
        Variable variable= new Variable( ALox.PREFIXES, GetName() );
        if( 0 == variable.Load() )
            return;

        Tokenizer prefixTok=        new Tokenizer();
        Tokenizer prefixTokInner=   new Tokenizer();
        Substring domainStr=        new Substring();
        AString   domainStrBuf=     new AString();
        Substring prefixStr=        new Substring();
        for( int varNo= 0; varNo< variable.Size(); varNo++ )
        {
            prefixTok.Set( variable.GetString( varNo ), '=' );

            domainStr.Set( prefixTok.Next() );
            if ( domainStr.StartsWith( "INTERNAL_DOMAINS", DomainSensitivity ) )
            {
                domainStrBuf._()._( domainStr.Buf, domainStr.Start + 16, domainStr.Length() -16 );
                while ( domainStrBuf.CharAtStart() == '/' )
                    domainStrBuf.DeleteStart( 1 );
                domainStrBuf.InsertAt( ALox.InternalDomains, 0 );
                domainStr.Set( domainStrBuf );
            }

            prefixTokInner.Set( prefixTok.Next(), ',' );
            prefixStr.Set( prefixTokInner.Next() );
            if ( prefixStr.IsEmpty() )
                continue;
            if ( prefixStr.Consume( '\"' ) )
                prefixStr.ConsumeFromEnd( '\"' );

            Inclusion otherPLs= Inclusion.Include;
            prefixTokInner.Next();
            if ( prefixTokInner.Actual.IsNotEmpty() )
                otherPLs= ALIB.ReadInclusion( prefixTokInner.Actual  );

            int searchMode= 0;
            if ( domainStr.Consume       ( '*' ) )    searchMode+= 2;
            if ( domainStr.ConsumeFromEnd( '*' ) )    searchMode+= 1;
            if(     ( searchMode == 0 && dom.FullPath.Equals          ( domainStr,    DomainSensitivity )     )
                ||  ( searchMode == 1 && dom.FullPath.StartsWith      ( domainStr,    DomainSensitivity )     )
                ||  ( searchMode == 2 && dom.FullPath.EndsWith        ( domainStr,    DomainSensitivity )     )
                ||  ( searchMode == 3 && dom.FullPath.IndexOf         ( domainStr, 0, DomainSensitivity ) >=0 )
                )
            {
                dom.PrefixLogables.Add( new Domain.PL( new AString( prefixStr ), otherPLs ) );

                // log info on this
                intMsg._()._NC( "String \"" )._NC( prefixStr )._NC ( "\" added as prefix logable for domain \'" )
                          ._NC( dom.FullPath )
                          ._NC( "\'. (Retrieved from variable" )
                          ._NC( variable.Fullname )._( ".)" );
                logInternal( Verbosity.Info, "PFX", intMsg );
            }
        }
    }
예제 #9
0
    /** ****************************************************************************************
     * Reads the verbosity for the given logger and domain from the ALib configuration system.
     * This internal method is used when a new logger is added.
     * Walks recursively for all existing domains.
     *
     * @param logger      The logger to set the verbosity for.
     * @param dom         The domain to set the verbosity for.
     * @param cfgResult   The result of the search for the variable to set verbosities from.
     ******************************************************************************************/
    protected void getAllVerbosities      ( Logger  logger,  Domain  dom,  Variable cfgResult )
    {
        // get verbosity for us
        getVerbosityFromConfig( logger, dom, cfgResult );

        // loop over all sub domains (recursion)
        foreach ( Domain subDomain in dom.SubDomains )
            getAllVerbosities( logger, subDomain, cfgResult );
    }
예제 #10
0
        /** ****************************************************************************************
         * This method is looping over the \e Loggers, checking their verbosity against the given
         * one, and, if they match, invoke the log method of the \e Logger.
         * With the first logger identified to be active, the <em>Prefix Objects</em> get
         * collected from the scope store.
         * @param dom       The domain to log on
         * @param verbosity The verbosity.
         * @param logable   The object to log.
         * @param prefixes  Denotes if prefixes should be included or not.
         ******************************************************************************************/
        protected void log( Domain dom, Verbosity verbosity, Object logable, Inclusion prefixes )
        {
            // OK, this is a little crude, but the simplest solution: As class ScopeStore sees
            // null objects as nothing and won't return them in a walk, we replace null by
            // an object (we choose the store itself) and fix this in the loop back to null
            if ( logable == null )
                logable= scopePrefixes;

            dom.CntLogCalls++;
            logObjects.Clear();
            for ( int i= 0; i < dom.CountLoggers() ; i++ )
                if( dom.IsActive( i, verbosity ) )
                {
                    // lazily collect objects once
                    if ( logObjects.Count == 0 )
                    {
                        scopePrefixes.InitWalk( Scope.ThreadInner, logable );
                        Object next;
                        while( (next= scopePrefixes.Walk() ) != null )
                        {
                            if ( prefixes == Inclusion.Include || next == logable)
                                logObjects.Insert( 0, next != scopePrefixes ? next : null );

                            // was this the actual? then insert domain-associated logables now
                            bool excludeOthers= false;
                            if( next == logable )
                            {
                                int qtyThreadInner= logObjects.Count -1;
                                Domain pflDom= dom;
                                while ( pflDom != null )
                                {
                                    for( int ii= pflDom.PrefixLogables.Count -1 ; ii >= 0 ; ii-- )
                                    {
                                        Domain.PL pl= pflDom.PrefixLogables[ii];
                                        logObjects.Insert( 0,  pl.Logable );
                                        if ( pl.IncludeOtherPLs == Inclusion.Exclude )
                                        {
                                            excludeOthers= true;
                                            break;
                                        }
                                    }

                                    pflDom= excludeOthers ? null :  pflDom.Parent;
                                }

                                // found a stoppable one? remove those from thread inner and break
                                if (excludeOthers)
                                {
                                    for ( int ii= 0; ii < qtyThreadInner ; ii++ )
                                        logObjects.RemoveAt( logObjects.Count - 1 );
                                    break;
                                }
                            }
                        }
                    }

                    Logger logger= dom.GetLogger(i);
                    logger.Acquire();
                        logger.CntLogs++;
                        logger.Log( dom, verbosity, logObjects, scopeInfo );
                        logger.TimeOfLastLog.Set();
                    logger.Release();
                }
        }
예제 #11
0
    /** ****************************************************************************************
     * Reads the verbosity for the given logger and domain from the ALib configuration system.
     * This internal method is used in two occasions:
     * - when a new logger is added: recursively for all existing domains (\p configStr is
     *   given)
     * - when a new domain is created on the fly(\p configStr is not given)
     *
     * @param logger      The logger to set the verbosity for.
     * @param dom         The domain to set the verbosity for.
     * @param variable    The (already read) variable to set verbosities from.
     ******************************************************************************************/
    protected void  getVerbosityFromConfig( Logger  logger,  Domain  dom, Variable variable  )
    {
        // get logger number. It may happen that the logger is not existent in this domain tree.
        int loggerNo= dom.GetLoggerNo( logger ) ;
        if ( loggerNo < 0 )
            return;

        Tokenizer verbosityTknzr=   new Tokenizer();
        Substring domainStr=      new Substring();
        AString   domainStrBuf=   new AString();
        for( int varNo= 0; varNo< variable.Size(); varNo++ )
        {
            verbosityTknzr.Set( variable.GetString( varNo ), '=' );

            domainStr.Set( verbosityTknzr.Next() );
            if ( domainStr.StartsWith( "INTERNAL_DOMAINS", DomainSensitivity ) )
            {
                domainStrBuf._()._( domainStr.Buf, domainStr.Start + 16, domainStr.Length() -16 );
                while ( domainStrBuf.CharAtStart() == '/' )
                    domainStrBuf.DeleteStart( 1 );
                domainStrBuf.InsertAt( ALox.InternalDomains, 0 );
                domainStr.Set( domainStrBuf );
            }

            Substring verbosityStr=  verbosityTknzr.Next();
            if ( verbosityStr.IsEmpty() )
                continue;

            int searchMode= 0;
            if ( domainStr.Consume       ( '*' ) )    searchMode+= 2;
            if ( domainStr.ConsumeFromEnd( '*' ) )    searchMode+= 1;
            if(     ( searchMode == 0 && dom.FullPath.Equals          ( domainStr,    DomainSensitivity )     )
                ||  ( searchMode == 1 && dom.FullPath.StartsWith      ( domainStr,    DomainSensitivity )     )
                ||  ( searchMode == 2 && dom.FullPath.EndsWith        ( domainStr,    DomainSensitivity )     )
                ||  ( searchMode == 3 && dom.FullPath.IndexOf         ( domainStr, 0, DomainSensitivity ) >=0 )
                )
            {
                Verbosity verbosity= ALox.ReadVerbosity( verbosityStr);
                dom.SetVerbosity( loggerNo, verbosity, variable.Priority );

                // log info on this
                intMsg._()._NC( "Logger \"" )._NC( logger.GetName() ) ._NC( "\":" ).Tab(11 + maxLoggerNameLength)
                          ._( '\'' )._NC( dom.FullPath )
                          ._( '\'' ).InsertChars(' ', maxDomainPathLength - dom.FullPath.Length() + 1 )
                          ._("= Verbosity." );
                          ALox.ToString( verbosity, dom.GetPriority(loggerNo), intMsg ).TrimEnd()
                          ._('.');
                logInternal( Verbosity.Info, "LGR", intMsg );
            }
        }
    }
예제 #12
0
        /** ****************************************************************************************
         * Invokes \b Find on the given domain and logs internal message when the domain was
         * not known before.
         *
         * @param domainSystem  The domain system. Either the standard or the internal one.
         * @param domainPath    The domain path.
         * @return The resulting \ref cs::aworx::lox::core::Domain "Domain".
         ******************************************************************************************/
        Domain findDomain( Domain domainSystem, AString domainPath )
        {
            AString substPath= domainSystem == domains ? tmpSubstitutionPath
                                                       : tmpSubstitutionPathInternalDomains;

            int maxSubstitutions= 10;
            for(;;)
            {
                // loop for creating domains, one by one
                Domain dom= null;
                for(;;)
                {
                    bool wasCreated= false;
                    dom= domainSystem.Find( domainPath, DomainSensitivity, 1, ref wasCreated );

                    if ( wasCreated )
                    {
                        // get maximum domain path length (for nicer State output only...)
                        if ( maxDomainPathLength < dom.FullPath.Length() )
                            maxDomainPathLength=   dom.FullPath.Length();

                        // log info on new domain
                        intMsg._()._('\'')._NC( dom.FullPath )._NC("' registered.");
                        logInternal( Verbosity.Info, "DMN", intMsg );
                    }

                    // read domain from Config
                    if ( !dom.ConfigurationRead )
                    {
                        dom.ConfigurationRead= true;

                        Variable variable= new Variable();
                        for ( int i= 0; i < dom.CountLoggers(); ++i )
                        {
                            Logger logger= dom.GetLogger(i);
                            if ( 0 != variable.Define( ALox.VERBOSITY, GetName(), logger.GetName() ).Load() )
                                getVerbosityFromConfig( logger, dom, variable );
                        }

                        getDomainPrefixFromConfig( dom );
                    }

                    // log inherited setting for each logger
                    if ( wasCreated )
                    {
                        if ( domainSystem.CountLoggers() == 0 )
                            logInternal( Verbosity.Verbose, "DMN", intMsg._()._NC("No loggers set, yet.") );
                        else
                            for ( int i= 0; i < domainSystem.CountLoggers(); i++ )
                            {
                                intMsg._()._("  \"")._( dom.GetLogger(i).GetName() )._NC("\":");
                                intMsg.InsertChars( ' ', maxLoggerNameLength  + 6 - intMsg.Length() );
                                intMsg._NC( dom.FullPath )
                                      ._NC( " = " ); ALox.ToString( dom.GetVerbosity( i ), dom.GetPriority( i), intMsg );

                                logInternal( Verbosity.Verbose, "DMN", intMsg );
                            }
                    }
                    else
                        break;
                }

                // apply domain substitutions
                if( domainSubstitutions.Count > 0 )
                {
                    substPath.Clear();
                    while( maxSubstitutions-- > 0  )
                    {
                        // loop over rules
                        bool substituted= false;
                        foreach( DomainSubstitutionRule rule in domainSubstitutions )
                        {
                            switch( rule.type )
                            {
                                case DomainSubstitutionRule.Type.StartsWith:
                                    if( substPath.IsEmpty() )
                                    {
                                        if ( dom.FullPath.StartsWith( rule.Search, DomainSensitivity ) )
                                        {
                                            substPath._( rule.Replacement )._( dom.FullPath, rule.Search.Length() );
                                            substituted= true;
                                            continue; //next rule
                                        }
                                    }
                                    else
                                    {
                                        if ( substPath.StartsWith( rule.Search, DomainSensitivity ) )
                                        {
                                            substPath.ReplaceSubstring( rule.Replacement, 0, rule.Search.Length()  );
                                            substituted= true;
                                            continue; //next rule
                                        }
                                    }
                                break;

                                case DomainSubstitutionRule.Type.EndsWith:
                                    if( substPath.IsEmpty() )
                                    {
                                        if ( dom.FullPath.EndsWith( rule.Search, DomainSensitivity ) )
                                        {
                                            substPath._( dom.FullPath, 0, dom.FullPath.Length() - rule.Search.Length() )._( rule.Replacement );
                                            substituted= true;
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        if ( substPath.EndsWith( rule.Search, DomainSensitivity ) )
                                        {
                                            substPath.DeleteEnd( rule.Search.Length() )._( rule.Replacement );
                                            substituted= true;
                                            continue;
                                        }
                                    }
                                break;


                                case DomainSubstitutionRule.Type.Substring:
                                    if( substPath.IsEmpty() )
                                    {
                                        int idx= dom.FullPath.IndexOf( rule.Search, 0, DomainSensitivity );
                                        if ( idx >= 0 )
                                        {
                                            substPath._( dom.FullPath, 0, idx )._( rule.Replacement)._( dom.FullPath, idx + rule.Search.Length() );
                                            substituted= true;
                                            continue; //next rule
                                        }
                                    }
                                    else
                                    {
                                        int idx= substPath.IndexOf( rule.Search, 0, DomainSensitivity );
                                        if ( idx >= 0 )
                                        {
                                            substPath.ReplaceSubstring( rule.Replacement, idx, rule.Search.Length()  );
                                            substituted= true;
                                            continue; //next rule
                                        }
                                    }
                                break;

                                case DomainSubstitutionRule.Type.Exact:
                                {
                                    if( substPath.IsEmpty() )
                                    {
                                        if ( dom.FullPath.Equals( rule.Search ) )
                                        {
                                            substPath._( rule.Replacement);
                                            substituted= true;
                                            continue; //next rule
                                        }
                                    }
                                    else
                                    {
                                        if ( substPath.Equals( rule.Search) )
                                        {
                                            substPath._()._( rule.Replacement );
                                            substituted= true;
                                            continue; //next rule
                                        }
                                    }
                                }
                                break;

                            } // switch rule type

                        }//rules loop

                        // stop if non was found
                        if( !substituted )
                            break;
                    }

                    // too many substitutions?
                    if ( maxSubstitutions <= 0 && !oneTimeWarningCircularDS )
                    {
                        oneTimeWarningCircularDS= true;
                        intMsg._()._(   "The Limit of 10 domain substitutions was reached. Circular substitution assumed!"
                                      + " (This error is only reported once!)" );

                        logInternal( Verbosity.Error, "DMN", intMsg );
                    }

                    // anything substituted?
                    if( substPath.Length() > 0 )
                    {
                        domainPath= substPath;
                        continue;
                    }
                }

                return dom;
            }
        }
예제 #13
0
    // #############################################################################################
    // Constructors
    // #############################################################################################

        /** ****************************************************************************************
         * Constructs a new, empty Lox with the given \p name.
         * The name is immutable and all \b %Lox objects registered with ALox must be unique.
         * The name \c "Log" is reserved for the internal default singleton used for debug-logging.
         * In addition, name \c "GLOBAL" is not allowed.
         *
         * If parameter \p register is \c true (the default), static method
         * \ref cs::aworx::lox::ALox::Register "ALox.Register" is invoked and the object will be
         * retrievable with static method
         * \ref cs::aworx::lox::ALox::Get "ALox.Get". In some situations, such 'registration'
         * may not be wanted.
         * @param name       The name of the Lox. Will be converted to upper case.
         * @param doRegister If \c true, this object is registered with static class
         *                   \ref cs::aworx::lox::ALox "ALox".
         *                   Optional and defaults to \c true.
         ******************************************************************************************/
        public Lox( String name, bool doRegister = true )   : base()
        {
            // set recursion warning of log buffer lock to 1. Warnings are logged if recursively
            // acquired more than once
            #if ALOX_DBG_LOG || ALOX_REL_LOG
                logBufLock.RecursionWarningThreshold= 1;

                scopeInfo=      new ScopeInfo( name, threadDictionary );
                scopeDomains=   new ScopeStore<AString                     >( scopeInfo, false );
                scopePrefixes=  new ScopeStore<Object                      >( scopeInfo, false );
                scopeLogData=   new ScopeStore<Dictionary<AString, LogData>>( scopeInfo, true  );
                scopeLogOnce=   new ScopeStore<Dictionary<AString, int[]>  >( scopeInfo, true  );


                // create domain trees
                domains          = new Domain( null, new AString( "") );
                internalDomains  = new Domain( null, new AString( ALox.InternalDomains,
                                                                  0, ALox.InternalDomains.Length - 1) );

                // create internal sub-domains
                bool wasCreated= false;
                String[] internalDomainList= {"LGR", "DMN", "PFX", "THR", "LGD", "VAR"  };
                foreach ( String it in internalDomainList )
                {
                    resDomainInternal._()._NC( it );
                    internalDomains.Find( resDomainInternal, Case.Sensitive, 1, ref wasCreated );
                }

                maxDomainPathLength= ALox.InternalDomains.Length + 3;

                // register with ALox
                if ( doRegister )
                    ALox.Register( this, ContainerOp.Insert );

                // read domain substitution rules from configuration
                Variable variable= new Variable( ALox.DOMAIN_SUBSTITUTION, GetName() );
                if ( variable.Load() != 0 )
                {
                    for( int ruleNo= 0; ruleNo< variable.Size(); ruleNo++ )
                    {
                        AString rule= variable.GetString( ruleNo );
                        int idx= rule.IndexOf( "->" );
                        if ( idx > 0 )
                        {
                            String domainPath=  rule.ToString( 0,  idx ).Trim();
                            String replacement= rule.ToString( idx + 2 ).Trim();
                            SetDomainSubstitutionRule( domainPath, replacement );
                        }
                        else
                        {
                            // using alib warning here as we can't do internal logging in the constructor
                            ALIB.WARNING( "Syntax error in variable \"" + variable.Fullname + "\"." );
                        }
                    }
                }
            #endif
        }
예제 #14
0
    /** ********************************************************************************************
     * Internal method used by State() to recursively (DFS) collect Domains of Logger that have
     * a different verbosity than their parent.
     *
     * @param domain      The actual domain to check.
     * @param loggerNo    The logger to collect domains for.
     * @param results     The result list.
     **********************************************************************************************/
    protected void logStateDomsWithDiffVerb( Domain domain, int loggerNo, List<Domain> results )
    {
        if (    domain.Parent == null
            ||  domain.Parent.GetVerbosity(loggerNo) != domain.GetVerbosity(loggerNo) )
            results.Add( domain );

        foreach( Domain it in domain.SubDomains )
            logStateDomsWithDiffVerb( it, loggerNo, results );
    }
예제 #15
0
    // #############################################################################################
    // Internals
    // #############################################################################################
        /** ****************************************************************************************
         * Internal, recursive helper of #Find.
         *
         * @param       domainPath  Path to search.
         * @param       sensitivity Denotes if domain name search is treated case sensitive or not.
         * @param       maxCreate   The maximum number of sub domains that are created if not
         *                          found at the end of the path.
         * @param[out]  wasCreated  Output parameter that is set \c true if domain was not found
         *                          and hence created.
         * @return The domain found or created.
         ******************************************************************************************/
        protected Domain findRecursive( Substring domainPath, Case sensitivity,
                                        int maxCreate, ref bool wasCreated          )
        {
            //--- get act sub-name and rest of path
            domainPath.Consume( Separator );
            int endSubName= domainPath.IndexOf( Separator );

            ALIB.ASSERT_ERROR( endSubName != 0, "Internal Error" );

            // find end of actual domain name and save rest
            Substring restOfDomainPath= tSubstring2;
            restOfDomainPath.SetNull();
            if ( endSubName > 0 )
                domainPath.Split( endSubName, restOfDomainPath, 1 );

            // search sub-domain
            Domain subDomain= null;

            // "."
            if( domainPath.Equals( "." ) )
                subDomain= this;

            // ".."
            else if( domainPath.Equals( ".." ) )
                subDomain= Parent != null ? Parent : this;


            // search in sub-domain
            else
            {
                int i;
                bool fixedOnce= false;
                for(;;)
                {
                    for( i= 0; i< SubDomains.Count; i++ )
                    {
                        int comparison=   SubDomains[i].Name.CompareTo( domainPath, sensitivity );
                        if( comparison >= 0 )
                        {
                            if ( comparison == 0 )
                                subDomain= SubDomains[i];
                            break;
                        }
                    }

                    // domain found?
                    if ( subDomain != null )
                        break;

                    // try and fix name
                    if( !fixedOnce )
                    {
                        fixedOnce= true;

                        bool illegalCharacterFound= false;
                        for( int cp= 0; cp< domainPath.Length() ; ++cp )
                        {
                            char c= domainPath.CharAt(cp);
                            if (     c <  '-' || c > 'z'
                                  || c == '<' || c == '>'
                                  || c == '[' || c == ']'
                                  || c == '=' || c == '?' || c == ';' || c == ':'
                                  || c == '\\'|| c == '\''|| c == '.' || c == ','
                               )
                            {
                                illegalCharacterFound= true;
                                domainPath.Buf[domainPath.Start + cp]= '#';
                            }
                        }

                        if ( illegalCharacterFound )
                            continue;
                     }

                    // create
                    if ( maxCreate == 0 )
                        return null;
                    wasCreated= true;
                    SubDomains.Insert( i, subDomain= new Domain( this,  new AString( domainPath ) ) );
                    maxCreate--;
                    if ( maxCreate == 0 )
                        return subDomain;

                    break;
                }

            }
            // recursion?
            if ( restOfDomainPath.IsNotEmpty() )
            {
                domainPath.Set( restOfDomainPath );
                return subDomain.findRecursive( domainPath, sensitivity, maxCreate, ref wasCreated );
            }

            // that's it
            return subDomain;
        }
예제 #16
0
    /** ****************************************************************************************
     * Helper method of #dumpStateOnLoggerRemoval to recursively collect domain settings.
     * @param domain    The actual domain.
     * @param loggerNo  The number of the logger
     * @param variable  The AString to collect the information.
     ******************************************************************************************/
    #if ALOX_DBG_LOG || ALOX_REL_LOG
    protected void verbositySettingToVariable( Domain domain, int loggerNo, Variable variable )
    {
        variable.AddString()._( domain.FullPath )
                            ._('=')
                            ._( domain.GetVerbosity( loggerNo ).ToString() );

        // loop over all sub domains (recursion)
        foreach( Domain subDomain in domain.SubDomains )
            verbositySettingToVariable( subDomain, loggerNo, variable );
    }
예제 #17
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;
    }
    /** ********************************************************************************************
     * The implementation of the abstract method of parent class TextLogger.
     * Loops over the log text, removes or ignores ESC sequences (all but ESC.TAB) and invokes
     * abstract methods of descendants as follows:
     * - \ref notifyLogOp "notifyLogOp(true)"
     * -   #logSubstring()
     * -   ...
     * - \ref notifyLogOp "notifyLogOp(Phase.End)"
     *
     * @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 msg           The log message.
     * @param scope         Information about the scope of the <em>Log Statement</em>..
     * @param lineNumber    The line number of a multi-line message, starting with 0. For single
     *                      line messages this is -1.
     **********************************************************************************************/
    override protected void logText(  Domain        domain,    Verbosity verbosity,
                                        AString       msg,
                                        ScopeInfo     scope,     int          lineNumber)
    {
        if ( !notifyLogOp( Phase.Begin ) )
            return;
        // loop over message, print the parts between the escape sequences
        int  msgLength=  msg.Length();
        int  start=      0;
        int  end;
        int  column=     0;
        while( start < msgLength )
        {
            bool foundESC=  true;
            end=    msg.IndexOf( '\x1B', start );
            if( end < 0 )
            {
                foundESC= false;
                end=      msgLength ;
            }


            if ( end > start )
            {
                if (!logSubstring( msg,  start, end - start ) )
                    return;
                column+= end - start;
            }

            // interpret escape sequence
            if ( foundESC )
            {
                char c= msg[++end];

                // auto tab or end of meta info part
                if ( c == 't' || c == 'A')
                {
                    end++;
                    c=  msg[end++];
                    int extraSpace=  c >= '0' && c <= '9' ? (int)  ( c - '0' )
                                                          : (int)  ( c - 'A' ) + 10;

                    int tabStop= AutoSizes.Next( column, extraSpace );

                    if ( tabStop > column )
                    {
                        AString spaces= Util.GetSpaces();
                        int spacesLength= spaces.Length();
                        int qty= tabStop - column;
                        while ( qty > 0 )
                        {
                            int size= qty < spacesLength ? qty : spacesLength;
                            if(!logSubstring( spaces, 0, size ) ) return;
                            qty-= size;
                        }
                        column= tabStop;
                    }

                }

                // prune or ignore all others
                else
                {
                    if ( !PruneESCSequences )
                        if(!logSubstring( msg, end - 1, 3 )) return;
                    end+= 2;
                }
            }

            // next
            start= end;

        } // write loop

        ALIB.ASSERT_WARNING( start == msgLength, "Loop error when pruning ESC codes" );
        notifyLogOp( Phase.End);
    }
예제 #19
0
    // #############################################################################################
    // logText
    // #############################################################################################

    /** ********************************************************************************************
     *
     *  The implementation of the abstract method of parent class TextLogger. Logs messages to the
     *  application console and/or the VStudio output window.
     *
     * @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 msg         The log message
     * @param scope       Information about the scope of the <em>Log Statement</em>..
     * @param lineNumber  The line number of a multi-line message, starting with 0. For
     *                    single line messages this is -1.
     **********************************************************************************************/
    override protected void logText(  Domain         domain,     Verbosity verbosity,
                                        AString        msg,
                                        ScopeInfo      scope,      int           lineNumber)
    {
        // loop over message, print the parts between the escape sequences
        Tokenizer msgParts= new Tokenizer( msg, '\x001B' );
        Substring actual=   msgParts.Actual;
        Substring rest=     msgParts.Rest;
        int       column=   0;
        for(;;)
        {
            msgParts.Next( Whitespaces.Keep );

            // check if this is an ANSI sequence already
            if ( rest.CharAtStart() == '[' )
            {
                // read the 'm'
                int idx= rest.IndexOf( 'm' );

                if ( idx < 0 ) // unknown ANSI Code
                {
                    ALIB.WARNING( "Unknown ANSI ESC Code " );
                    textWriter.Write( actual.Buf, actual.Start, actual.Length() );
                    continue;
                }

                column+= actual.Length();

                actual.End= rest.Start + idx ;
                rest.Start+= idx + 1;

                textWriter.Write( actual.Buf, actual.Start, actual.Length() );

                continue;
            }

            if ( actual.IsNotEmpty() )
            {
                textWriter.Write( actual.Buf, actual.Start, actual.Length() );
                column+= actual.Length();
            }

            // end of loop?
            if ( !msgParts.HasNext() )
                break;

            // found an ESC sequence
            char c= rest.Consume();

            // Colors
            bool isForeGround=  true;
            if( c == 'C' || c == 'c' )
            {
                isForeGround=  c== 'c';

                c= rest.Consume();
                int colNo= c - '0';
                ALIB.ASSERT_WARNING( colNo >=0 && colNo <=9, "Unknown ESC-c code" );

                // add bg
                colNo+=  isForeGround ? 0 : 10;

                // add light
                colNo+=  (isForeGround ? !IsBackgroundLight : IsBackgroundLight )  ? 20 : 0;

                textWriter.Write( ansiCols[ colNo ] );

            }

            // Styles
            else if ( c == 's' )
            {
                // bold/italics style not supported in Windows console

                // reset all
                if ( rest.Consume() == 'a' )
                {
                    textWriter.Write( ANSI_RESET );
                }
            }

            // auto tab / end of meta
            else if ( c == 't' || c == 'A')
            {
                bool endOfMeta= c == 'A';
                c=  rest.Consume();
                int extraSpace=  c >= '0' && c <= '9' ? (int)  ( c - '0' )
                                                      : (int)  ( c - 'A' ) + 10;

                int tabStop= AutoSizes.Next( column, extraSpace );

                Util.WriteSpaces( textWriter, tabStop - column );
                column= tabStop;

                if ( endOfMeta )
                {
                    String msgPrefix;
                    switch ( verbosity )
                    {
                        case lox.Verbosity.Verbose:   msgPrefix= MsgPrefixVerbose;     break;
                        case lox.Verbosity.Info:      msgPrefix= MsgPrefixInfo;        break;
                        case lox.Verbosity.Warning:   msgPrefix= MsgPrefixWarning;     break;
                        case lox.Verbosity.Error:     msgPrefix= MsgPrefixError;       break;
                        default:                  msgPrefix= "";                   break;
                    }
                    textWriter.Write( msgPrefix );
                }
            }

            // Link (we just colorize links here)
            else if ( c == 'l' )
            {
                textWriter.Write( rest.Consume() == 'S'
                                       ?  ( IsBackgroundLight ? ANSI_LIGHT_BLUE : ANSI_LIGHT_BLUE )
                                       :  ANSI_STD_COL                             );
            }

            else
            {
                ALIB.WARNING( "Unknown ESC code" );
            }

        } // write loop


        textWriter.WriteLine( MsgSuffix );
    }
예제 #20
0
    /** ********************************************************************************************
     * Internal method used by State() to recursively log Domain instances.
     *
     * @param domain      The Domain instance to log out.
     * @param buf         The buffer to log to.
     **********************************************************************************************/
    protected  void logStateDomainRecursive( Domain domain, AString buf )
    {
        int reference= buf.Length();
        buf._NC("  ")  ._NC( domain );
        int idx= buf.IndexOf( '[', reference );
        buf.InsertChars( ' ', maxDomainPathLength + 5 - idx + reference , idx);
        buf.NewLine();

        // loop over all sub domains (recursion)
        foreach ( Domain subDomain in domain.SubDomains )
            logStateDomainRecursive( subDomain, buf);
    }