首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >测井机理

测井机理
EN

Code Review用户
提问于 2015-06-19 10:51:46
回答 2查看 265关注 0票数 1

我有以下代码:

代码语言:javascript
复制
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <cassert>
#include <vector>
#include <cstdlib>
#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <boost/filesystem.hpp>

using namespace std;
using namespace boost::filesystem;

static ofstream Log; // For information-level messages
static stringstream LogErrorStream;  // Buffer soft errors to output them separately after the informational messages in the log file.

// Convert any type to its string representation
template<typename T> static string ToString( const T& obj )
{
    stringstream ss;
    ss << obj;
    return ss.str();
}

// Escape HTML special characters
static string EscapeHTMLSpecialChars( const path& PathName, const bool& href = false )
{
    string in = PathName.string();
    string ret;
    for ( decltype( in.size() ) i = 0; i < in.size(); i++ )
    {
        if ( in[i] == '&' )
        {
            ret += "&";
        }
        else if ( in[i] == '<' )
        {
            ret += "<";
        }
        else if ( in[i] == '>' )
        {
            ret += ">";
        }
        else if ( in[i] == '"' )
        {
            ret += """;
        }
        else if ( in[i] == '\'' )
        {
            ret += "'";
        }
        else if ( href && in[i] == '#' ) // If the input is an href attribute
        {
            ret += "%23";
        }
        else if ( href && in[i] == '?' )
        {
            ret += "%3F";
        }
        else
        {
            ret += in[i];
        }
    }
    return ret;
}

// Convert the input size ( in bytes ) to its nearest units in the ratio of 1024.
// ( Trying to do how Windows reports size of a file on right clicking and checking its properties )
static string RoundSize( const long long& size )
{
    double ret = ( double )size;
    static const vector<string> units {"bytes", "KiB", "MiB", "GiB", "TiB"};
    const unsigned ratio = 1024;
    unsigned i;
    for ( i = 0; ret > ratio && i < units.size() - 1; i++ )
    {
        ret /= ratio;
    }
    return ToString( ret ) + " " + units[i];
}

// Iterate through a directory and store everything found ( regular files, directories or any other special files ) in the input container
static void DirectoryIterate( const path& dirPath, vector<path>& dirContents )
{
    if ( is_directory( dirPath ) )
    {
        copy( directory_iterator( dirPath ), directory_iterator(), back_inserter( dirContents ) );
    }
}

// Returns the difference in height in the filesystem tree, between the directory "parent" and the file/folder "descendant"
static int HeightDiff( const path parent, path descendant )
{
    int diff = 0;
    while ( descendant != parent )
    {
        descendant = descendant.parent_path();
        if ( descendant.empty() )
        {
            diff = -1;  // "descendant" is in fact not a descendant of "parent"
            break;
        }
        diff++;
    }
    return diff;
}

// Returns true if the file/folder "descendant" is a descendant of the directory "parent"
static bool IsDescendant( const path parent, path descendant )
{
    return HeightDiff( parent, descendant ) >= 1;
}

// Create a set of HTML files containing information about source directory's contents and store it in the destination directory, in a directory structure similar to the source directory
// Returns the total size of the source directory
static long long Snapshot( const path& sourcePath, const path& destinationPath )
{
    Log << sourcePath << endl;

    // This should be executed only once during the whole program execution ( during the first invocation of Snapshot() )
    static bool isDescendant = IsDescendant( sourcePath, destinationPath );
    if ( isDescendant )
    {
        LogErrorStream << "The destination path cannot be a descendant of the source path!! Please provide an alternate destination path !!" << endl;
        return -1;
    }

    boost::system::error_code ec;

    long long sourcePathSize = 0; // Total size of the source directory

    vector<path> dirContents, files, directories;
    try
    {
        DirectoryIterate( sourcePath, dirContents );
    }
    catch ( const filesystem_error& ex )
    {
        LogErrorStream << ex.what() << endl;
        return 0; // cannot iterate through the directory, so no point in going further
    }

    sort( dirContents.begin(), dirContents.end() ); // sort, since directory iteration is not ordered on some file systems
    for ( const auto& item : dirContents )
    {
        ec.clear();
        if ( is_directory( item, ec ) )
        {
            directories.push_back( item );
        }
        else if ( !ec )
        {
            files.push_back( item );
        }
        else
        {
            LogErrorStream << "Failed to determine if " << absolute( item ) << " is a directory or not : " << ec.message() << endl;
        }
    }

    const path pwd = destinationPath / sourcePath.filename(); // Present working directory
    ec.clear();
    create_directory( pwd, ec );
    if ( ec )
    {
        LogErrorStream << "Failed to create " << absolute( pwd ) << " : " << ec.message() << endl;
        return 0;
    }

    // Create the output file.
    const path outFilePath = ( pwd / sourcePath.filename() ).string() + ".html";
    ofstream outFile( outFilePath.string() );
    if ( !outFile )
    {
        LogErrorStream << "Failed to create " << absolute( outFilePath ) << " : " << strerror( errno ) << endl;
        return 0;
    }

    // Write the HTML file header.
    outFile << ""
                    "<!DOCTYPE html>\n"
                    "<html>\n"
                    "<head>\n"
                    "<meta charset=\"UTF-8\">\n"
                    "<title>" << EscapeHTMLSpecialChars( sourcePath.filename() ) << "</title>\n"
                    "</head>\n"
                    "<body>\n";

    // Write information about the files contained in the source directory
    outFile << ""
                    "<h1> Files </h1>\n"
                    "<table>\n";
    for ( const auto& file : files )
    {
        outFile << ""
                        " <tr>\n"
                        "  <td>" << EscapeHTMLSpecialChars( file.filename() ) << "</td>\n"
                        "  <td>";

        ec.clear();
        auto size = file_size( file, ec );
        if ( ec )
        {
            LogErrorStream << "Failed to read size of " << absolute( file ) << " : " << ec.message() << endl;
        }
        else
        {
            outFile << RoundSize( size );
            sourcePathSize += size;
        }
        outFile << ""
                        "</td>\n"
                        " </tr>\n";
    }
    outFile << "</table>\n";

    // Write information about the directories contained in the source directory
    outFile << ""
                    "<h1> Directories </h1>\n"
                    "<table>\n";
    for ( const auto& directory : directories )
    {
        long long size = Snapshot( sourcePath / directory.filename(), pwd );
        sourcePathSize += size;
        outFile << ""
                        " <tr>\n"
                        "  <td><a href=\"" << EscapeHTMLSpecialChars( ( directory.filename() / directory.filename() ).generic_string(), true ) << ".html\">" << EscapeHTMLSpecialChars( directory.filename() ) << "</a></td>\n" <<
                        "  <td>" << RoundSize( size ) << "</td>\n"
                        " </tr>\n";
    }
    outFile << "</table>\n";

    // Write the footer
    outFile << ""
                    "<br>\n"
                    "<h3>Total directory size = " << RoundSize( sourcePathSize ) << "</h3><br>\n"
                    "</body>\n"
                    "</html>\n";

    return sourcePathSize;
}

int main( int argc, char** argv )
{
    const path defaultLogFilePath = "DirectorySnapshotLog.txt";

    if ( argc < 3 )
    {
        cout << "Usage : " << argv[0] << " <source_directory_path> <destination_directory_path> [log_file_path=" << defaultLogFilePath << "]\n";
        return -1;
    }

    const path LogFilePath = ( ( argc >= 4 ) ? path( argv[3] ) : defaultLogFilePath );
    Log.open( LogFilePath.string() );
    if ( !Log )
    {
        cerr << "Error creating " << absolute( LogFilePath ) << " : " << strerror( errno ) << endl;
        return -1;
    }

    try
    {
        Snapshot( canonical( argv[1] ), canonical( argv[2] ) );
    }
    catch ( const filesystem_error& ex )
    {
        LogErrorStream << ex.what() << endl;
    }

    if ( Log )
    {
        if ( LogErrorStream.str().empty() )
        {
            cout << "The program ran without any errors.\n";
        }
        else
        {
            Log << "\nERRORS -:\n\n" << LogErrorStream.str() << endl;
            cout << "There were some errors during the execution of this program !\n\nCheck " << absolute( LogFilePath ) << " for details.\n";
            return -1;
        }
    }
}

我当前的日志记录策略是使用Log立即输出所有信息级别的消息,并且只有在输出了所有信息级别的消息之后才输出错误级别的消息。为了实现这一点,我将错误级别的消息存储在stringstream对象中,并在程序结束时输出它。

这种策略的基本原理是,我希望通过查看日志文件并间歇性地刷新日志文件,查看程序当前运行的目录。我不使用stdout进行信息级别的日志记录,因为我想存储它以进行调试,以防程序崩溃。

我对此策略持怀疑态度的原因是,如果程序崩溃,错误级别的消息可能不会写入文件。因此,我能想到的唯一选择是,在遇到所有错误消息时立即记录它们,而不是先缓冲它们。

这两个选项中哪一个更适合程序流程?还有比这两个更好的选择吗?

我使用GCC 4.9.2和-std=c++14选项。

EN

回答 2

Code Review用户

回答已采纳

发布于 2015-06-19 11:49:49

这两个选项中哪一个更适合程序流程?

视情况而定。既不适合所有情况,也不适合最佳情况。

还有比这两个更好的选择吗?

是。通常,日志记录是应用程序功能的一个模块/部分,与其他功能正交(也就是说,您应该能够在不更改日志代码实现的情况下更改应用程序逻辑,并且可以更改日志代码而不更改应用程序逻辑)。

因此,日志记录通常是作为一个单独的库实现的,应该支持:

  • 多个接收器(同时向多个日志写入消息)
  • 消息元数据(模块名称、线程id、时间、消息类型等)
  • 消息的优先发送(可以/应该以与错误不同的方式处理警告)
  • 运行时配置

作为替代,看看一些c++测井框架 (谷歌搜索的结果)和这个问题

票数 2
EN

Code Review用户

发布于 2015-06-19 12:58:04

对于高效的日志记录机制,您需要:

  • 它将在由发件人(log_msg,log_msgf .)提供的单独线程(日志服务)中处理。通过(线程)队列。
  • 多源和消息级别
  • “发送”方法(S)尽可能少地执行(选择没有输出的消息,获取时间,构建/复制(格式化的)文本并发送到服务)。如果源没有消息级别的输出,则能够快速忽略消息是原始的。发送到日志记录服务的消息的池很可能是必需的。
  • 能够使用过滤器在不同介质上输出(即:从该源到这些输出的错误)
  • 输出用类似于“上面的行被重复了X次”来“总结”输出,帮助IOs保持低水平(这种情况经常发生)
  • 减少IOs,这意味着对输出进行缓冲写入。因此,在某些情况下,您还需要能够刷新一个或所有输出(即:中止之前的关键消息)。
  • 为了能够发出“重新打开”输出的命令(因此您可以“滚动”日志)
  • 您还想问问自己是否允许自己丢失一条消息(即:如果磁盘和服务队列已满怎么办?阻止还是等待?)

日志确实是一个非常有趣的问题。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/94064

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档