You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rm...@apache.org on 2022/12/04 04:16:49 UTC

[logging-log4cxx] branch LOGCXX-566 created (now c138073c)

This is an automated email from the ASF dual-hosted git repository.

rmiddleton pushed a change to branch LOGCXX-566
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git


      at c138073c Converting colors to escape sequences kinda works

This branch includes the following new commits:

     new c138073c Converting colors to escape sequences kinda works

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[logging-log4cxx] 01/01: Converting colors to escape sequences kinda works

Posted by rm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rmiddleton pushed a commit to branch LOGCXX-566
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git

commit c138073c45d773b412559df544b74786ebdc36a0
Author: Robert Middleton <ro...@rm5248.com>
AuthorDate: Sat Dec 3 23:16:36 2022 -0500

    Converting colors to escape sequences kinda works
---
 src/main/cpp/colorstartpatternconverter.cpp        | 190 ++++++++++++++++++++-
 src/main/cpp/patternlayout.cpp                     |  46 ++++-
 .../log4cxx/pattern/colorstartpatternconverter.h   |  13 +-
 src/main/include/log4cxx/pattern/patternparser.h   |   3 +-
 src/main/include/log4cxx/patternlayout.h           |   3 +
 5 files changed, 243 insertions(+), 12 deletions(-)

diff --git a/src/main/cpp/colorstartpatternconverter.cpp b/src/main/cpp/colorstartpatternconverter.cpp
index 02a8d779..c58ad02c 100644
--- a/src/main/cpp/colorstartpatternconverter.cpp
+++ b/src/main/cpp/colorstartpatternconverter.cpp
@@ -20,6 +20,7 @@
 #include <log4cxx/spi/loggingevent.h>
 #include <log4cxx/spi/location/locationinfo.h>
 #include <log4cxx/helpers/stringhelper.h>
+#include <log4cxx/private/patternconverter_priv.h>
 
 using namespace log4cxx;
 using namespace log4cxx::pattern;
@@ -28,9 +29,122 @@ using namespace log4cxx::helpers;
 
 IMPLEMENT_LOG4CXX_OBJECT(ColorStartPatternConverter)
 
+#define priv static_cast<ColorPatternConverterPrivate*>(m_priv.get())
+
+static LogString colorToANSISequence(const LogString& color, bool isForeground, Pool& pool){
+	int numberToConvert = 0;
+
+	if(StringHelper::equalsIgnoreCase(color, LOG4CXX_STR("BLACK"), LOG4CXX_STR("black"))){
+		numberToConvert = 30;
+	}else if(StringHelper::equalsIgnoreCase(color, LOG4CXX_STR("RED"), LOG4CXX_STR("red"))){
+		numberToConvert = 31;
+	}else if(StringHelper::equalsIgnoreCase(color, LOG4CXX_STR("GREEN"), LOG4CXX_STR("green"))){
+		numberToConvert = 32;
+	}else if(StringHelper::equalsIgnoreCase(color, LOG4CXX_STR("YELLOW"), LOG4CXX_STR("yellow"))){
+		numberToConvert = 33;
+	}else if(StringHelper::equalsIgnoreCase(color, LOG4CXX_STR("BLUE"), LOG4CXX_STR("blue"))){
+		numberToConvert = 34;
+	}else if(StringHelper::equalsIgnoreCase(color, LOG4CXX_STR("MAGENTA"), LOG4CXX_STR("magenta"))){
+		numberToConvert = 35;
+	}else if(StringHelper::equalsIgnoreCase(color, LOG4CXX_STR("CYAN"), LOG4CXX_STR("cyan"))){
+		numberToConvert = 36;
+	}else if(StringHelper::equalsIgnoreCase(color, LOG4CXX_STR("WHITE"), LOG4CXX_STR("white"))){
+		numberToConvert = 37;
+	}
+
+	if( numberToConvert == 0 ){
+		return LOG4CXX_STR("");
+	}
+	LogString ret;
+	if( isForeground == false ){
+		numberToConvert += 10;
+	}
+	StringHelper::toString(numberToConvert, pool, ret);
+	return ret;
+}
+
+static LogString graphicsModeToANSISequence(const LogString& graphicsMode, Pool& pool){
+	int numberToConvert = 0;
+
+	if(StringHelper::equalsIgnoreCase(graphicsMode, LOG4CXX_STR("BOLD"), LOG4CXX_STR("bold"))){
+		numberToConvert = 1;
+	}else if(StringHelper::equalsIgnoreCase(graphicsMode, LOG4CXX_STR("DIM"), LOG4CXX_STR("dim"))){
+		numberToConvert = 2;
+	}else if(StringHelper::equalsIgnoreCase(graphicsMode, LOG4CXX_STR("ITALIC"), LOG4CXX_STR("italic"))){
+		numberToConvert = 3;
+	}else if(StringHelper::equalsIgnoreCase(graphicsMode, LOG4CXX_STR("UNDERLINE"), LOG4CXX_STR("underline"))){
+		numberToConvert = 4;
+	}else if(StringHelper::equalsIgnoreCase(graphicsMode, LOG4CXX_STR("BLINKING"), LOG4CXX_STR("blinking"))){
+		numberToConvert = 5;
+	}else if(StringHelper::equalsIgnoreCase(graphicsMode, LOG4CXX_STR("INVERSE"), LOG4CXX_STR("inverse"))){
+		numberToConvert = 7;
+	}else if(StringHelper::equalsIgnoreCase(graphicsMode, LOG4CXX_STR("STRIKETHROUGH"), LOG4CXX_STR("strikethrough"))){
+		numberToConvert = 9;
+	}
+
+	if( numberToConvert == 0 ){
+		return LOG4CXX_STR("");
+	}
+	LogString ret;
+	StringHelper::toString(numberToConvert, pool, ret);
+	return ret;
+}
+
+static LogString convertSingleSequence(const LogString& sequence, Pool& pool){
+	LogString strInParens;
+	bool inParens = false;
+	size_t x = 0;
+
+	for(x = 0; x < sequence.length(); x++){
+		if( sequence[x] == '(' && !inParens ){
+			inParens = true;
+			continue;
+		}else if( sequence[x] == '(' && inParens ){
+			// Unbalanced parens - parse invalid
+			return LOG4CXX_STR("");
+		}
+
+		if( sequence[x] == ')' && inParens ){
+			inParens = false;
+			break;
+		}
+
+		if( inParens ){
+			strInParens.push_back(sequence[x]);
+		}
+	}
+
+	if( x != (sequence.length() - 1) || inParens ){
+		// Unbalanced parens, or more data in the string than we expected - parse invalid
+		return LOG4CXX_STR("");
+	}
+
+	if(StringHelper::startsWith(sequence, "fg(")){
+		// Parse foreground
+		return colorToANSISequence(strInParens, true, pool);
+	}else if(StringHelper::startsWith(sequence, "bg(")){
+		return colorToANSISequence(strInParens, false, pool);
+	}else{
+		return graphicsModeToANSISequence(sequence, pool);
+	}
+}
+
+struct ColorStartPatternConverter::ColorPatternConverterPrivate : public PatternConverterPrivate
+{
+	ColorPatternConverterPrivate( const LogString& name, const LogString& style ) :
+		PatternConverterPrivate( name, style ){}
+
+	LogString m_fatalColor;
+	LogString m_errorColor;
+	LogString m_warnColor;
+	LogString m_infoColor;
+	LogString m_debugColor;
+	LogString m_traceColor;
+};
+
 ColorStartPatternConverter::ColorStartPatternConverter() :
-	LoggingEventPatternConverter(LOG4CXX_STR("Color Start"),
-		LOG4CXX_STR("colorStart"))
+	LoggingEventPatternConverter(std::make_unique<ColorPatternConverterPrivate>(LOG4CXX_STR("Color Start"),
+		LOG4CXX_STR("colorStart")))
 {
 }
 
@@ -52,30 +166,90 @@ void ColorStartPatternConverter::format(
 	switch (lvl->toInt())
 	{
 		case log4cxx::Level::FATAL_INT:
-			toAppendTo.append(LOG4CXX_STR("\x1B[35m")); //magenta
+			toAppendTo.append(priv->m_fatalColor);
 			break;
 
 		case log4cxx::Level::ERROR_INT:
-			toAppendTo.append(LOG4CXX_STR("\x1B[91m")); //red
+			toAppendTo.append(priv->m_errorColor);
 			break;
 
 		case log4cxx::Level::WARN_INT:
-			toAppendTo.append(LOG4CXX_STR("\x1B[33m")); //yellow
+			toAppendTo.append(priv->m_warnColor);
 			break;
 
 		case log4cxx::Level::INFO_INT:
-			toAppendTo.append(LOG4CXX_STR("\x1B[32m")); //green
+			toAppendTo.append(priv->m_infoColor);
 			break;
 
 		case log4cxx::Level::DEBUG_INT:
-			toAppendTo.append(LOG4CXX_STR("\x1B[36m")); //cyan
+			toAppendTo.append(priv->m_debugColor);
 			break;
 
 		case log4cxx::Level::TRACE_INT:
-			toAppendTo.append(LOG4CXX_STR("\x1B[34m")); //blue
+			toAppendTo.append(priv->m_traceColor);
 			break;
 
 		default:
 			break;
 	}
 }
+
+void ColorStartPatternConverter::setFatalColor(const LogString& color){
+	parseColor(color, &(priv->m_fatalColor));
+}
+
+void ColorStartPatternConverter::setErrorColor(const LogString& color){
+	parseColor(color, &(priv->m_errorColor));
+}
+
+void ColorStartPatternConverter::setWarnColor(const LogString& color){
+	parseColor(color, &(priv->m_warnColor));
+}
+
+void ColorStartPatternConverter::setInfoColor(const LogString& color){
+	parseColor(color, &(priv->m_infoColor));
+}
+
+void ColorStartPatternConverter::setDebugColor(const LogString& color){
+	parseColor(color, &(priv->m_debugColor));
+}
+
+void ColorStartPatternConverter::setTraceColor(const LogString& color){
+	parseColor(color, &(priv->m_traceColor));
+}
+
+void ColorStartPatternConverter::parseColor(const LogString& color, LogString* result){
+	LogString lower = StringHelper::toLowerCase(color);
+	Pool pool;
+
+	if( StringHelper::startsWith(lower, "\\x1b") ){
+		// We start with an escape sequence, copy the data over after the escape byte
+		result->clear();
+		result->append("\x1b");
+		for( size_t x = 4; x < color.size(); x++ ){
+			result->push_back(color[x]);
+		}
+	}else{
+		// We do not start with an escape sequence: try to parse color
+		// Escape sequence information:
+		// https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
+		// https://en.wikipedia.org/wiki/ANSI_escape_code
+		result->clear();
+		result->append("\x1b[");
+		LogString tmp;
+		for( size_t x = 0; x < color.size(); x++ ){
+			if(color[x] == '|' ||
+					x == color.size() ){
+				LogString toAppend = convertSingleSequence(tmp, pool);
+				tmp.clear();
+				if(!toAppend.empty()){
+					result->push_back(';');
+					result->append(toAppend);
+				}
+			}else{
+				tmp.push_back(color[x]);
+			}
+		}
+		result->append("m");
+	}
+}
diff --git a/src/main/cpp/patternlayout.cpp b/src/main/cpp/patternlayout.cpp
index 4d119f80..e1b5e244 100644
--- a/src/main/cpp/patternlayout.cpp
+++ b/src/main/cpp/patternlayout.cpp
@@ -74,6 +74,13 @@ struct PatternLayout::PatternLayoutPrivate
 	 * Field widths and alignment corresponding to pattern converters.
 	 */
 	FormattingInfoList patternFields;
+
+	LogString m_fatalColor = LOG4CXX_STR("\x1B[35m"); //magenta
+	LogString m_errorColor = LOG4CXX_STR("\x1B[31m"); //red
+	LogString m_warnColor = LOG4CXX_STR("\x1B[33m"); //yellow
+	LogString m_infoColor = LOG4CXX_STR("\x1B[32m"); //green
+	LogString m_debugColor = LOG4CXX_STR("\x1B[36m"); //cyan;
+	LogString m_traceColor = LOG4CXX_STR("\x1B[34m"); //blue;
 };
 
 IMPLEMENT_LOG4CXX_OBJECT(PatternLayout)
@@ -129,6 +136,30 @@ void PatternLayout::setOption(const LogString& option, const LogString& value)
 			LOG4CXX_STR("conversionpattern")))
 	{
 		m_priv->conversionPattern = OptionConverter::convertSpecialChars(value);
+	}else if(StringHelper::equalsIgnoreCase(option,
+											LOG4CXX_STR("ERRORCOLOR"),
+											LOG4CXX_STR("errorcolor"))){
+		m_priv->m_errorColor = value;
+	}else if(StringHelper::equalsIgnoreCase(option,
+											LOG4CXX_STR("FATALCOLOR"),
+											LOG4CXX_STR("fatalcolor"))){
+		m_priv->m_fatalColor = value;
+	}else if(StringHelper::equalsIgnoreCase(option,
+											LOG4CXX_STR("WARNCOLOR"),
+											LOG4CXX_STR("warncolor"))){
+		m_priv->m_warnColor = value;
+	}else if(StringHelper::equalsIgnoreCase(option,
+											LOG4CXX_STR("INFOCOLOR"),
+											LOG4CXX_STR("infocolor"))){
+		m_priv->m_infoColor = value;
+	}else if(StringHelper::equalsIgnoreCase(option,
+											LOG4CXX_STR("DEBUGCOLOR"),
+											LOG4CXX_STR("debugcolor"))){
+		m_priv->m_debugColor = value;
+	}else if(StringHelper::equalsIgnoreCase(option,
+											LOG4CXX_STR("TRACECOLOR"),
+											LOG4CXX_STR("tracecolor"))){
+		m_priv->m_traceColor = value;
 	}
 }
 
@@ -168,7 +199,7 @@ void PatternLayout::activateOptions(Pool&)
 }
 
 #define RULES_PUT(spec, cls) \
-	specs.insert(PatternMap::value_type(LogString(LOG4CXX_STR(spec)), (PatternConstructor) cls ::newInstance))
+	specs.insert(PatternMap::value_type(LogString(LOG4CXX_STR(spec)), cls ::newInstance))
 
 
 log4cxx::pattern::PatternMap PatternLayout::getFormatSpecifiers()
@@ -180,7 +211,7 @@ log4cxx::pattern::PatternMap PatternLayout::getFormatSpecifiers()
 	RULES_PUT("C", ClassNamePatternConverter);
 	RULES_PUT("class", ClassNamePatternConverter);
 
-	RULES_PUT("Y", ColorStartPatternConverter);
+	specs.insert(PatternMap::value_type(LogString(LOG4CXX_STR("Y")), std::bind(&PatternLayout::createColorStartPatternConverter, this, std::placeholders::_1)));
 	RULES_PUT("y", ColorEndPatternConverter);
 
 	RULES_PUT("d", DatePatternConverter);
@@ -231,7 +262,18 @@ LogString PatternLayout::getConversionPattern() const
 	return m_priv->conversionPattern;
 }
 
+pattern::PatternConverterPtr PatternLayout::createColorStartPatternConverter(const std::vector<LogString>& options){
+	std::shared_ptr<ColorStartPatternConverter> colorPatternConverter = std::make_shared<ColorStartPatternConverter>();
+
+	colorPatternConverter->setErrorColor(m_priv->m_errorColor);
+	colorPatternConverter->setFatalColor(m_priv->m_fatalColor);
+	colorPatternConverter->setWarnColor(m_priv->m_warnColor);
+	colorPatternConverter->setInfoColor(m_priv->m_infoColor);
+	colorPatternConverter->setDebugColor(m_priv->m_debugColor);
+	colorPatternConverter->setTraceColor(m_priv->m_traceColor);
 
+	return colorPatternConverter;
+}
 
 
 
diff --git a/src/main/include/log4cxx/pattern/colorstartpatternconverter.h b/src/main/include/log4cxx/pattern/colorstartpatternconverter.h
index 3ce700ab..c84d0619 100644
--- a/src/main/include/log4cxx/pattern/colorstartpatternconverter.h
+++ b/src/main/include/log4cxx/pattern/colorstartpatternconverter.h
@@ -35,6 +35,8 @@ namespace pattern
 class LOG4CXX_EXPORT ColorStartPatternConverter
 	: public LoggingEventPatternConverter
 {
+	struct ColorPatternConverterPrivate;
+
 	public:
 		DECLARE_LOG4CXX_PATTERN(ColorStartPatternConverter)
 		BEGIN_LOG4CXX_CAST_MAP()
@@ -44,7 +46,6 @@ class LOG4CXX_EXPORT ColorStartPatternConverter
 
 		ColorStartPatternConverter();
 
-
 		/**
 		 * Obtains an instance of pattern converter.
 		 * @param options options, may be null.
@@ -58,6 +59,16 @@ class LOG4CXX_EXPORT ColorStartPatternConverter
 		void format(const spi::LoggingEventPtr& event,
 			LogString& toAppendTo,
 			helpers::Pool& p) const override;
+
+		void setFatalColor(const LogString& color);
+		void setErrorColor(const LogString& color);
+		void setWarnColor(const LogString& color);
+		void setInfoColor(const LogString& color);
+		void setDebugColor(const LogString& color);
+		void setTraceColor(const LogString& color);
+
+	private:
+		void parseColor(const LogString& color, LogString* result);
 };
 
 }
diff --git a/src/main/include/log4cxx/pattern/patternparser.h b/src/main/include/log4cxx/pattern/patternparser.h
index 2c328ae3..66aea74e 100644
--- a/src/main/include/log4cxx/pattern/patternparser.h
+++ b/src/main/include/log4cxx/pattern/patternparser.h
@@ -21,6 +21,7 @@
 
 #include <map>
 #include <vector>
+#include <functional>
 #include <log4cxx/helpers/class.h>
 #include <log4cxx/pattern/patternconverter.h>
 #include <log4cxx/pattern/formattinginfo.h>
@@ -30,7 +31,7 @@ namespace log4cxx
 namespace pattern
 {
 
-typedef PatternConverterPtr (*PatternConstructor)(const std::vector<LogString>& options);
+typedef std::function<PatternConverterPtr(const std::vector<LogString>& options)> PatternConstructor;
 typedef std::map<LogString, PatternConstructor> PatternMap;
 
 
diff --git a/src/main/include/log4cxx/patternlayout.h b/src/main/include/log4cxx/patternlayout.h
index f7b844d8..3e605cb9 100644
--- a/src/main/include/log4cxx/patternlayout.h
+++ b/src/main/include/log4cxx/patternlayout.h
@@ -416,6 +416,9 @@ class LOG4CXX_EXPORT PatternLayout : public Layout
 
 	protected:
 		virtual log4cxx::pattern::PatternMap getFormatSpecifiers();
+
+	private:
+		pattern::PatternConverterPtr createColorStartPatternConverter(const std::vector<LogString>& options);
 };
 
 LOG4CXX_PTR_DEF(PatternLayout);