2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/runtime/server/access-log.h"
28 #include "hphp/runtime/base/datetime.h"
29 #include "hphp/runtime/base/timestamp.h"
30 #include "hphp/runtime/base/runtime-option.h"
31 #include "hphp/runtime/server/log-writer.h"
32 #include "hphp/runtime/server/server-note.h"
33 #include "hphp/runtime/server/server-stats.h"
34 #include "hphp/runtime/server/request-uri.h"
35 #include "hphp/util/process.h"
36 #include "hphp/util/atomic.h"
37 #include "hphp/util/compatibility.h"
38 #include "hphp/util/hardware-counter.h"
39 #include "hphp/util/timer.h"
42 ///////////////////////////////////////////////////////////////////////////////
43 Mutex
AccessLogFileData::m_lock
;
44 std::unordered_map
<std::string
, AccessLogFileData::factory_t
>
45 AccessLogFileData::m_factories
;
47 AccessLogFileData::AccessLogFileData(const std::string
& fil
,
48 const std::string
& lnk
,
49 const std::string
& fmt
,
54 , periodMultiplier(mpl
)
57 * a LogWriter with it's format can be selected between colons like:
58 * Format = :thrift: [["%{%s}t", "out-name", "STRING"], ...]
60 m_logOutputType
= ClassicWriter::handle
;
61 auto fmt_
= folly::StringPiece(fmt
);
62 while (!fmt_
.empty() && std::isspace(fmt_
.front())) fmt_
.pop_front();
63 if (fmt_
.removePrefix(':')) {
64 size_t close
= fmt_
.find(':');
65 if (close
!= fmt_
.npos
) {
66 m_logOutputType
= fmt_
.subpiece(0, close
).str();
67 fmt_
.advance(close
+ 1);
68 format
= folly::trimWhitespace(fmt_
).str();
73 std::unique_ptr
<LogWriter
> AccessLogFileData::Writer(LogChannel chan
) const {
75 auto ifactory
= m_factories
.find(m_logOutputType
);
76 if (ifactory
!= m_factories
.end()) {
77 return ifactory
->second(*this, chan
);
79 throw std::runtime_error(
80 ("LogWriter not registered: " + m_logOutputType
).c_str());
83 void AccessLogFileData::registerWriter(const std::string
& handle
,
86 m_factories
[handle
] = factory
;
89 AccessLog::~AccessLog() {
90 signal(SIGCHLD
, SIG_DFL
);
93 void AccessLog::init(const std::string
&defaultFormat
,
94 std::vector
<AccessLogFileData
> &files
,
95 const std::string
&username
) {
97 if (m_initialized
) return;
100 AccessLogFileData("", "", defaultFormat
, 0).Writer(LogChannel::THREADLOCAL
);
101 m_defaultWriter
->init(username
, m_fGetThreadData
);
102 for (auto const& file
: files
) {
103 auto ch
= Logger::UseCronolog
? LogChannel::CRONOLOG
: LogChannel::REGULAR
;
104 auto writer
= std::shared_ptr
<LogWriter
>(file
.Writer(ch
));
105 writer
->init(username
, m_fGetThreadData
);
106 m_files
.push_back(writer
);
110 void AccessLog::init(const std::string
&defaultFormat
,
111 std::map
<std::string
, AccessLogFileData
> &files
,
112 const std::string
&username
) {
114 if (m_initialized
) return;
115 m_initialized
= true;
117 AccessLogFileData("", "", defaultFormat
, 0).Writer(LogChannel::THREADLOCAL
);
118 m_defaultWriter
->init(username
, m_fGetThreadData
);
119 for (auto const& file
: files
) {
120 auto ch
= Logger::UseCronolog
? LogChannel::CRONOLOG
: LogChannel::REGULAR
;
121 auto writer
= std::shared_ptr
<LogWriter
>(file
.second
.Writer(ch
));
122 writer
->init(username
, m_fGetThreadData
);
123 m_files
.push_back(writer
);
127 void AccessLog::init(const std::string
&format
,
128 const std::string
&symLink
,
129 const std::string
&file
,
130 const std::string
&username
) {
132 if (m_initialized
) return;
133 m_initialized
= true;
135 AccessLogFileData("", "", format
, 0).Writer(LogChannel::THREADLOCAL
);
136 m_defaultWriter
->init(username
, m_fGetThreadData
);
137 if (!file
.empty() && !format
.empty()) {
138 auto ch
= Logger::UseCronolog
? LogChannel::CRONOLOG
: LogChannel::REGULAR
;
139 auto writer
= std::shared_ptr
<LogWriter
>(
140 AccessLogFileData(file
, symLink
, format
, 0).Writer(ch
));
141 writer
->init(username
, m_fGetThreadData
);
142 m_files
.push_back(writer
);
146 void AccessLog::log(Transport
*transport
, const VirtualHost
*vhost
) {
148 if (!m_initialized
) return;
149 m_defaultWriter
->write(transport
, vhost
);
150 for (auto& file
: m_files
) file
->write(transport
, vhost
);
153 void AccessLog::onNewRequest() {
154 if (!m_initialized
) return;
155 ThreadData
*threadData
= m_fGetThreadData();
156 threadData
->startTime
= TimeStamp::Current();
159 void AccessLog::flushAllWriters() {
160 if (!m_initialized
) return;
161 m_defaultWriter
->flush();
162 for (auto& file
: m_files
) file
->flush();
165 bool AccessLog::setThreadLog(const char *file
) {
166 return (m_fGetThreadData()->log
= fopen(file
, "a")) != nullptr;
168 void AccessLog::clearThreadLog() {
169 FILE* &threadLog
= m_fGetThreadData()->log
;
176 FILE* LogWriter::getOutputFile() const {
177 FILE* outfile
= nullptr;
179 case LogChannel::THREADLOCAL
:
181 auto tData
= (m_threadDataFn
? m_threadDataFn() : nullptr);
182 outfile
= (tData
? tData
->log
: nullptr);
185 case LogChannel::CRONOLOG
:
186 outfile
= (m_cronolog
.get() ? m_cronolog
->getOutputFile() : nullptr);
188 case LogChannel::REGULAR
:
195 void LogWriter::recordWriteAndMaybeDropCaches(FILE* out
, int bytes
) {
197 case LogChannel::THREADLOCAL
:
199 auto tData
= (m_threadDataFn
? m_threadDataFn() : nullptr);
200 if (tData
) tData
->flusher
.recordWriteAndMaybeDropCaches(out
, bytes
);
203 case LogChannel::CRONOLOG
:
204 case LogChannel::REGULAR
:
205 m_flusher
.recordWriteAndMaybeDropCaches(out
, bytes
);
210 ///////////////////////////////////////////////////////////////////////////////