1
0
mirror of https://github.com/Icinga/icinga2.git synced 2025-04-08 17:05:25 +02:00

Implement generic color support for terminals

fixes 
This commit is contained in:
Gunnar Beutner 2014-10-17 09:45:46 +02:00
parent 92896311f3
commit 8cc6368954
9 changed files with 372 additions and 64 deletions

@ -29,6 +29,7 @@
#include "base/scriptvariable.hpp"
#include "base/context.hpp"
#include "base/clicommand.hpp"
#include "base/console.hpp"
#include "config.h"
#include <boost/program_options.hpp>
#include <boost/tuple/tuple.hpp>
@ -166,6 +167,9 @@ int Main(void)
visibleDesc.add_options()
("help", "show this help message")
("version,V", "show version information")
#ifndef _WIN32
("color", "use VT100 color codes even when stdout is not a terminal")
#endif /* _WIN32 */
("define,D", po::value<std::vector<std::string> >(), "define a constant")
("library,l", po::value<std::vector<std::string> >(), "load a library")
("include,I", po::value<std::vector<std::string> >(), "add include search directory")
@ -201,6 +205,13 @@ int Main(void)
ConfigCompiler::CompileFile(initconfig);
}
#ifndef _WIN32
if (vm.count("color")) {
Console::SetType(std::cout, Console_VT100);
Console::SetType(std::cerr, Console_VT100);
}
#endif /* _WIN32 */
if (vm.count("define")) {
BOOST_FOREACH(const String& define, vm["define"].as<std::vector<std::string> >()) {
String key, value;

@ -23,7 +23,7 @@ mkclass_target(streamlogger.ti streamlogger.thpp)
mkclass_target(sysloglogger.ti sysloglogger.thpp)
set(base_SOURCES
application.cpp application.thpp array.cpp clicommand.cpp configerror.cpp context.cpp
application.cpp application.thpp array.cpp clicommand.cpp configerror.cpp console.cpp context.cpp
convert.cpp debuginfo.cpp dictionary.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp
exception.cpp fifo.cpp filelogger.cpp filelogger.thpp logger.cpp logger.thpp
netstring.cpp networkstream.cpp object.cpp objectlock.cpp process.cpp

221
lib/base/console.cpp Normal file

@ -0,0 +1,221 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "base/console.hpp"
#include "base/initialize.hpp"
using namespace icinga;
INITIALIZE_ONCE(&Console::DetectType);
static ConsoleType l_ConsoleType = Console_Dumb;
ConsoleColorTag::ConsoleColorTag(int color)
: m_Color(color)
{ }
std::ostream& icinga::operator<<(std::ostream& fp, const ConsoleColorTag& cct)
{
fp.flush();
#ifndef _WIN32
if (l_ConsoleType == Console_VT100)
Console::PrintVT100ColorCode(fp, cct.m_Color);
#else /* _WIN32 */
if (l_ConsoleType == Console_Windows) {
fp.flush();
Console::SetWindowsConsoleColor(fp, cct.m_Color);
}
#endif /* _WIN32 */
return fp;
}
void Console::DetectType(void)
{
l_ConsoleType = Console_Dumb;
#ifndef _WIN32
if (isatty(1))
l_ConsoleType = Console_VT100;
#else /* _WIN32 */
l_ConsoleType = Console_Windows;
#endif /* _WIN32 */
}
void Console::SetType(std::ostream& fp, ConsoleType type)
{
if (&fp == &std::cout || &fp == &std::cerr)
l_ConsoleType = type;
}
ConsoleType Console::GetType(std::ostream& fp)
{
if (&fp == &std::cout || &fp == &std::cerr)
return l_ConsoleType;
else
return Console_Dumb;
}
#ifndef _WIN32
void Console::PrintVT100ColorCode(std::ostream& fp, int color)
{
if (color == Console_Normal) {
fp << "\33[0m";
return;
}
switch (color & 0xff) {
case Console_ForegroundBlack:
fp << "\33[30m";
break;
case Console_ForegroundRed:
fp << "\33[31m";
break;
case Console_ForegroundGreen:
fp << "\33[32m";
break;
case Console_ForegroundYellow:
fp << "\33[33m";
break;
case Console_ForegroundBlue:
fp << "\33[34m";
break;
case Console_ForegroundMagenta:
fp << "\33[35m";
break;
case Console_ForegroundCyan:
fp << "\33[36m";
break;
case Console_ForegroundWhite:
fp << "\33[37m";
break;
}
switch (color & 0xff00) {
case Console_BackgroundBlack:
fp << "\33[40m";
break;
case Console_BackgroundRed:
fp << "\33[41m";
break;
case Console_BackgroundGreen:
fp << "\33[42m";
break;
case Console_BackgroundYellow:
fp << "\33[43m";
break;
case Console_BackgroundBlue:
fp << "\33[44m";
break;
case Console_BackgroundMagenta:
fp << "\33[45m";
break;
case Console_BackgroundCyan:
fp << "\33[46m";
break;
case Console_BackgroundWhite:
fp << "\33[47m";
break;
}
if (color & Console_Bold)
fp << "\33[1m";
}
#else /* _WIN32 */
void Console::SetWindowsConsoleColor(std::ostream& fp, int color)
{
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
HANDLE hConsole;
if (&fp == &std::cout)
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
else if (&fp == &std::cerr)
hConsole = GetStdHandle(STD_ERROR_HANDLE);
else
return;
if (!GetConsoleScreenBufferInfo(hConsole, &consoleInfo))
return;
WORD attrs = 0;
if (color == Console_Normal)
attrs = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
switch (color & 0xff) {
case Console_ForegroundBlack:
attrs |= 0;
break;
case Console_ForegroundRed:
attrs |= FOREGROUND_RED;
break;
case Console_ForegroundGreen:
attrs |= FOREGROUND_GREEN;
break;
case Console_ForegroundYellow:
attrs |= FOREGROUND_RED | FOREGROUND_GREEN;
break;
case Console_ForegroundBlue:
attrs |= FOREGROUND_BLUE;
break;
case Console_ForegroundMagenta:
attrs |= FOREGROUND_RED | FOREGROUND_BLUE;
break;
case Console_ForegroundCyan:
attrs |= FOREGROUND_GREEN | FOREGROUND_BLUE;
break;
case Console_ForegroundWhite:
attrs |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
break;
}
switch (color & 0xff00) {
case Console_BackgroundBlack:
attrs |= 0;
break;
case Console_BackgroundRed:
attrs |= BACKGROUND_RED;
break;
case Console_BackgroundGreen:
attrs |= BACKGROUND_GREEN;
break;
case Console_BackgroundYellow:
attrs |= BACKGROUND_RED | BACKGROUND_GREEN;
break;
case Console_BackgroundBlue:
attrs |= BACKGROUND_BLUE;
break;
case Console_BackgroundMagenta:
attrs |= BACKGROUND_RED | BACKGROUND_BLUE;
break;
case Console_BackgroundCyan:
attrs |= BACKGROUND_GREEN | BACKGROUND_BLUE;
break;
case Console_BackgroundWhite:
attrs |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
break;
}
if (color & Console_Bold)
attrs |= FOREGROUND_INTENSITY;
SetConsoleTextAttribute(hConsole, attrs);
}
#endif /* _WIN32 */

103
lib/base/console.hpp Normal file

@ -0,0 +1,103 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef CONSOLE_H
#define CONSOLE_H
#include "base/i2-base.hpp"
#include <ostream>
namespace icinga
{
enum ConsoleColor
{
Console_Normal,
// bit 0-7: foreground
Console_ForegroundBlack = 1,
Console_ForegroundRed = 2,
Console_ForegroundGreen = 3,
Console_ForegroundYellow = 4,
Console_ForegroundBlue = 5,
Console_ForegroundMagenta = 6,
Console_ForegroundCyan = 7,
Console_ForegroundWhite = 8,
// bit 8-15: background
Console_BackgroundBlack = 256,
Console_BackgroundRed = 266,
Console_BackgroundGreen = 267,
Console_BackgroundYellow = 268,
Console_BackgroundBlue = 269,
Console_BackgroundMagenta = 270,
Console_BackgroundCyan = 271,
Console_BackgroundWhite = 272,
// bit 16-23: flags
Console_Bold = 65536
};
enum ConsoleType
{
Console_Dumb,
#ifndef _WIN32
Console_VT100,
#else /* _WIN32 */
Console_Windows,
#endif /* _WIN32 */
};
class I2_BASE_API ConsoleColorTag
{
public:
ConsoleColorTag(int color);
friend I2_BASE_API std::ostream& operator<<(std::ostream& fp, const ConsoleColorTag& cct);
private:
int m_Color;
};
/**
* Console utilities.
*
* @ingroup base
*/
class I2_BASE_API Console
{
public:
static void DetectType(void);
static void SetType(std::ostream& fp, ConsoleType type);
static ConsoleType GetType(std::ostream& fp);
#ifndef _WIN32
static void PrintVT100ColorCode(std::ostream& fp, int color);
#else /* _WIN32 */
static void SetWindowsConsoleColor(std::ostream& fp, int color);
#endif /* _WIN32 */
private:
Console(void);
};
}
#endif /* CONSOLE_H */

@ -106,11 +106,8 @@ void icinga::Log(LogSeverity severity, const String& facility,
logger->ProcessLogEntry(entry);
}
if (Logger::IsConsoleLogEnabled() && entry.Severity >= Logger::GetConsoleLogSeverity()) {
static bool tty = StreamLogger::IsTty(std::cout);
StreamLogger::ProcessLogEntry(std::cout, tty, entry);
}
if (Logger::IsConsoleLogEnabled() && entry.Severity >= Logger::GetConsoleLogSeverity())
StreamLogger::ProcessLogEntry(std::cout, entry);
}
/**

@ -20,6 +20,7 @@
#include "base/streamlogger.hpp"
#include "base/utility.hpp"
#include "base/objectlock.hpp"
#include "base/console.hpp"
#include <iostream>
using namespace icinga;
@ -78,7 +79,6 @@ void StreamLogger::BindStream(std::ostream *stream, bool ownsStream)
m_Stream = stream;
m_OwnsStream = ownsStream;
m_Tty = IsTty(*stream);
m_FlushLogTimer = make_shared<Timer>();
m_FlushLogTimer->SetInterval(1);
@ -90,10 +90,9 @@ void StreamLogger::BindStream(std::ostream *stream, bool ownsStream)
* Processes a log entry and outputs it to a stream.
*
* @param stream The output stream.
* @param tty Whether the output stream is a TTY.
* @param entry The log entry.
*/
void StreamLogger::ProcessLogEntry(std::ostream& stream, bool tty, const LogEntry& entry)
void StreamLogger::ProcessLogEntry(std::ostream& stream, const LogEntry& entry)
{
String timestamp = Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", entry.Timestamp);
@ -101,35 +100,28 @@ void StreamLogger::ProcessLogEntry(std::ostream& stream, bool tty, const LogEntr
stream << "[" << timestamp << "] ";
if (tty) {
switch (entry.Severity) {
case LogNotice:
stream << "\x1b[1;34m"; // blue
break;
case LogInformation:
stream << "\x1b[1;32m"; // green
break;
case LogWarning:
stream << "\x1b[1;33m"; // yellow;
break;
case LogCritical:
stream << "\x1b[1;31m"; // red
break;
default:
break;
}
ConsoleColor color;
switch (entry.Severity) {
case LogNotice:
color = Console_ForegroundBlue;
break;
case LogInformation:
color = Console_ForegroundGreen;
break;
case LogWarning:
color = Console_ForegroundYellow;
break;
case LogCritical:
color = Console_ForegroundRed;
break;
default:
return;
}
try {
stream << Logger::SeverityToString(entry.Severity);
} catch (const std::exception&) {
/* bail early */
return;
}
if (tty)
stream << "\x1b[0m"; // clear colors
stream << ConsoleColorTag(color);
stream << Logger::SeverityToString(entry.Severity);
stream << ConsoleColorTag(Console_Normal);
stream << "/" << entry.Facility << ": " << entry.Message << "\n";
}
@ -140,25 +132,6 @@ void StreamLogger::ProcessLogEntry(std::ostream& stream, bool tty, const LogEntr
*/
void StreamLogger::ProcessLogEntry(const LogEntry& entry)
{
ProcessLogEntry(*m_Stream, m_Tty, entry);
ProcessLogEntry(*m_Stream, entry);
}
/**
* Checks whether the specified stream is a terminal.
*
* @param stream The stream.
* @returns true if the stream is a terminal, false otherwise.
*/
bool StreamLogger::IsTty(std::ostream& stream)
{
#ifndef _WIN32
/* Eww... */
if (&stream == &std::cout)
return isatty(fileno(stdout));
if (&stream == &std::cerr)
return isatty(fileno(stderr));
#endif /*_ WIN32 */
return false;
}

@ -44,8 +44,7 @@ public:
void BindStream(std::ostream *stream, bool ownsStream);
static void ProcessLogEntry(std::ostream& stream, bool tty, const LogEntry& entry);
static bool IsTty(std::ostream& stream);
static void ProcessLogEntry(std::ostream& stream, const LogEntry& entry);
protected:
virtual void ProcessLogEntry(const LogEntry& entry);

@ -29,6 +29,7 @@
#include "base/stdiostream.hpp"
#include "base/debug.hpp"
#include "base/objectlock.hpp"
#include "base/console.hpp"
#include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp>
@ -144,8 +145,8 @@ void ObjectListCommand::PrintObject(std::ostream& fp, bool& first, const String&
else
fp << "Object '";
fp << "\x1b[1;34m" << internal_name << "\x1b[0m" << "'"; //blue
fp << " of type '" << "\x1b[1;34m" << type << "\x1b[0m" << "':\n"; //blue
fp << ConsoleColorTag(Console_ForegroundBlue | Console_Bold) << internal_name << ConsoleColorTag(Console_Normal) << "'";
fp << " of type '" << ConsoleColorTag(Console_ForegroundBlue | Console_Bold) << type << ConsoleColorTag(Console_Normal) << "':\n";
PrintProperties(fp, properties, debug_hints, 2);
@ -166,7 +167,7 @@ void ObjectListCommand::PrintProperties(std::ostream& fp, const Dictionary::Ptr&
Value val = kv.second;
/* key & value */
fp << std::setw(indent) << " " << "* " << "\x1b[1;32m" << key << "\x1b[0m"; //green
fp << std::setw(indent) << " " << "* " << ConsoleColorTag(Console_ForegroundGreen) << key << ConsoleColorTag(Console_Normal);
/* extract debug hints for key */
Dictionary::Ptr debug_hints_fwd;
@ -201,8 +202,8 @@ void ObjectListCommand::PrintHints(std::ostream& fp, const Dictionary::Ptr& debu
void ObjectListCommand::PrintHint(std::ostream& fp, const Array::Ptr& msg, int indent)
{
fp << std::setw(indent) << " " << "\x1b[1;36m" "% " << msg->Get(0) << " modified in '" << msg->Get(1) << "', lines "
<< msg->Get(2) << ":" << msg->Get(3) << "-" << msg->Get(4) << ":" << msg->Get(5) << "\x1b[0m" "\n"; //cyan
fp << std::setw(indent) << " " << ConsoleColorTag(Console_ForegroundCyan) << "% " << msg->Get(0) << " modified in '" << msg->Get(1) << "', lines "
<< msg->Get(2) << ":" << msg->Get(3) << "-" << msg->Get(4) << ":" << msg->Get(5) << ConsoleColorTag(Console_Normal) << "\n";
}
void ObjectListCommand::PrintTypeCounts(std::ostream& fp, const std::map<String, int>& type_count)

@ -302,7 +302,10 @@ void ConfigItem::WriteObjectsFile(const String& filename)
persistentItem->Set("type", item->GetType());
persistentItem->Set("name", item->GetName());
persistentItem->Set("abstract", item->IsAbstract());
persistentItem->Set("properties", item->GetProperties());
{
ObjectLock olock(item);
persistentItem->Set("properties", item->GetProperties());
}
persistentItem->Set("debug_hints", item->GetDebugHints());
String json = JsonSerialize(persistentItem);