예제 #1
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;
        }

    }
예제 #2
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 );
    }
    /** ********************************************************************************************
     *
     *  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
    /** ********************************************************************************************
     *  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;
    }
예제 #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
    // #############################################################################################
    // 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       );
예제 #7
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);
예제 #8
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.
     * 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);
    }
예제 #10
0
        // #############################################################################################
        // Public interface
        // #############################################################################################

        /** ****************************************************************************************
         * Constructor
         * @param scopeInfo  The ScopeInfo singleton of 'our' Lox.
         * @param cfgSingleThreadValue Determines if for thread-related scopes, a list of values is
         *                             stored, or just one.
         ******************************************************************************************/
        public ScopeStore(ScopeInfo scopeInfo, bool cfgSingleThreadValue)
        {
            this.scopeInfo            = scopeInfo;
            this.cfgSingleThreadValue = cfgSingleThreadValue;
            this.globalStore          = default(T);
        }
예제 #11
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
        }