OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #import "RTCFileLogger.h" | |
12 | |
13 #include "webrtc/base/checks.h" | |
14 #include "webrtc/base/filerotatingstream.h" | |
15 #include "webrtc/base/logging.h" | |
16 #include "webrtc/base/logsinks.h" | |
17 #include "webrtc/base/scoped_ptr.h" | |
18 | |
19 NSString *const kDefaultLogDirName = @"webrtc_logs"; | |
20 NSUInteger const kDefaultMaxFileSize = 10 * 1024 * 1024; // 10MB. | |
21 const char *kRTCFileLoggerRotatingLogPrefix = "rotating_log"; | |
22 | |
23 @implementation RTCFileLogger { | |
24 BOOL _hasStarted; | |
25 NSString *_dirPath; | |
26 NSUInteger _maxFileSize; | |
27 rtc::scoped_ptr<rtc::FileRotatingLogSink> _logSink; | |
28 } | |
29 | |
30 @synthesize severity = _severity; | |
31 @synthesize rotationType = _rotationType; | |
32 @synthesize shouldDisableBuffering = _shouldDisableBuffering; | |
33 | |
34 - (instancetype)init { | |
35 NSArray *paths = NSSearchPathForDirectoriesInDomains( | |
36 NSDocumentDirectory, NSUserDomainMask, YES); | |
37 NSString *documentsDirPath = [paths firstObject]; | |
38 NSString *defaultDirPath = | |
39 [documentsDirPath stringByAppendingPathComponent:kDefaultLogDirName]; | |
40 return [self initWithDirPath:defaultDirPath | |
41 maxFileSize:kDefaultMaxFileSize]; | |
42 } | |
43 | |
44 - (instancetype)initWithDirPath:(NSString *)dirPath | |
45 maxFileSize:(NSUInteger)maxFileSize { | |
46 return [self initWithDirPath:dirPath | |
47 maxFileSize:maxFileSize | |
48 rotationType:RTCFileLoggerTypeCall]; | |
49 } | |
50 | |
51 - (instancetype)initWithDirPath:(NSString *)dirPath | |
52 maxFileSize:(NSUInteger)maxFileSize | |
53 rotationType:(RTCFileLoggerRotationType)rotationType { | |
54 NSParameterAssert(dirPath.length); | |
55 NSParameterAssert(maxFileSize); | |
56 if (self = [super init]) { | |
57 BOOL isDir = NO; | |
58 NSFileManager *fileManager = [NSFileManager defaultManager]; | |
59 if ([fileManager fileExistsAtPath:dirPath isDirectory:&isDir]) { | |
60 if (!isDir) { | |
61 // Bail if something already exists there. | |
62 return nil; | |
63 } | |
64 } else { | |
65 if (![fileManager createDirectoryAtPath:dirPath | |
66 withIntermediateDirectories:NO | |
67 attributes:nil | |
68 error:nil]) { | |
69 // Bail if we failed to create a directory. | |
70 return nil; | |
71 } | |
72 } | |
73 _dirPath = dirPath; | |
74 _maxFileSize = maxFileSize; | |
75 _severity = RTCFileLoggerSeverityInfo; | |
76 } | |
77 return self; | |
78 } | |
79 | |
80 - (void)dealloc { | |
81 [self stop]; | |
82 } | |
83 | |
84 - (void)start { | |
85 if (_hasStarted) { | |
86 return; | |
87 } | |
88 switch (_rotationType) { | |
89 case RTCFileLoggerTypeApp: | |
90 _logSink.reset( | |
91 new rtc::FileRotatingLogSink(_dirPath.UTF8String, | |
92 kRTCFileLoggerRotatingLogPrefix, | |
93 _maxFileSize, | |
94 _maxFileSize / 10)); | |
95 break; | |
96 case RTCFileLoggerTypeCall: | |
97 _logSink.reset( | |
98 new rtc::CallSessionFileRotatingLogSink(_dirPath.UTF8String, | |
99 _maxFileSize)); | |
100 break; | |
101 } | |
102 if (!_logSink->Init()) { | |
103 LOG(LS_ERROR) << "Failed to open log files at path: " | |
104 << _dirPath.UTF8String; | |
105 _logSink.reset(); | |
106 return; | |
107 } | |
108 if (_shouldDisableBuffering) { | |
109 _logSink->DisableBuffering(); | |
110 } | |
111 rtc::LogMessage::LogThreads(true); | |
112 rtc::LogMessage::LogTimestamps(true); | |
113 rtc::LogMessage::AddLogToStream(_logSink.get(), [self rtcSeverity]); | |
114 _hasStarted = YES; | |
115 } | |
116 | |
117 - (void)stop { | |
118 if (!_hasStarted) { | |
119 return; | |
120 } | |
121 RTC_DCHECK(_logSink); | |
122 rtc::LogMessage::RemoveLogToStream(_logSink.get()); | |
123 _hasStarted = NO; | |
124 _logSink.reset(); | |
125 } | |
126 | |
127 - (NSData *)logData { | |
128 if (_hasStarted) { | |
129 return nil; | |
130 } | |
131 NSMutableData* logData = [NSMutableData data]; | |
132 rtc::scoped_ptr<rtc::FileRotatingStream> stream; | |
133 switch(_rotationType) { | |
134 case RTCFileLoggerTypeApp: | |
135 stream.reset( | |
136 new rtc::FileRotatingStream(_dirPath.UTF8String, | |
137 kRTCFileLoggerRotatingLogPrefix)); | |
138 break; | |
139 case RTCFileLoggerTypeCall: | |
140 stream.reset(new rtc::CallSessionFileRotatingStream(_dirPath.UTF8String)); | |
141 break; | |
142 } | |
143 if (!stream->Open()) { | |
144 return logData; | |
145 } | |
146 size_t bufferSize = 0; | |
147 if (!stream->GetSize(&bufferSize) || bufferSize == 0) { | |
148 return logData; | |
149 } | |
150 size_t read = 0; | |
151 // Allocate memory using malloc so we can pass it direcly to NSData without | |
152 // copying. | |
153 rtc::scoped_ptr<uint8_t[]> buffer(static_cast<uint8_t*>(malloc(bufferSize))); | |
154 stream->ReadAll(buffer.get(), bufferSize, &read, nullptr); | |
155 logData = [[NSMutableData alloc] initWithBytesNoCopy:buffer.release() | |
156 length:read]; | |
157 return logData; | |
158 } | |
159 | |
160 #pragma mark - Private | |
161 | |
162 - (rtc::LoggingSeverity)rtcSeverity { | |
163 switch (_severity) { | |
164 case RTCFileLoggerSeverityVerbose: | |
165 return rtc::LS_VERBOSE; | |
166 case RTCFileLoggerSeverityInfo: | |
167 return rtc::LS_INFO; | |
168 case RTCFileLoggerSeverityWarning: | |
169 return rtc::LS_WARNING; | |
170 case RTCFileLoggerSeverityError: | |
171 return rtc::LS_ERROR; | |
172 } | |
173 } | |
174 | |
175 @end | |
OLD | NEW |