12d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin/* 22d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * libjingle 32d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * Copyright 2015 Google Inc. 42d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * 52d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * Redistribution and use in source and binary forms, with or without 62d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * modification, are permitted provided that the following conditions are met: 72d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * 82d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * 1. Redistributions of source code must retain the above copyright notice, 92d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * this list of conditions and the following disclaimer. 102d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * 2. Redistributions in binary form must reproduce the above copyright notice, 112d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * this list of conditions and the following disclaimer in the documentation 122d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * and/or other materials provided with the distribution. 132d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * 3. The name of the author may not be used to endorse or promote products 142d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * derived from this software without specific prior written permission. 152d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * 162d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 172d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 182d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 192d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 202d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 212d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 222d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 232d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 242d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 252d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 262d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin */ 272d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 282d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin#import "RTCFileLogger.h" 292d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 302d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin#include "webrtc/base/checks.h" 3128bae02bd383abbd35cc87fa1188a569f1b3c683tkchin#include "webrtc/base/filerotatingstream.h" 322d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin#include "webrtc/base/logging.h" 3328bae02bd383abbd35cc87fa1188a569f1b3c683tkchin#include "webrtc/base/logsinks.h" 342d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin#include "webrtc/base/scoped_ptr.h" 352d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 3628bae02bd383abbd35cc87fa1188a569f1b3c683tkchinNSString *const kDefaultLogDirName = @"webrtc_logs"; 372d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke ChinNSUInteger const kDefaultMaxFileSize = 10 * 1024 * 1024; // 10MB. 38d02b0fab76847c72bd45e5a40763255283abe212hayscconst char *kRTCFileLoggerRotatingLogPrefix = "rotating_log"; 392d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 402d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin@implementation RTCFileLogger { 412d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin BOOL _hasStarted; 4228bae02bd383abbd35cc87fa1188a569f1b3c683tkchin NSString *_dirPath; 432d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin NSUInteger _maxFileSize; 44d02b0fab76847c72bd45e5a40763255283abe212haysc rtc::scoped_ptr<rtc::FileRotatingLogSink> _logSink; 452d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin} 462d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 472d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin@synthesize severity = _severity; 48d02b0fab76847c72bd45e5a40763255283abe212haysc@synthesize rotationType = _rotationType; 492d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 502d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin- (instancetype)init { 512d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin NSArray *paths = NSSearchPathForDirectoriesInDomains( 522d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin NSDocumentDirectory, NSUserDomainMask, YES); 532d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin NSString *documentsDirPath = [paths firstObject]; 5428bae02bd383abbd35cc87fa1188a569f1b3c683tkchin NSString *defaultDirPath = 5528bae02bd383abbd35cc87fa1188a569f1b3c683tkchin [documentsDirPath stringByAppendingPathComponent:kDefaultLogDirName]; 5628bae02bd383abbd35cc87fa1188a569f1b3c683tkchin return [self initWithDirPath:defaultDirPath 5728bae02bd383abbd35cc87fa1188a569f1b3c683tkchin maxFileSize:kDefaultMaxFileSize]; 582d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin} 592d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 6028bae02bd383abbd35cc87fa1188a569f1b3c683tkchin- (instancetype)initWithDirPath:(NSString *)dirPath 6128bae02bd383abbd35cc87fa1188a569f1b3c683tkchin maxFileSize:(NSUInteger)maxFileSize { 62d02b0fab76847c72bd45e5a40763255283abe212haysc return [self initWithDirPath:dirPath 63d02b0fab76847c72bd45e5a40763255283abe212haysc maxFileSize:maxFileSize 64d02b0fab76847c72bd45e5a40763255283abe212haysc rotationType:kRTCFileLoggerTypeCall]; 65d02b0fab76847c72bd45e5a40763255283abe212haysc} 66d02b0fab76847c72bd45e5a40763255283abe212haysc 67d02b0fab76847c72bd45e5a40763255283abe212haysc- (instancetype)initWithDirPath:(NSString *)dirPath 68d02b0fab76847c72bd45e5a40763255283abe212haysc maxFileSize:(NSUInteger)maxFileSize 69d02b0fab76847c72bd45e5a40763255283abe212haysc rotationType:(RTCFileLoggerRotationType)rotationType { 7028bae02bd383abbd35cc87fa1188a569f1b3c683tkchin NSParameterAssert(dirPath.length); 712d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin NSParameterAssert(maxFileSize); 722d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin if (self = [super init]) { 7328bae02bd383abbd35cc87fa1188a569f1b3c683tkchin BOOL isDir = NO; 7428bae02bd383abbd35cc87fa1188a569f1b3c683tkchin NSFileManager *fileManager = [NSFileManager defaultManager]; 7528bae02bd383abbd35cc87fa1188a569f1b3c683tkchin if ([fileManager fileExistsAtPath:dirPath isDirectory:&isDir]) { 7628bae02bd383abbd35cc87fa1188a569f1b3c683tkchin if (!isDir) { 7728bae02bd383abbd35cc87fa1188a569f1b3c683tkchin // Bail if something already exists there. 7828bae02bd383abbd35cc87fa1188a569f1b3c683tkchin return nil; 7928bae02bd383abbd35cc87fa1188a569f1b3c683tkchin } 8028bae02bd383abbd35cc87fa1188a569f1b3c683tkchin } else { 8128bae02bd383abbd35cc87fa1188a569f1b3c683tkchin if (![fileManager createDirectoryAtPath:dirPath 8228bae02bd383abbd35cc87fa1188a569f1b3c683tkchin withIntermediateDirectories:NO 8328bae02bd383abbd35cc87fa1188a569f1b3c683tkchin attributes:nil 8428bae02bd383abbd35cc87fa1188a569f1b3c683tkchin error:nil]) { 8528bae02bd383abbd35cc87fa1188a569f1b3c683tkchin // Bail if we failed to create a directory. 8628bae02bd383abbd35cc87fa1188a569f1b3c683tkchin return nil; 8728bae02bd383abbd35cc87fa1188a569f1b3c683tkchin } 8828bae02bd383abbd35cc87fa1188a569f1b3c683tkchin } 8928bae02bd383abbd35cc87fa1188a569f1b3c683tkchin _dirPath = dirPath; 902d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin _maxFileSize = maxFileSize; 912d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin _severity = kRTCFileLoggerSeverityInfo; 922d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin } 932d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin return self; 942d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin} 952d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 962d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin- (void)dealloc { 972d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin [self stop]; 982d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin} 992d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 1002d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin- (void)start { 1012d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin if (_hasStarted) { 1022d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin return; 1032d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin } 104d02b0fab76847c72bd45e5a40763255283abe212haysc switch (_rotationType) { 105d02b0fab76847c72bd45e5a40763255283abe212haysc case kRTCFileLoggerTypeApp: 106d02b0fab76847c72bd45e5a40763255283abe212haysc _logSink.reset( 107d02b0fab76847c72bd45e5a40763255283abe212haysc new rtc::FileRotatingLogSink(_dirPath.UTF8String, 108d02b0fab76847c72bd45e5a40763255283abe212haysc kRTCFileLoggerRotatingLogPrefix, 109d02b0fab76847c72bd45e5a40763255283abe212haysc _maxFileSize, 110d02b0fab76847c72bd45e5a40763255283abe212haysc _maxFileSize / 10)); 111d02b0fab76847c72bd45e5a40763255283abe212haysc break; 112d02b0fab76847c72bd45e5a40763255283abe212haysc case kRTCFileLoggerTypeCall: 113d02b0fab76847c72bd45e5a40763255283abe212haysc _logSink.reset( 114d02b0fab76847c72bd45e5a40763255283abe212haysc new rtc::CallSessionFileRotatingLogSink(_dirPath.UTF8String, 115d02b0fab76847c72bd45e5a40763255283abe212haysc _maxFileSize)); 116d02b0fab76847c72bd45e5a40763255283abe212haysc break; 117d02b0fab76847c72bd45e5a40763255283abe212haysc } 11828bae02bd383abbd35cc87fa1188a569f1b3c683tkchin if (!_logSink->Init()) { 11928bae02bd383abbd35cc87fa1188a569f1b3c683tkchin LOG(LS_ERROR) << "Failed to open log files at path: " 12028bae02bd383abbd35cc87fa1188a569f1b3c683tkchin << _dirPath.UTF8String; 1212d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin _logSink.reset(); 1222d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin return; 1232d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin } 1242d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin rtc::LogMessage::LogThreads(true); 1252d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin rtc::LogMessage::LogTimestamps(true); 1262d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin rtc::LogMessage::AddLogToStream(_logSink.get(), [self rtcSeverity]); 1272d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin _hasStarted = YES; 1282d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin} 1292d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 1302d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin- (void)stop { 1312d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin if (!_hasStarted) { 1322d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin return; 1332d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin } 13491d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg RTC_DCHECK(_logSink); 1352d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin rtc::LogMessage::RemoveLogToStream(_logSink.get()); 1362d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin _hasStarted = NO; 13728bae02bd383abbd35cc87fa1188a569f1b3c683tkchin _logSink.reset(); 1382d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin} 1392d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 1402d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin- (NSData *)logData { 1412d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin if (_hasStarted) { 1422d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin return nil; 1432d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin } 14428bae02bd383abbd35cc87fa1188a569f1b3c683tkchin NSMutableData* logData = [NSMutableData data]; 145d02b0fab76847c72bd45e5a40763255283abe212haysc rtc::scoped_ptr<rtc::FileRotatingStream> stream; 146d02b0fab76847c72bd45e5a40763255283abe212haysc switch(_rotationType) { 147d02b0fab76847c72bd45e5a40763255283abe212haysc case kRTCFileLoggerTypeApp: 148d02b0fab76847c72bd45e5a40763255283abe212haysc stream.reset( 149d02b0fab76847c72bd45e5a40763255283abe212haysc new rtc::FileRotatingStream(_dirPath.UTF8String, 150d02b0fab76847c72bd45e5a40763255283abe212haysc kRTCFileLoggerRotatingLogPrefix)); 151d02b0fab76847c72bd45e5a40763255283abe212haysc break; 152d02b0fab76847c72bd45e5a40763255283abe212haysc case kRTCFileLoggerTypeCall: 153d02b0fab76847c72bd45e5a40763255283abe212haysc stream.reset(new rtc::CallSessionFileRotatingStream(_dirPath.UTF8String)); 154d02b0fab76847c72bd45e5a40763255283abe212haysc break; 155d02b0fab76847c72bd45e5a40763255283abe212haysc } 15628bae02bd383abbd35cc87fa1188a569f1b3c683tkchin if (!stream->Open()) { 15728bae02bd383abbd35cc87fa1188a569f1b3c683tkchin return logData; 1582d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin } 15928bae02bd383abbd35cc87fa1188a569f1b3c683tkchin size_t bufferSize = 0; 16028bae02bd383abbd35cc87fa1188a569f1b3c683tkchin if (!stream->GetSize(&bufferSize) || bufferSize == 0) { 16128bae02bd383abbd35cc87fa1188a569f1b3c683tkchin return logData; 1622d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin } 16328bae02bd383abbd35cc87fa1188a569f1b3c683tkchin size_t read = 0; 1642d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin // Allocate memory using malloc so we can pass it direcly to NSData without 1652d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin // copying. 16628bae02bd383abbd35cc87fa1188a569f1b3c683tkchin rtc::scoped_ptr<uint8_t[]> buffer(static_cast<uint8_t*>(malloc(bufferSize))); 16728bae02bd383abbd35cc87fa1188a569f1b3c683tkchin stream->ReadAll(buffer.get(), bufferSize, &read, nullptr); 16828bae02bd383abbd35cc87fa1188a569f1b3c683tkchin logData = [[NSMutableData alloc] initWithBytesNoCopy:buffer.release() 16928bae02bd383abbd35cc87fa1188a569f1b3c683tkchin length:read]; 17028bae02bd383abbd35cc87fa1188a569f1b3c683tkchin return logData; 1712d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin} 1722d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 17328bae02bd383abbd35cc87fa1188a569f1b3c683tkchin#pragma mark - Private 17428bae02bd383abbd35cc87fa1188a569f1b3c683tkchin 1752d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin- (rtc::LoggingSeverity)rtcSeverity { 1762d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin switch (_severity) { 1772d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin case kRTCFileLoggerSeverityVerbose: 1782d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin return rtc::LS_VERBOSE; 1792d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin case kRTCFileLoggerSeverityInfo: 1802d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin return rtc::LS_INFO; 1812d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin case kRTCFileLoggerSeverityWarning: 1822d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin return rtc::LS_WARNING; 1832d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin case kRTCFileLoggerSeverityError: 1842d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin return rtc::LS_ERROR; 1852d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin } 1862d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin} 1872d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin 1882d3b7e2173c672dca5d97d9a5c8ab4217652c442Zeke Chin@end 189