1313 */
1414package com .agiletec .aps .system ;
1515
16+ import jakarta .servlet .http .HttpServletRequest ;
1617import org .entando .entando .ent .util .EntLogging .EntLogger ;
1718import org .entando .entando .ent .util .EntLogging .EntLogFactory ;
1819import org .slf4j .Marker ;
1920import org .slf4j .MarkerFactory ;
2021
22+ import java .util .Enumeration ;
23+
2124/**
2225 * Utility class for system logger
2326 *
@@ -29,6 +32,12 @@ public class ApsSystemUtils {
2932 private static final Marker startupMarker = MarkerFactory .getMarker ("STARTUP" );
3033 private static final boolean ENABLE_DIRECT_STDOUT_TRACE =
3134 ("" + System .getProperty ("org.entando.enableDirectStdoutTrace" )).equals ("true" );
35+
36+ /**
37+ * Comma-separated list of feature flags tags that are enabled.
38+ * See {@link ApsSystemUtils#isTagEnabled} for details about the rules.
39+ */
40+ public static final String ENTANDO_FEATURE_FLAGS = System .getenv ("ENTANDO_FEATURE_FLAGS" );
3241
3342 private ApsSystemUtils () {
3443 throw new IllegalStateException ("Utility class" );
@@ -79,4 +88,170 @@ public static boolean directStdoutTrace(String str, boolean force) {
7988 }
8089 }
8190
91+ /**
92+ * ApsDeepDebug is a utility class for managing and printing deep debug messages.
93+ * This class provides methods to log messages conditionally based on specified tags,
94+ * leveraging the environment variable "ENTANDO_FF_DEEP_DEBUG" to control the output.
95+ */
96+ public static class ApsDeepDebug {
97+ public static final String FORCE_TAG_PREFIX = "::" ;
98+ private static final String SEP_LW = "▔▔▔▔▔▔▔▔▔▔" ;
99+ private static final String SEP_UP = "▁▁▁▁▁▁▁▁▁▁" ;
100+ private static final String SEP_FL = "▒" ;
101+ public static final String ENTANDO_FF_DEEP_DEBUG = System .getenv ("ENTANDO_FF_DEEP_DEBUG" );
102+
103+ /**
104+ * Prints - if allowed by the implicit tag "print" - a single deep debug message
105+ */
106+ public static boolean print (String message ) {
107+ return print (null , "" , message );
108+ }
109+
110+ /**
111+ * Prints - if allowed by the given tag - a single deep debug message
112+ */
113+ public static boolean print (String tag , String message ) {
114+ return print (tag , "" , message );
115+ }
116+
117+ /**
118+ * Prints - if allowed by the given tag - multiple deep messages
119+ */
120+ public static boolean print (String tag , String prefix , String ... messages ) {
121+ return print (tag , prefix , false , messages );
122+ }
123+
124+ /**
125+ * Prints - if allowed by the given tag - multiple deep messages
126+ */
127+ public synchronized static boolean print (String tag , String prefix , boolean suppressTitle , String ... messages ) {
128+ if (isTagEnabled (tag )) {
129+ if (prefix == null ) prefix = "├ " ;
130+ if (tag == null ) suppressTitle = true ;
131+
132+ try {
133+ StringBuilder sb = new StringBuilder ();
134+ if (!suppressTitle ) addHeader (tag , sb );
135+ for (String str : messages ) {
136+ if (!suppressTitle ) {
137+ sb .append (prefix ).append (" " );
138+ }
139+ sb .append (str ).append ("\n " );
140+ }
141+ if (!suppressTitle ) {
142+ addFooter (sb );
143+ }
144+ System .out .println (sb );
145+ } catch (Throwable t ) {
146+ logger .warn (String .format ("Error printing the deep debug message" ), t );
147+ }
148+ return true ;
149+ } else {
150+ return false ;
151+ }
152+ }
153+
154+ public static void printHttpRequest (String tag , HttpServletRequest request ) {
155+ if (isTagEnabled (tag )) {
156+ Enumeration <String > headerNames = request .getHeaderNames ();
157+ StringBuilder sb = new StringBuilder ();
158+ addHeader (tag , sb ).append ("~ " ).append (request .getRequestURL ()).append ("\n " );
159+ while (headerNames .hasMoreElements ()) {
160+ String headerName = headerNames .nextElement ();
161+ Enumeration <String > headerValues = request .getHeaders (headerName );
162+ while (headerValues .hasMoreElements ()) {
163+ String headerValue = headerValues .nextElement ();
164+ sb .append ("~ " ).append (headerName ).append (": " ).append (headerValue ).append ("\n " );
165+ }
166+ }
167+ addFooter (sb );
168+ print (sb .toString ());
169+ }
170+ }
171+
172+ private static void addFooter (StringBuilder s ) {
173+ s .append (SEP_LW + SEP_LW + SEP_LW + SEP_LW + SEP_LW + SEP_LW + SEP_LW + SEP_LW + SEP_LW + SEP_LW );
174+ }
175+
176+ private static StringBuilder addHeader (String title , StringBuilder s ) {
177+ return s .append ("\n " + SEP_UP + SEP_UP + SEP_UP + SEP_UP + SEP_UP + SEP_UP + SEP_UP + SEP_UP + SEP_UP + SEP_UP + "\n " )
178+ .append (title ).append ("\n " );
179+ }
180+
181+ /**
182+ * Checks if a tag is enabled according to ENTANDO_FF_DEEP_DEBUG
183+ * Check also {@link ApsSystemUtils#isTagEnabled}
184+ */
185+ public static boolean isTagEnabled (String tag ) {
186+ return ApsSystemUtils .isTagEnabled (getDeepDebugFF (), tag );
187+ }
188+
189+ /**
190+ * Prints a feature flare, which is a signal that a feature was enabled
191+ */
192+ public static void printFeatureFlare (String tag , String flareName , boolean alwaysPrint ) {
193+ String sep = SEP_FL .repeat (tag .length () + 4 + 4 );
194+ print (
195+ ((alwaysPrint ) ? FORCE_TAG_PREFIX : "" ) + "FLARE" + ((flareName != null ) ? ":" + tag : "" ),
196+ null ,
197+ true ,
198+ "" , sep , SEP_FL + SEP_FL + SEP_FL + " " + tag + " " + SEP_FL + SEP_FL + SEP_FL , sep , ""
199+ );
200+ }
201+
202+ public static void printFeatureFlare (String flareName ) {
203+ printFeatureFlare (null , flareName , false );
204+ }
205+ }
206+
207+ public static String getEnv (String name , String def ) {
208+ String res = System .getenv (name );
209+ return (res != null ) ? res : def ;
210+ }
211+
212+ public static boolean getEnvFlag (String name , boolean def ) {
213+ String res = System .getenv (name );
214+ return res != null ? Boolean .parseBoolean (res ) : def ;
215+ }
216+
217+ /**
218+ * Checks if a FEAURE is enabled according to ENTANDO_FF_TAGS
219+ * Check also {@link ApsSystemUtils#isTagEnabled}
220+ */
221+ public static boolean isFeatureEnabled (String tag ) {
222+ return ApsSystemUtils .isTagEnabled (getFeatureFlags (), tag );
223+ }
224+
225+ /**
226+ * Checks if a tag is enabled.
227+ * <pre>
228+ * A tag is enabled if "enabledTags" lists it or one of its subtags.
229+ * A tag is divided in subtags by the char ":"</p>
230+ *
231+ * For instance, if the tag "A-FLAG" is present in enabledTags it would enable:
232+ * - The tag "A-FLAG"
233+ * - The tags like "A-FLAG:SOMETHING" (note that the subtags order doesn't matter)
234+ * </pre>
235+ */
236+ public static boolean isTagEnabled (String enabledTags , String tag ) {
237+ if (enabledTags == null ) return false ;
238+ if (enabledTags .equals ("*" ) || enabledTags .equals ("true" )) return true ;
239+ if (tag == null ) return false ;
240+ enabledTags = "," + enabledTags + "," ;
241+ if (enabledTags .contains ("," + tag + "," )) return true ;
242+ for (String subtag : tag .split (":" )) {
243+ if (enabledTags .contains ("," + subtag + "," )) return true ;
244+ }
245+ return false ;
246+ }
247+
248+ /* Mockable getter of the constant */
249+ public static String getFeatureFlags () {
250+ return ENTANDO_FEATURE_FLAGS ;
251+ }
252+
253+ static public String getDeepDebugFF () {
254+ return ApsDeepDebug .ENTANDO_FF_DEEP_DEBUG ;
255+ }
256+
82257}
0 commit comments