| 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..3080ebc080ec9b13fe421afdcfb8e7930cb38891 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,35 @@ 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];
|
| -}
|
| -
|
| -#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;
|
| + size_t bufferSize = 0;
|
| + if (!stream->GetSize(&bufferSize) || bufferSize == 0) {
|
| + return logData;
|
| }
|
| + size_t read = 0;
|
| // 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::scoped_ptr<uint8_t[]> buffer(static_cast<uint8_t*>(malloc(bufferSize)));
|
| + stream->ReadAll(buffer.get(), bufferSize, &read, nullptr);
|
| + logData = [[NSMutableData alloc] initWithBytesNoCopy:buffer.release()
|
| + length:read];
|
| + return logData;
|
| }
|
|
|
| +#pragma mark - Private
|
| +
|
| - (rtc::LoggingSeverity)rtcSeverity {
|
| switch (_severity) {
|
| case kRTCFileLoggerSeverityVerbose:
|
|
|