1

我正在尝试用 C++ 制作一个优雅的日志记录系统。我目前正在使用printf(),虽然cout也可以是一个选项。

我想要实现的是这样的

console_log( "ClassName", "funcName", "Message." );

我目前的代码很简单:

static void console_log( const std::string & className, const std::string & funcName, const std::string & message ) {
    printf( "%s : %s : %s\n",  className.c_str(), funcName.c_str(), message.c_str() );
}

它打印得很好,像这样

// For example:
console_log( "MenuPanel", "selectedThisButton", "Something happened." );
console_log( "MenuPanel", "selectedAnotherButton", "Another thing happened." );

// Output:
MenuPanel : selectedThisButton : Something happened.
MenuPanel : selectedAnotherButton : Another thing happened.

但是,我希望它以类似表格的方式打印,其中所有“列”都正确对齐。例如:

MenuPanel : selectedThisButton    : Something happened.
MenuPanel : selectedAnotherButton : Another thing happened.

如何使第一个和第二个“列”具有完全相同的宽度/字符数,并在必要时使用额外的空格?它不需要是动态的。将“列”设置为 16 个字符之类的东西就可以了。

不过,我不希望将任何第三方库用于如此简单的事情。如果可能的话,不boost

4

3 回答 3

4

我将使用 I/O 流而不是 C 样式printf,并打印具有特定宽度的东西(任何类型),然后您可以包含<iomanip>并设置字段宽度

some_stream << std::setw(MY_WIDTH) << whatever;

例子:

#include <iostream>
#include <iomanip>

int main()
{
    std::cout << std::setw(10) << "hi";
}

输出:

        hi
于 2013-08-23T08:44:58.203 回答
3

如果您采用“保持简单”的方式,您可以替换:

printf( "%s : %s : %s\n", className.c_str(), funcName.c_str(), 
message.c_str() ); 

printf( "%30s : %30s : %30s\n", className.c_str(), funcName.c_str(), 
message.c_str() );

无论您喜欢什么宽度,您都可以查看 printf 文档中的对齐修饰符。

于 2013-08-23T08:51:53.330 回答
0

一般的解决方案是相当复杂的,但是如果你可以假设一个固定宽度的字体(每个字符都有相同的宽度),并且预先知道每列的宽度,比如:

std::string rPad( std::string const& original, int minWidth )
{
    return original
        + std::string( 
            std::max( minWidth - static_cast<int>( original.size() ), 0 ),
            ' ' );
}

void console_log(
    std::string const& className,
    std::string const& funcName,
    std::string const& message )
{
    std::cout << rPad( className, classNameWidth )
        << " : " << rPad( funcName, funcNameWidth )
        << " : " << rPad
        << std::endl;
}

或者,您可以执行以下操作:

void console_log(
    std::string const& className,
    std::string const& funcName,
    std::string const& message )
{
    std::cout << alignedText( classNameWidth ) << className
        << " : " << alignedText( funcNameWidth ) << funcName
        << " : " << message << std::endl;
}

操纵alignedText器通常很有用,无论如何您都应该将它放在工具箱中:

class alignedText
{
    mutable std::ostream* myOwner;
    mutable std::ostream::fmtflags myFlags;
    int myWidth;
public:
    alignedText( int width ) : myOwner myWidth( width ) {}
    ~alignedText()
    {
        if ( myOwner != nullptr ) {
            myOwner->flags( myFlags );
        }
    }
    void set( std::ostream& dest ) const
    {
        if ( myOwner == nullptr ) {
            myOwner = &dest;
            myFlags = myOwner->flags();
        }
        dest.setf( std::ios_base::left, std::ios_base::adjustfield );
        dest.width( myWidth );
    }
    friend std::ostream& operator<<( std::ostream& dest, alignedText const& manip )
    {
        manip.set( dest );
        return dest;
    }
};

(虽然可以使用 来完成同样的事情printf,但结果的可读性要差得多,完全无法维护,当然,您通常具有 . 的脆弱性printf。)

于 2013-08-23T09:01:41.460 回答