logging: improve the AsyncFileWriter flush test()
[folly.git] / folly / experimental / logging / xlog.cpp
1 /*
2  * Copyright 2004-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <folly/experimental/logging/xlog.h>
17 #include <folly/Synchronized.h>
18
19 using folly::StringPiece;
20
21 namespace folly {
22
23 namespace {
24 /**
25  * buck copies header files from their original location in the source tree
26  * and places them under buck-out/ with a path like
27  * buck-out/<rule-name-components>/<original-path>
28  *
29  * We want to strip off the buck-out/<rule-name-components> portion,
30  * so that the filename we use is just the original path in the source tree.
31  *
32  * The <rule-name-component> section should always end in a path component that
33  * includes a '#': it's format is <rule-name>#<parameters>, where <parameters>
34  * is a comma separated list that never includes '/'.
35  *
36  * Search for the first path component with a '#', and strip off everything up
37  * to this component.
38  */
39 StringPiece stripBuckOutPrefix(StringPiece filename) {
40   size_t idx = 0;
41   while (true) {
42     auto end = filename.find('/', idx);
43     if (end == StringPiece::npos) {
44       // We were unable to find where the buck-out prefix should end.
45       return filename;
46     }
47
48     auto component = filename.subpiece(idx, end - idx);
49     if (component.find('#') != StringPiece::npos) {
50       return filename.subpiece(end + 1);
51     }
52     idx = end + 1;
53   }
54 }
55 } // unnamed namespace
56
57 std::string getXlogCategoryNameForFile(StringPiece filename) {
58   // Buck mangles the directory layout for header files.  Rather than including
59   // them from their original location, it moves them into deep directories
60   // inside buck-out, and includes them from there.
61   //
62   // If this path looks like a buck header directory, try to strip off the
63   // buck-specific portion.
64   if (filename.startsWith("buck-out/")) {
65     filename = stripBuckOutPrefix(filename);
66   }
67
68   std::string categoryName = filename.str();
69
70   // Translate slashes to dots, to turn the directory layout into
71   // a category hierarchy.
72   size_t lastDot = std::string::npos;
73   for (size_t n = 0; n < categoryName.size(); ++n) {
74     if (categoryName[n] == '/') {
75       categoryName[n] = '.';
76       lastDot = std::string::npos;
77     } else if (categoryName[n] == '.') {
78       lastDot = n;
79     }
80   }
81
82   // Strip off the filename extension, if one was present.
83   if (lastDot != std::string::npos) {
84     categoryName.resize(lastDot);
85   }
86   return categoryName;
87 }
88
89 template <bool IsInHeaderFile>
90 LogLevel XlogLevelInfo<IsInHeaderFile>::loadLevelFull(
91     folly::StringPiece categoryName,
92     bool isOverridden) {
93   auto currentLevel = level_.load(std::memory_order_acquire);
94   if (UNLIKELY(currentLevel == ::folly::LogLevel::UNINITIALIZED)) {
95     return LoggerDB::get()->xlogInit(
96         isOverridden ? categoryName : getXlogCategoryNameForFile(categoryName),
97         &level_,
98         nullptr);
99   }
100   return currentLevel;
101 }
102
103 template <bool IsInHeaderFile>
104 LogCategory* XlogCategoryInfo<IsInHeaderFile>::init(
105     folly::StringPiece categoryName,
106     bool isOverridden) {
107   return LoggerDB::get()->xlogInitCategory(
108       isOverridden ? categoryName : getXlogCategoryNameForFile(categoryName),
109       &category_,
110       &isInitialized_);
111 }
112
113 #ifdef __INCLUDE_LEVEL__
114 LogLevel XlogLevelInfo<false>::loadLevelFull(
115     folly::StringPiece categoryName,
116     bool isOverridden,
117     XlogFileScopeInfo* fileScopeInfo) {
118   auto currentLevel = fileScopeInfo->level.load(std::memory_order_acquire);
119   if (UNLIKELY(currentLevel == ::folly::LogLevel::UNINITIALIZED)) {
120     return LoggerDB::get()->xlogInit(
121         isOverridden ? categoryName : getXlogCategoryNameForFile(categoryName),
122         &fileScopeInfo->level,
123         &fileScopeInfo->category);
124   }
125   return currentLevel;
126 }
127 #endif
128
129 // Explicitly instantiations of XlogLevelInfo and XlogCategoryInfo
130 // If __INCLUDE_LEVEL__ is not available only the "true" variants ever get
131 // used, because we cannot determine if we are ever in the .cpp file being
132 // compiled or not.
133 template class XlogLevelInfo<true>;
134 template class XlogCategoryInfo<true>;
135 }