就像DCMTK官方论坛说的那个问题一样:问题:自定义Appender输出DCMTK的oflog
大家都知道:DCMTK只提供下面四个日志输出类。
FileAppender: Appends log events to a file.(将DCMTK日志输出到一个文件中)
ConsoleAppender:ConsoleAppender appends log events to STD_NAMESPACE cout
or STD_NAMESPACE cerr
using a layout specified by the user.(将DCMTK日志输出到控制台cmd)
log4cplus::NullAppender:Appends log events to ......(不输出,空的)
SocketAppender:Sends spi::InternalLoggingEvent objects to a remote a log server.(将该日志事件发送给远程服务器)
因为我需要在自己的Qt Gui项目中也输出DCMTK日志,供系统测试或者通过我项目的日志模块登记到数据库、文件中。总之我需要把DCMTK的日志模块集成到自己的Gui项目中。于是我自定义了一个GuiAppender类。
GuiAppender:
实现将DCMTK日志事件捕获,并将日志输出在VS2008的Debug窗口中,也可以后期供调用。
我的GuiAppender类 源码
#ifndef GUIAPPENDER_H #define GUIAPPENDER_H #include "dcmtk/oflog/config.h" #include "dcmtk/oflog/appender.h" #include "dcmtk/oflog/helpers/property.h" #include <sstream> namespace log4cplus { class GuiAppender : public Appender { public: GuiAppender(); GuiAppender(const log4cplus::helpers::Properties& properties, log4cplus::tstring& error); virtual ~GuiAppender(); // Methods virtual void close(); protected: virtual void append(const log4cplus::spi::InternalLoggingEvent& event); //声明一个ostringsteam对象 STD_NAMESPACE ostringstream outString ; private: // Disallow copying of instances of this class GuiAppender(const GuiAppender&); GuiAppender& operator=(const GuiAppender&); }; } // end namespace log4cplus #endif // GUIAPPENDER_H
#include "GuiAppender.h" #include <string> #include <QDebug> #include <QString> log4cplus::GuiAppender::GuiAppender() { } log4cplus::GuiAppender::GuiAppender(const log4cplus::helpers::Properties& properties, tstring&) : Appender(properties) { } log4cplus::GuiAppender::~GuiAppender() { } void log4cplus::GuiAppender::close() { } // This method does not need to be locked since it is called by // doAppend() which performs the locking void log4cplus::GuiAppender::append(const spi::InternalLoggingEvent& event) { //格式化输入DCMTK日志 layout->formatAndAppend(outString, event); //获取DCMTK日志字符串流 STD_NAMESPACE string m = outString.str(); //将C++标准字符串流,转换成QString QString t = QString::fromStdString(m); //输出调试信息 qDebug() << t; //清空 outString.str(""); }
主程序测试。
/* * * Copyright (C) 2011-2012, OFFIS e.V. * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation were developed by * * OFFIS e.V. * R&D Division Health * Escherweg 2 * D-26121 Oldenburg, Germany * * * Module: dcmnet * * Author: Michael Onken * * Purpose: Test for move feature of the DcmSCU class */ #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmnet/diutil.h" #include "DcmTestSCU.h" #include <QtGui/QApplication> #include <QDebug> #include "dcmtk/oflog/oflog.h" #include "GuiAppender.h" #define OFFIS_CONSOLE_APPLICATION "testscu" static OFLogger echoscuLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION); static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v" OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $"; // our application entity title used for calling the peer machine #define APPLICATIONTITLE "TEST-SCU" // host name of the peer machine "www.dicomserver.co.uk" #define PEERHOSTNAME "10.3.2.84" // TCP/IP port to connect to the peer machine "11112" #define PEERPORT 5104 // application entity title of the peer machine #define PEERAPPLICATIONTITLE "MOVESCP" // MOVE destination AE Title #define MOVEAPPLICATIONTITLE "TEST-SCU" #define QRResponse FINDResponse static Uint8 findUncompressedPC(const OFString& sopClass, DcmSCU& scu) { Uint8 pc; pc = scu.findPresentationContextID(sopClass, UID_LittleEndianExplicitTransferSyntax); if (pc == 0) pc = scu.findPresentationContextID(sopClass, UID_BigEndianExplicitTransferSyntax); if (pc == 0) pc = scu.findPresentationContextID(sopClass, UID_LittleEndianImplicitTransferSyntax); return pc; } // ******************************************** int main(int argc, char *argv[]) { QApplication a(argc, argv); /* Setup DICOM connection parameters */ OFLog::configure(OFLogger::DEBUG_LOG_LEVEL); OFLOG_DEBUG(echoscuLogger, "OFLOG_DEBUG"); /* specify log pattern */ OFauto_ptr<log4cplus::Layout> layout(new log4cplus::PatternLayout("%D{%Y-%m-%d %H:%M:%S.%q} %5p: %m%n")); //建立Gui日志输出类 log4cplus::SharedAppenderPtr guiAppender(new log4cplus::GuiAppender()); guiAppender->setLayout(layout); //获取全局日志对象 log4cplus::Logger log = log4cplus::Logger::getRoot(); //去除所有日志输出类 log.removeAllAppenders(); //加入Gui输出类 log.addAppender(guiAppender); //设置日志输出层 log.setLogLevel(OFLogger::INFO_LOG_LEVEL); //测试输出一个error日志 OFLOG_ERROR(log, "There are six log levels and each provides a OFLOG_level() macro"); //继续测试,输出DCMTK C-Echo动作产生的INFO //后面是DCMTK的DcmNet模块中 网络通信的测试,大家不需要了解 DcmTestSCU scu; // set AE titles scu.setAETitle(APPLICATIONTITLE); scu.setPeerHostName(PEERHOSTNAME); scu.setPeerPort(PEERPORT); scu.setPeerAETitle(PEERAPPLICATIONTITLE); // Use presentation context for FIND/MOVE in study root, propose all uncompressed transfer syntaxes OFList<OFString> ts; ts.push_back(UID_LittleEndianExplicitTransferSyntax); ts.push_back(UID_BigEndianExplicitTransferSyntax); ts.push_back(UID_LittleEndianImplicitTransferSyntax); scu.addPresentationContext(UID_FINDStudyRootQueryRetrieveInformationModel, ts); scu.addPresentationContext(UID_MOVEStudyRootQueryRetrieveInformationModel, ts); scu.addPresentationContext(UID_VerificationSOPClass, ts); /* Initialize network */ OFCondition result = scu.initNetwork(); if (result.bad()) { DCMNET_ERROR("Unable to set up the network: " << result.text()); return 1; } /* Negotiate Association */ result = scu.negotiateAssociation(); if (result.bad()) { DCMNET_ERROR("Unable to negotiate association: " << result.text()); return 1; } /* Let's look whether the server is listening: Assemble and send C-ECHO request */ result = scu.sendECHORequest(0); if (result.bad()) { DCMNET_ERROR("Could not process C-ECHO with the server: " << result.text()); return 1; } scu.closeAssociation(DCMSCU_RELEASE_ASSOCIATION); return a.exec(); }
最终结果,将DCMTK日志输出到VS2008的Debug窗口中。
------------------------------------
柳北风儿
http://qimo601.iteye.com
------------------------------------