Skip to content

Commit 6bf1376

Browse files
helfmanmeta-codesync[bot]
authored andcommitted
Disable colored output if not running in a terminal (facebookincubator#289)
Summary: Pull Request resolved: facebookincubator#289 Colored output is great for the terminal, but it is annoying when the output is piped into a file. With this change, the tool detects if it is running in a (color supporting) terminal, and only then emits colors. Reviewed By: sdruzkin Differential Revision: D85069881 fbshipit-source-id: 6d0969cfe3579fd06fcbbb652acd73314205351d
1 parent 41adea2 commit 6bf1376

File tree

3 files changed

+108
-56
lines changed

3 files changed

+108
-56
lines changed

dwio/nimble/tools/NimbleDump.cpp

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,34 @@
3030
using namespace facebook;
3131
namespace po = ::boost::program_options;
3232

33+
namespace {
3334
template <typename T>
3435
std::optional<T> getOptional(const po::variable_value& val) {
3536
return val.empty() ? std::nullopt : std::optional<T>(val.as<T>());
3637
}
3738

39+
bool isColorfulTty() {
40+
auto isTty = isatty(fileno(stdout));
41+
if (!isTty) {
42+
return false;
43+
}
44+
45+
auto term = std::getenv("TERM");
46+
return !(term == nullptr || term[0] == '\0' || strcmp(term, "dumb") == 0);
47+
}
48+
49+
} // namespace
50+
3851
FOLLY_INIT_LOGGING_CONFIG("CRITICAL");
3952
int main(int argc, char* argv[]) {
4053
facebook::config::Flags::overrideDefault("minloglevel", "5");
4154

4255
auto init = init::InitFacebookLight{
4356
&argc, &argv, folly::InitOptions().useGFlags(false)};
4457

58+
// Enable colored output if we are running in a terminal
59+
bool enableColors = isColorfulTty();
60+
4561
std::string version{BuildInfo::getBuildTimeISO8601()};
4662
if (!version.empty()) {
4763
auto buildRevision = BuildInfo::getBuildRevision();
@@ -66,10 +82,11 @@ int main(int argc, char* argv[]) {
6682
"<file>",
6783
"Print file information",
6884
"Prints file information from the file footer.",
69-
[](const po::variables_map& options,
70-
const std::vector<std::string>& /*args*/) {
85+
[enableColors](
86+
const po::variables_map& options,
87+
const std::vector<std::string>& /*args*/) {
7188
nimble::tools::NimbleDumpLib{
72-
std::cout, options["file"].as<std::string>()}
89+
std::cout, enableColors, options["file"].as<std::string>()}
7390
.emitInfo();
7491
},
7592
makePositionalArgs())
@@ -83,10 +100,11 @@ int main(int argc, char* argv[]) {
83100
"<file>",
84101
"Print overall layout of the file",
85102
"Print overall layout of the file",
86-
[](const po::variables_map& options,
87-
const std::vector<std::string>& /*args*/) {
103+
[enableColors](
104+
const po::variables_map& options,
105+
const std::vector<std::string>& /*args*/) {
88106
nimble::tools::NimbleDumpLib{
89-
std::cout, options["file"].as<std::string>()}
107+
std::cout, enableColors, options["file"].as<std::string>()}
90108
.emitFileLayout(options["no_header"].as<bool>());
91109
},
92110
makePositionalArgs())
@@ -108,10 +126,11 @@ int main(int argc, char* argv[]) {
108126
"<file>",
109127
"Print file schema",
110128
"Prints the file schema tree.",
111-
[](const po::variables_map& options,
112-
const std::vector<std::string>& /*args*/) {
129+
[enableColors](
130+
const po::variables_map& options,
131+
const std::vector<std::string>& /*args*/) {
113132
nimble::tools::NimbleDumpLib{
114-
std::cout, options["file"].as<std::string>()}
133+
std::cout, enableColors, options["file"].as<std::string>()}
115134
.emitSchema(!options["full"].as<bool>());
116135
},
117136
makePositionalArgs())
@@ -133,10 +152,11 @@ int main(int argc, char* argv[]) {
133152
"<file>",
134153
"Print stripe information",
135154
"Prints detailed stripe information.",
136-
[](const po::variables_map& options,
137-
const std::vector<std::string>& /*args*/) {
155+
[enableColors](
156+
const po::variables_map& options,
157+
const std::vector<std::string>& /*args*/) {
138158
nimble::tools::NimbleDumpLib{
139-
std::cout, options["file"].as<std::string>()}
159+
std::cout, enableColors, options["file"].as<std::string>()}
140160
.emitStripes(options["no_header"].as<bool>());
141161
},
142162
makePositionalArgs())
@@ -158,10 +178,11 @@ int main(int argc, char* argv[]) {
158178
"<file>",
159179
"Print stream information",
160180
"Prints detailed stream information.",
161-
[](const po::variables_map& options,
162-
const std::vector<std::string>& /*args*/) {
181+
[enableColors](
182+
const po::variables_map& options,
183+
const std::vector<std::string>& /*args*/) {
163184
nimble::tools::NimbleDumpLib{
164-
std::cout, options["file"].as<std::string>()}
185+
std::cout, enableColors, options["file"].as<std::string>()}
165186
.emitStreams(
166187
options["no_header"].as<bool>(),
167188
options["labels"].as<bool>(),
@@ -207,10 +228,11 @@ int main(int argc, char* argv[]) {
207228
"Print encoding histogram",
208229
"Prints encoding histogram, counting how many times each encoding "
209230
"appears in the file.",
210-
[](const po::variables_map& options,
211-
const std::vector<std::string>& /*args*/) {
231+
[enableColors](
232+
const po::variables_map& options,
233+
const std::vector<std::string>& /*args*/) {
212234
nimble::tools::NimbleDumpLib{
213-
std::cout, options["file"].as<std::string>()}
235+
std::cout, enableColors, options["file"].as<std::string>()}
214236
.emitHistogram(
215237
options["root_only"].as<bool>(),
216238
options["no_header"].as<bool>(),
@@ -245,10 +267,11 @@ int main(int argc, char* argv[]) {
245267
"<file>",
246268
"Print the content of a stream",
247269
"Prints the materialized content (actual values) of a stream.",
248-
[](const po::variables_map& options,
249-
const std::vector<std::string>& /*args*/) {
270+
[enableColors](
271+
const po::variables_map& options,
272+
const std::vector<std::string>& /*args*/) {
250273
nimble::tools::NimbleDumpLib{
251-
std::cout, options["file"].as<std::string>()}
274+
std::cout, enableColors, options["file"].as<std::string>()}
252275
.emitContent(
253276
options["stream"].as<uint32_t>(),
254277
getOptional<uint32_t>(options["stripe"]),
@@ -282,10 +305,11 @@ int main(int argc, char* argv[]) {
282305
"<file>",
283306
"Dumps stream binary content",
284307
"Dumps stream binary content to a file.",
285-
[](const po::variables_map& options,
286-
const std::vector<std::string>& /*args*/) {
308+
[enableColors](
309+
const po::variables_map& options,
310+
const std::vector<std::string>& /*args*/) {
287311
nimble::tools::NimbleDumpLib{
288-
std::cout, options["file"].as<std::string>()}
312+
std::cout, enableColors, options["file"].as<std::string>()}
289313
.emitBinary(
290314
[path = options["output"].as<std::string>()]() {
291315
return std::make_unique<std::ofstream>(
@@ -322,10 +346,11 @@ int main(int argc, char* argv[]) {
322346
"<file>",
323347
"Dumps layout file",
324348
"Dumps captured layout file content.",
325-
[](const po::variables_map& options,
326-
const std::vector<std::string>& /*args*/) {
349+
[enableColors](
350+
const po::variables_map& options,
351+
const std::vector<std::string>& /*args*/) {
327352
nimble::tools::NimbleDumpLib{
328-
std::cout, options["file"].as<std::string>()}
353+
std::cout, enableColors, options["file"].as<std::string>()}
329354
.emitLayout(
330355
options["no_header"].as<bool>(),
331356
!options["uncompressed"].as<bool>());
@@ -354,10 +379,11 @@ int main(int argc, char* argv[]) {
354379
"<file>",
355380
"Print stripes metadata information",
356381
"Prints stripes metadata information as referenced by the footer.",
357-
[](const po::variables_map& options,
358-
const std::vector<std::string>& /*args*/) {
382+
[enableColors](
383+
const po::variables_map& options,
384+
const std::vector<std::string>& /*args*/) {
359385
nimble::tools::NimbleDumpLib{
360-
std::cout, options["file"].as<std::string>()}
386+
std::cout, enableColors, options["file"].as<std::string>()}
361387
.emitStripesMetadata(options["no_header"].as<bool>());
362388
},
363389
makePositionalArgs())
@@ -379,10 +405,11 @@ int main(int argc, char* argv[]) {
379405
"<file>",
380406
"Print stripe groups metadata information",
381407
"Prints stripe groups information as referenced by the footer.",
382-
[](const po::variables_map& options,
383-
const std::vector<std::string>& /*args*/) {
408+
[enableColors](
409+
const po::variables_map& options,
410+
const std::vector<std::string>& /*args*/) {
384411
nimble::tools::NimbleDumpLib{
385-
std::cout, options["file"].as<std::string>()}
412+
std::cout, enableColors, options["file"].as<std::string>()}
386413
.emitStripeGroupsMetadata(options["no_header"].as<bool>());
387414
},
388415
makePositionalArgs())
@@ -403,10 +430,11 @@ int main(int argc, char* argv[]) {
403430
"<file>",
404431
"Print optional sections information",
405432
"Prints optional sections information as referenced by the footer.",
406-
[](const po::variables_map& options,
407-
const std::vector<std::string>& /*args*/) {
433+
[enableColors](
434+
const po::variables_map& options,
435+
const std::vector<std::string>& /*args*/) {
408436
nimble::tools::NimbleDumpLib{
409-
std::cout, options["file"].as<std::string>()}
437+
std::cout, enableColors, options["file"].as<std::string>()}
410438
.emitOptionalSectionsMetadata(options["no_header"].as<bool>());
411439
},
412440
makePositionalArgs())

dwio/nimble/tools/NimbleDumpLib.cpp

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,20 @@
3838
#include "folly/cli/NestedCommandLineApp.h"
3939

4040
namespace facebook::nimble::tools {
41-
#define RED "\033[31m"
42-
#define GREEN "\033[32m"
43-
#define YELLOW "\033[33m"
44-
#define BLUE "\033[34m"
45-
#define PURPLE "\033[35m"
46-
#define CYAN "\033[36m"
47-
#define RESET_COLOR "\033[0m"
41+
#undef RED
42+
#define RED(enableColor) (enableColor ? "\033[31m" : "")
43+
#undef GREEN
44+
#define GREEN(enableColor) (enableColor ? "\033[32m" : "")
45+
#undef YELLOW
46+
#define YELLOW(enableColor) (enableColor ? "\033[33m" : "")
47+
#undef BLUE
48+
#define BLUE(enableColor) (enableColor ? "\033[34m" : "")
49+
#undef PURPLE
50+
#define PURPLE(enableColor) (enableColor ? "\033[35m" : "")
51+
#undef CYAN
52+
#define CYAN(enableColor) (enableColor ? "\033[36m" : "")
53+
#undef RESET_COLOR
54+
#define RESET_COLOR(enableColor) (enableColor ? "\033[0m" : "")
4855

4956
namespace {
5057

@@ -105,6 +112,7 @@ class TableFormatter {
105112
public:
106113
TableFormatter(
107114
std::ostream& ostream,
115+
bool enableColor,
108116
std::vector<std::tuple<
109117
std::string /* Title */,
110118
uint8_t /* Width */,
@@ -114,14 +122,14 @@ class TableFormatter {
114122
const std::string& separator = "\t")
115123
: ostream_{ostream}, fields_{std::move(fields)}, separator_{separator} {
116124
if (!noHeader) {
117-
ostream << YELLOW;
125+
ostream << YELLOW(enableColor);
118126
for (const auto& field : fields_) {
119127
ostream << (std::get<2>(field) == Alignment::Right ? std::right
120128
: std::left)
121129
<< std::setw(std::get<1>(field)) << std::get<0>(field)
122130
<< ((&field != &fields_.back()) ? separator_ : "");
123131
}
124-
ostream << RESET_COLOR << std::endl;
132+
ostream << RESET_COLOR(enableColor) << std::endl;
125133
}
126134
}
127135

@@ -151,11 +159,11 @@ void traverseTablet(
151159
velox::memory::MemoryPool& memoryPool,
152160
const TabletReader& tabletReader,
153161
std::optional<int32_t> stripeIndex,
154-
std::function<void(uint32_t /* stripeId */)> stripeVisitor = nullptr,
155-
std::function<void(
162+
const std::function<void(uint32_t /* stripeId */)>& stripeVisitor = nullptr,
163+
const std::function<void(
156164
ChunkedStream& /*stream*/,
157165
uint32_t /*stripeId*/,
158-
uint32_t /* streamId*/)> streamVisitor = nullptr) {
166+
uint32_t /* streamId*/)>& streamVisitor = nullptr) {
159167
uint32_t startStripe = stripeIndex ? *stripeIndex : 0;
160168
uint32_t endStripe =
161169
stripeIndex ? *stripeIndex : tabletReader.stripeCount() - 1;
@@ -262,23 +270,27 @@ auto commaSeparated(T value) {
262270

263271
} // namespace
264272

265-
NimbleDumpLib::NimbleDumpLib(std::ostream& ostream, const std::string& file)
273+
NimbleDumpLib::NimbleDumpLib(
274+
std::ostream& ostream,
275+
bool enableColors,
276+
const std::string& file)
266277
: pool_{velox::memory::deprecatedAddDefaultLeafMemoryPool()},
267278
file_{dwio::file_system::FileSystem::openForRead(
268279
file,
269280
dwio::common::request::AccessDescriptorBuilder()
270281
.withClientId("nimble_dump")
271282
.build())},
272-
ostream_{ostream} {}
283+
ostream_{ostream},
284+
enableColors_{enableColors} {}
273285

274286
void NimbleDumpLib::emitInfo() {
275287
std::vector<std::string> preloadedOptionalSections = {
276288
std::string(kStatsSection)};
277289
auto tablet = std::make_shared<TabletReader>(
278290
*pool_, file_.get(), preloadedOptionalSections);
279-
ostream_ << CYAN << "Nimble File " << RESET_COLOR << "Version "
280-
<< tablet->majorVersion() << "." << tablet->minorVersion()
281-
<< std::endl;
291+
ostream_ << CYAN(enableColors_) << "Nimble File "
292+
<< RESET_COLOR(enableColors_) << "Version " << tablet->majorVersion()
293+
<< "." << tablet->minorVersion() << std::endl;
282294
ostream_ << "File Size: " << commaSeparated(tablet->fileSize()) << std::endl;
283295
ostream_ << "Checksum: " << tablet->checksum() << " ["
284296
<< nimble::toString(tablet->checksumType()) << "]" << std::endl;
@@ -449,6 +461,7 @@ void NimbleDumpLib::emitStripes(bool noHeader) {
449461
TabletReader tabletReader{*pool_, file_.get()};
450462
TableFormatter formatter(
451463
ostream_,
464+
enableColors_,
452465
{{"Stripe Id", 7, Alignment::Left},
453466
{"Stripe Offset", 15, Alignment::Right},
454467
{"Stripe Size", 15, Alignment::Right},
@@ -492,7 +505,8 @@ void NimbleDumpLib::emitStreams(
492505
}
493506
fields.emplace_back("Type", 30, Alignment::Left);
494507

495-
TableFormatter formatter(ostream_, std::move(fields), noHeader);
508+
TableFormatter formatter(
509+
ostream_, enableColors_, std::move(fields), noHeader);
496510

497511
std::optional<StreamLabels> labels{};
498512
std::unordered_set<uint32_t> inMapStreams;
@@ -613,6 +627,7 @@ void NimbleDumpLib::emitHistogram(
613627

614628
TableFormatter formatter(
615629
ostream_,
630+
enableColors_,
616631
{{"Encoding Type", 17, Alignment::Left},
617632
{"Data Type", 13, Alignment::Left},
618633
{"Compression", 15, Alignment::Left},
@@ -851,6 +866,7 @@ void NimbleDumpLib::emitLayout(bool noHeader, bool compressed) {
851866

852867
TableFormatter formatter(
853868
ostream_,
869+
enableColors_,
854870
{
855871
{"Node Id", 11, Alignment::Left},
856872
{"Parent Id", 11, Alignment::Left},
@@ -891,14 +907,15 @@ void NimbleDumpLib::emitLayout(bool noHeader, bool compressed) {
891907
folly::to<std::string>(parentId),
892908
toString(node.schemaKind()),
893909
std::string(node.name()),
894-
encodingLayout});
910+
std::move(encodingLayout)});
895911
});
896912
}
897913

898914
void NimbleDumpLib::emitStripesMetadata(bool noHeader) {
899915
TabletReader tabletReader{*pool_, file_.get()};
900916
TableFormatter formatter(
901917
ostream_,
918+
enableColors_,
902919
{
903920
{"Offset", 15, Alignment::Left},
904921
{"Size", 15, Alignment::Left},
@@ -988,6 +1005,7 @@ void NimbleDumpLib::emitFileLayout(bool noHeader) {
9881005

9891006
TableFormatter formatter(
9901007
ostream_,
1008+
enableColors_,
9911009
{
9921010
{"Offset", 15, Alignment::Right},
9931011
{"Size", 15, Alignment::Right},
@@ -1010,6 +1028,7 @@ void NimbleDumpLib::emitStripeGroupsMetadata(bool noHeader) {
10101028
TabletReader tabletReader{*pool_, file_.get()};
10111029
TableFormatter formatter(
10121030
ostream_,
1031+
enableColors_,
10131032
{
10141033
{"Group Id", 10, Alignment::Left},
10151034
{"Offset", 15, Alignment::Left},
@@ -1050,6 +1069,7 @@ void NimbleDumpLib::emitOptionalSectionsMetadata(bool noHeader) {
10501069

10511070
TableFormatter formatter(
10521071
ostream_,
1072+
enableColors_,
10531073
{{"Name", 20, Alignment::Left},
10541074
{"Compression", 12, Alignment::Left},
10551075
{"Offset", 15, Alignment::Right},

0 commit comments

Comments
 (0)