Chromium Code Reviews| Index: talk/app/webrtc/objc/RTCFileLogger.mm |
| diff --git a/talk/app/webrtc/objc/RTCFileLogger.mm b/talk/app/webrtc/objc/RTCFileLogger.mm |
| index b474d7a5c65dec7f9b0673300998980009e93b4c..cf6b2b6ef6432f3ad3c8372365453dc0bb520614 100644 |
| --- a/talk/app/webrtc/objc/RTCFileLogger.mm |
| +++ b/talk/app/webrtc/objc/RTCFileLogger.mm |
| @@ -28,45 +28,19 @@ |
| #import "RTCFileLogger.h" |
| #include "webrtc/base/checks.h" |
| +#include "webrtc/base/filerotatingstream.h" |
| #include "webrtc/base/logging.h" |
| +#include "webrtc/base/logsinks.h" |
| #include "webrtc/base/scoped_ptr.h" |
| -#include "webrtc/base/stream.h" |
| -NSString *const kDefaultLogFileName = @"webrtc.log"; |
| +NSString *const kDefaultLogDirName = @"webrtc_logs"; |
| NSUInteger const kDefaultMaxFileSize = 10 * 1024 * 1024; // 10MB. |
| -namespace rtc { |
| - |
| -class CircularFileStreamLogSink : public LogSink { |
| - public: |
| - // Creates a log sink that writes to the given stream. This log sink takes |
| - // ownership of |stream|. |
| - CircularFileStreamLogSink(CircularFileStream *stream) { |
| - DCHECK(stream); |
| - _stream.reset(stream); |
| - } |
| - |
| - ~CircularFileStreamLogSink() override {} |
| - |
| - void OnLogMessage(const std::string &message) override { |
| - if (_stream) { |
| - _stream->WriteAll(message.data(), message.size(), nullptr, nullptr); |
| - } |
| - } |
| - |
| - CircularFileStream *GetStream() { return _stream.get(); } |
| - |
| - private: |
| - scoped_ptr<CircularFileStream> _stream; |
| -}; |
| - |
| -} // namespace rtc |
| - |
| @implementation RTCFileLogger { |
| BOOL _hasStarted; |
| - NSString *_filePath; |
| + NSString *_dirPath; |
| NSUInteger _maxFileSize; |
| - rtc::scoped_ptr<rtc::CircularFileStreamLogSink> _logSink; |
| + rtc::scoped_ptr<rtc::CallSessionFileRotatingLogSink> _logSink; |
| } |
| @synthesize severity = _severity; |
| @@ -75,18 +49,34 @@ class CircularFileStreamLogSink : public LogSink { |
| NSArray *paths = NSSearchPathForDirectoriesInDomains( |
| NSDocumentDirectory, NSUserDomainMask, YES); |
| NSString *documentsDirPath = [paths firstObject]; |
| - NSString *defaultFilePath = |
| - [documentsDirPath stringByAppendingPathComponent:kDefaultLogFileName]; |
| - return [self initWithFilePath:defaultFilePath |
| - maxFileSize:kDefaultMaxFileSize]; |
| + NSString *defaultDirPath = |
| + [documentsDirPath stringByAppendingPathComponent:kDefaultLogDirName]; |
| + return [self initWithDirPath:defaultDirPath |
| + maxFileSize:kDefaultMaxFileSize]; |
| } |
| -- (instancetype)initWithFilePath:(NSString *)filePath |
| - maxFileSize:(NSUInteger)maxFileSize { |
| - NSParameterAssert(filePath.length); |
| +- (instancetype)initWithDirPath:(NSString *)dirPath |
| + maxFileSize:(NSUInteger)maxFileSize { |
| + NSParameterAssert(dirPath.length); |
| NSParameterAssert(maxFileSize); |
| if (self = [super init]) { |
| - _filePath = filePath; |
| + BOOL isDir = NO; |
| + NSFileManager *fileManager = [NSFileManager defaultManager]; |
| + if ([fileManager fileExistsAtPath:dirPath isDirectory:&isDir]) { |
| + if (!isDir) { |
| + // Bail if something already exists there. |
| + return nil; |
| + } |
| + } else { |
| + if (![fileManager createDirectoryAtPath:dirPath |
| + withIntermediateDirectories:NO |
| + attributes:nil |
| + error:nil]) { |
| + // Bail if we failed to create a directory. |
| + return nil; |
| + } |
| + } |
| + _dirPath = dirPath; |
| _maxFileSize = maxFileSize; |
| _severity = kRTCFileLoggerSeverityInfo; |
| } |
| @@ -101,19 +91,14 @@ class CircularFileStreamLogSink : public LogSink { |
| if (_hasStarted) { |
| return; |
| } |
| - rtc::scoped_ptr<rtc::CircularFileStream> stream; |
| - stream.reset(new rtc::CircularFileStream(_maxFileSize)); |
| - _logSink.reset(new rtc::CircularFileStreamLogSink(stream.release())); |
| - int error = 0; |
| - if (!_logSink->GetStream()->Open(_filePath.UTF8String, "wb", &error)) { |
| - LOG(LS_ERROR) << "Failed to open log file at path: " |
| - << _filePath.UTF8String |
| - << " Error: " |
| - << error; |
| + _logSink.reset(new rtc::CallSessionFileRotatingLogSink(_dirPath.UTF8String, |
| + _maxFileSize)); |
| + if (!_logSink->Init()) { |
| + LOG(LS_ERROR) << "Failed to open log files at path: " |
| + << _dirPath.UTF8String; |
| _logSink.reset(); |
| return; |
| } |
| - // TODO(tkchin): Log thead info on iOS, currently this doesn't do anything. |
| rtc::LogMessage::LogThreads(true); |
| rtc::LogMessage::LogTimestamps(true); |
| rtc::LogMessage::AddLogToStream(_logSink.get(), [self rtcSeverity]); |
| @@ -127,93 +112,31 @@ class CircularFileStreamLogSink : public LogSink { |
| DCHECK(_logSink); |
| rtc::LogMessage::RemoveLogToStream(_logSink.get()); |
| _hasStarted = NO; |
| - |
| - // Read the ordered version of the log. |
| - NSData *logData = [self reorderedLogData]; |
| - NSError *error = nil; |
| - // Write the ordered version back to disk. |
| - if (![logData writeToFile:_filePath |
| - options:NSDataWritingAtomic |
| - error:&error]) { |
| - LOG(LS_ERROR) << "Failed to rewrite log to disk at path: " |
| - << _filePath.UTF8String; |
| - if (error) { |
| - LOG(LS_ERROR) << "Error: " << error.localizedDescription.UTF8String; |
| - } |
| - } else { |
| - // If we succeeded in writing to disk we don't need to hold on to the |
| - // stream anymore. |
| - _logSink.reset(); |
| - } |
| + _logSink.reset(); |
| } |
| - (NSData *)logData { |
| if (_hasStarted) { |
| return nil; |
| } |
| - if (!_logSink.get()) { |
| - // If there isn't a previously used stream just return contents of file. |
| - return [[self class] contentsOfFileAtPath:_filePath]; |
| + NSMutableData* logData = [NSMutableData data]; |
| + rtc::scoped_ptr<rtc::CallSessionFileRotatingStream> stream( |
| + new rtc::CallSessionFileRotatingStream(_dirPath.UTF8String)); |
| + if (!stream->Open()) { |
| + return logData; |
| } |
| - return [self reorderedLogData]; |
| + const size_t bufferSize = 1024; |
| + size_t read = 0; |
| + rtc::scoped_ptr<uint8_t[]> buffer(new uint8_t[bufferSize]); |
| + do { |
| + stream->ReadAll(buffer.get(), bufferSize, &read, nullptr); |
| + [logData appendBytes:buffer.get() length:read]; |
| + } while (read > 0); |
|
jiayl2
2015/07/22 21:17:33
Do we need the loop because ReadAll may exit when
tkchin_webrtc
2015/07/22 23:01:39
No, it's because the buffer may be too big or too
jiayl2
2015/07/22 23:35:01
Ah, I see. I think this is fine.
|
| + return logData; |
| } |
| #pragma mark - Private |
| -+ (NSData *)contentsOfFileAtPath:(NSString *)path { |
| - NSError *error = nil; |
| - NSData *contents = [NSData dataWithContentsOfFile:path |
| - options:0 |
| - error:&error]; |
| - if (error) { |
| - LOG(LS_ERROR) << "Failed to read contents of file at path: " |
| - << path.UTF8String |
| - << " Error: " |
| - << error.localizedDescription.UTF8String; |
| - return nil; |
| - } |
| - return contents; |
| -} |
| - |
| -- (NSData *)reorderedLogData { |
| - if (_hasStarted || !_logSink.get()) { |
| - return nil; |
| - } |
| - // We have a stream we used for writing in memory and we're not writing. The |
| - // stream has a pointer to where the log boundary is so it can reorder the |
| - // log correctly. We just need to reopen the file in read mode. |
| - int error = 0; |
| - rtc::CircularFileStream *stream = _logSink->GetStream(); |
| - if (!stream->Open(_filePath.UTF8String, "r", &error)) { |
| - LOG(LS_ERROR) << "Failed to open log file at path: " |
| - << _filePath.UTF8String |
| - << " Error: " |
| - << error; |
| - return nil; |
| - } |
| - size_t logSize = 0; |
| - size_t bytesRead = 0; |
| - error = 0; |
| - if (!stream->GetSize(&logSize)) { |
| - LOG(LS_ERROR) << "Failed to get log file size."; |
| - return nil; |
| - } |
| - // Allocate memory using malloc so we can pass it direcly to NSData without |
| - // copying. |
| - rtc::scoped_ptr<uint8_t[]> buffer(static_cast<uint8_t*>(malloc(logSize))); |
| - if (stream->ReadAll(buffer.get(), logSize, &bytesRead, &error) |
| - != rtc::SR_SUCCESS) { |
| - LOG(LS_ERROR) << "Failed to read log file at path: " |
| - << _filePath.UTF8String |
| - << " Error: " |
| - << error; |
| - } |
| - DCHECK_LE(bytesRead, logSize); |
| - // NSData takes ownership of the bytes and frees it on dealloc. |
| - return [NSData dataWithBytesNoCopy:buffer.release() |
| - length:bytesRead]; |
| -} |
| - |
| - (rtc::LoggingSeverity)rtcSeverity { |
| switch (_severity) { |
| case kRTCFileLoggerSeverityVerbose: |