2009-07-16 5 views
7

다른 라이브러리 또는 실행 파일에서 사용하기위한 C++ 공유 라이브러리를 작성하고 있습니다. 내 라이브러리에 일반 로깅을 추가하는 가장 좋은 방법은 무엇입니까? 이상 적으로는 도서관의 사용자가 선택한 로깅 기능에 내 라이브러리를 적용하고 싶습니다. 난 내 라이브러리 내가 어떤 log4XXX 특정 API에 묶여 내 라이브러리를 만들고 싶어하지 않는C++ 공유 라이브러리에서 일반 로깅 지원 추가

class A { 
    public: 
    void method(string param1, int param2); 
} 

void A::method(string param1, int param2){ 
    /* i want to log values of param1 and param2, 
    but actual logging method must be defined outside of my library. 
    Maybe some kind of macro should help here. */ 
    /*e.g.*/ GENERICLOG_DEBUG("param1=" + param1+ " param2="+param1); 
    /*if so, what that macro body should look like ? */ 
} 

에서 클래스가 있다고 가정 .

답변

8

당신은 라이브러리의 사용자가 자신의 기록에 어댑터와 라이브러리를 제공 할 수 있도록 콜백 메커니즘을 제공 할 수 있습니다.

즉, 라이브러리에 추상적 인 로깅 인터페이스 클래스, 예를 들면 제공과 함께 로거를 regster하는

class Logger 
{ 
public: 
    virtual ~Logger() {} 
    virtual void log (const std::string& message) = 0; 
}; 

및 클래스를 :

라이브러리는 다음과 같이 뭔가를 기록
class Log 
{ 
private: 
    static Logger* logger_; 
public: 
    static void registerLogger (Logger& logger) 
    { logger_ = &logger; } 

    static void log (const std::string& message) 
    { if (logger_ != 0) logger_->log (message); } 
}; 

:

Log::log ("My log message"); 

라이브러리를 사용하는 응용 프로그램은 Logger (즉 구체적인 서브 클래스)를 만들고 Log 클래스에 등록하십시오. Logger impl은 로깅을 구현합니다.

이렇게하면 다른 로깅 라이브러리를 사용하는 응용 프로그램에서 라이브러리를 사용할 수 있습니다.

위의 코드는 기본이며 테스트되지 않았습니다. 실제로는 로그 메서드를 변경하여 로깅 수준 매개 변수 등을 포함 할 수 있습니다.

+0

고마워, 좋은 해결책! 내 사용자 라이브러리에 사용자 로그 프로그램이 등록되지 않은 경우 기본 로깅 (예 : syslog)을 제공 할 수도 있습니다. –

+0

예. –

0

syslog - syslog 기능을 사용할 수 있습니다.

또는 사용자가 콜백을 지정할 수 있습니다.

0

기존 로깅 lib를 사용하지 않으려면 매크로를 사용해보십시오. 나 자신의 lib를 제공하고 printf 형식화 메커니즘과 같은 매크로를 사용할 수 있도록하는 것이 좋습니다.

저는 과거와 비슷한 것을했습니다. 매크로는 플러그인을 통해 확장 할 수 있었던 실제 로깅을 캡슐화하는 로그 객체를 호출합니다.

하지만 Log4xxx에서 이미 비슷한 점이 있다고 생각합니다.

 
#ifdef _MYAPI_IMPL 
#define MY_API __declspec(dllexport) 
#else 
#define MY_API __declspec(dllimport) 
#endif 

class MY_API Log 
{ 
public: 
    enum Level {Error, Warning, Info, Debug}; 
    Log(Level level, const char* file, int line); 
    void operator()(const char* Format, ...); 
private: 
     const char* m_file; 
     Level m_level; 
     int m_line; 
}; 

#define __LOG(lvl) (Log(lvl, __FILE__, __LINE__)) 

#define LOG_ERR __LOG(Log::Error) 
#define LOG_WRN __LOG(Log::Warning) 
#define LOG_INF __LOG(Log::Info) 
#define LOG_DBG __LOG(Log::Debug) 

class My_API Logger 
{ 
public: 
    virtual void log(const char* message)=0; 
}; 

class MY_API LoggerManager 
{ 
private: 
    static LoggerManager* s_inst; 
    LoggerManager() {} 
     virtual ~LoggerManager() {} 
public: 
    static LoggerManager* Instance(); 
    static void Clean(); 
    addLogger(Logger* newLogger, Log::Level minlevel = Log::Info); 
     log(const char* file, int line, Log::Level level, const char* message); 
}; 

CPP :

 

Log::Log(Level level, const char* file, int line) 
: m_file(file), m_level(level), m_line(line) 
{ 
} 

void Log::operator()(const char* format, ...) 
{ 
    va_list va; 
    va_start(va, format); 
    char message[LENGTH+1]={0}; 

    _vsnprintf(message, LENGTH, format, va); 

    va_end(va); 

    LoggerManager::Instance()->log(m_file, m_line, m_level, message); 


}; 

다른 libs와 및 EXE은 할 수 있어야 다음

는 제안 (죄송 시간 나는 그것이 작동하는 희망, 테스트 없음)

헤더입니다 이렇게 전화 해. 그들은 .h와 lib에 링크를 포함시켜야합니다.

 
LOG_INF("Hello %s!", "world"); 

업데이트 : 로깅 메커니즘에 필요한 설명을 추가했습니다. 한 가지 방법은 싱글 톤을 사용하고 실제 로깅을 위해 서브 클래스화할 인터페이스를 제공하는 것입니다.

매크로를 사용하면 매크로가 로그의 위치를 ​​파악할 수있는 이점이 있습니다.이 로그는 매우 흥미로운 정보 일 수 있습니다. 모든 로깅 메커니즘을 구현하지 않으려는 경우 매크로를 일반 printf로 설정할 수도 있습니다.

+0

void Log :: operator() (const char * format, ...); 이 기능에서 메시지의 길이를 "길이"보다 강하게 보장 할 수있는 방법은 무엇입니까? – bbg

+0

나는 당신이 옳다고 생각하며 그러한 해결책을 사용하면서이 점을 돌봐야한다. – luc

1

google-glog를 사용할 수 있습니다. 사용하는 것이 좋습니다.

https://github.com/google/glog

은, 시스템 로그에 기록을 이메일로 보낼 수 있습니다, 파일 디버그 값에 따라 지원하고, 다른 좋은 기능의로드합니다. 라이브러리에 로깅 기능의

1

선언 프로토 타입 :

extern void __cdecl UserLog(char* stText);

이 라이브러리에 그것을 구현하지 마십시오. 라이브러리 사용자는이 기능을 구현해야하며 라이브러리는 사용자 구현을 사용합니다.

사용자의 구현 (즉, 그냥 샘플입니다) 다음과 같이 수 : 라이브러리에 정적 라이브러리의 경우 유효입니다

void __cdecl UserLog(char* stText) 
{ 
    std::cout << stText << std::endl; 
}

합니다. 코드에서

다음과 같은 방법으로 사용할 수 있습니다 :

class A { 
    public: 
    void method(string param1, int param2); 
} 

void A::method(string param1, int param2){ 
    string formatted = str(boost::format("param1=%s param2=%d") % param1 % param2); 
    UserLog(formatted.c_str()); 
}
관련 문제