Index: webrtc/sdk/objc/Framework/Classes/RTCFileLogger.mm |
diff --git a/webrtc/sdk/objc/Framework/Classes/RTCFileLogger.mm b/webrtc/sdk/objc/Framework/Classes/RTCFileLogger.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c1fbd747c3c32a9c0c346879ca3c7f4381b6ac55 |
--- /dev/null |
+++ b/webrtc/sdk/objc/Framework/Classes/RTCFileLogger.mm |
@@ -0,0 +1,176 @@ |
+/* |
+ * Copyright 2015 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#import "WebRTC/RTCFileLogger.h" |
+ |
+#include <memory> |
+ |
+#include "webrtc/base/checks.h" |
+#include "webrtc/base/filerotatingstream.h" |
+#include "webrtc/base/logging.h" |
+#include "webrtc/base/logsinks.h" |
+ |
+NSString *const kDefaultLogDirName = @"webrtc_logs"; |
+NSUInteger const kDefaultMaxFileSize = 10 * 1024 * 1024; // 10MB. |
+const char *kRTCFileLoggerRotatingLogPrefix = "rotating_log"; |
+ |
+@implementation RTCFileLogger { |
+ BOOL _hasStarted; |
+ NSString *_dirPath; |
+ NSUInteger _maxFileSize; |
+ std::unique_ptr<rtc::FileRotatingLogSink> _logSink; |
+} |
+ |
+@synthesize severity = _severity; |
+@synthesize rotationType = _rotationType; |
+@synthesize shouldDisableBuffering = _shouldDisableBuffering; |
+ |
+- (instancetype)init { |
+ NSArray *paths = NSSearchPathForDirectoriesInDomains( |
+ NSDocumentDirectory, NSUserDomainMask, YES); |
+ NSString *documentsDirPath = [paths firstObject]; |
+ NSString *defaultDirPath = |
+ [documentsDirPath stringByAppendingPathComponent:kDefaultLogDirName]; |
+ return [self initWithDirPath:defaultDirPath |
+ maxFileSize:kDefaultMaxFileSize]; |
+} |
+ |
+- (instancetype)initWithDirPath:(NSString *)dirPath |
+ maxFileSize:(NSUInteger)maxFileSize { |
+ return [self initWithDirPath:dirPath |
+ maxFileSize:maxFileSize |
+ rotationType:RTCFileLoggerTypeCall]; |
+} |
+ |
+- (instancetype)initWithDirPath:(NSString *)dirPath |
+ maxFileSize:(NSUInteger)maxFileSize |
+ rotationType:(RTCFileLoggerRotationType)rotationType { |
+ NSParameterAssert(dirPath.length); |
+ NSParameterAssert(maxFileSize); |
+ if (self = [super init]) { |
+ 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 = RTCFileLoggerSeverityInfo; |
+ } |
+ return self; |
+} |
+ |
+- (void)dealloc { |
+ [self stop]; |
+} |
+ |
+- (void)start { |
+ if (_hasStarted) { |
+ return; |
+ } |
+ switch (_rotationType) { |
+ case RTCFileLoggerTypeApp: |
+ _logSink.reset( |
+ new rtc::FileRotatingLogSink(_dirPath.UTF8String, |
+ kRTCFileLoggerRotatingLogPrefix, |
+ _maxFileSize, |
+ _maxFileSize / 10)); |
+ break; |
+ case RTCFileLoggerTypeCall: |
+ _logSink.reset( |
+ new rtc::CallSessionFileRotatingLogSink(_dirPath.UTF8String, |
+ _maxFileSize)); |
+ break; |
+ } |
+ if (!_logSink->Init()) { |
+ LOG(LS_ERROR) << "Failed to open log files at path: " |
+ << _dirPath.UTF8String; |
+ _logSink.reset(); |
+ return; |
+ } |
+ if (_shouldDisableBuffering) { |
+ _logSink->DisableBuffering(); |
+ } |
+ rtc::LogMessage::LogThreads(true); |
+ rtc::LogMessage::LogTimestamps(true); |
+ rtc::LogMessage::AddLogToStream(_logSink.get(), [self rtcSeverity]); |
+ _hasStarted = YES; |
+} |
+ |
+- (void)stop { |
+ if (!_hasStarted) { |
+ return; |
+ } |
+ RTC_DCHECK(_logSink); |
+ rtc::LogMessage::RemoveLogToStream(_logSink.get()); |
+ _hasStarted = NO; |
+ _logSink.reset(); |
+} |
+ |
+- (NSData *)logData { |
+ if (_hasStarted) { |
+ return nil; |
+ } |
+ NSMutableData* logData = [NSMutableData data]; |
+ std::unique_ptr<rtc::FileRotatingStream> stream; |
+ switch(_rotationType) { |
+ case RTCFileLoggerTypeApp: |
+ stream.reset( |
+ new rtc::FileRotatingStream(_dirPath.UTF8String, |
+ kRTCFileLoggerRotatingLogPrefix)); |
+ break; |
+ case RTCFileLoggerTypeCall: |
+ stream.reset(new rtc::CallSessionFileRotatingStream(_dirPath.UTF8String)); |
+ break; |
+ } |
+ if (!stream->Open()) { |
+ return logData; |
+ } |
+ 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. |
+ std::unique_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 RTCFileLoggerSeverityVerbose: |
+ return rtc::LS_VERBOSE; |
+ case RTCFileLoggerSeverityInfo: |
+ return rtc::LS_INFO; |
+ case RTCFileLoggerSeverityWarning: |
+ return rtc::LS_WARNING; |
+ case RTCFileLoggerSeverityError: |
+ return rtc::LS_ERROR; |
+ } |
+} |
+ |
+@end |