1313 */
1414package software .amazon .lambda .powertools .logging .internal ;
1515
16+ import java .io .ByteArrayInputStream ;
17+ import java .io .ByteArrayOutputStream ;
18+ import java .io .IOException ;
19+ import java .io .InputStream ;
20+ import java .io .InputStreamReader ;
21+ import java .io .OutputStreamWriter ;
22+ import java .util .Map ;
23+ import java .util .Optional ;
24+ import java .util .Random ;
25+
1626import com .amazonaws .services .lambda .runtime .Context ;
1727import com .fasterxml .jackson .databind .ObjectMapper ;
1828import org .apache .logging .log4j .Level ;
1929import org .apache .logging .log4j .LogManager ;
2030import org .apache .logging .log4j .Logger ;
21- import org .apache .logging .log4j .ThreadContext ;
2231import org .apache .logging .log4j .core .LoggerContext ;
2332import org .apache .logging .log4j .core .config .Configurator ;
2433import org .apache .logging .log4j .core .util .IOUtils ;
2837import org .aspectj .lang .annotation .Pointcut ;
2938import software .amazon .lambda .powertools .logging .PowertoolsLogging ;
3039
31- import java .io .ByteArrayInputStream ;
32- import java .io .ByteArrayOutputStream ;
33- import java .io .IOException ;
34- import java .io .InputStream ;
35- import java .io .InputStreamReader ;
36- import java .io .OutputStreamWriter ;
37- import java .util .Map ;
38- import java .util .Optional ;
39-
4040import static java .util .Optional .empty ;
4141import static java .util .Optional .of ;
4242import static software .amazon .lambda .powertools .core .internal .LambdaHandlerProcessor .coldStartDone ;
4545import static software .amazon .lambda .powertools .core .internal .LambdaHandlerProcessor .placedOnRequestHandler ;
4646import static software .amazon .lambda .powertools .core .internal .LambdaHandlerProcessor .placedOnStreamHandler ;
4747import static software .amazon .lambda .powertools .core .internal .LambdaHandlerProcessor .serviceName ;
48+ import static software .amazon .lambda .powertools .logging .PowertoolsLogger .appendKey ;
49+ import static software .amazon .lambda .powertools .logging .PowertoolsLogger .appendKeys ;
4850
4951@ Aspect
5052public final class LambdaLoggingAspect {
51- private static final ObjectMapper mapper = new ObjectMapper ();
52- private static String LOG_LEVEL = System .getenv ("LOG_LEVEL" );
53+ private static final Logger LOG = LogManager .getLogger (LambdaLoggingAspect .class );
54+ private static final ObjectMapper MAPPER = new ObjectMapper ();
55+ private static final Random SAMPLER = new Random ();
5356
54- static {
55- resetLogLevels ();
56- }
57+ private static final String LOG_LEVEL = System .getenv ("LOG_LEVEL" );
58+ private static final String SAMPLING_RATE = System .getenv ("POWERTOOLS_LOGGER_SAMPLE_RATE" );
5759
58- private static void resetLogLevels () {
59- if ( LOG_LEVEL != null ) {
60- LoggerContext ctx = ( LoggerContext ) LogManager . getContext ( false );
61- Configurator . setAllLevels ( LogManager . getRootLogger (). getName (), Level . getLevel ( LOG_LEVEL ));
62- ctx . updateLoggers ( );
60+ private static Level LEVEL_AT_INITIALISATION ;
61+
62+ static {
63+ if ( null != LOG_LEVEL ) {
64+ resetLogLevels ( Level . getLevel ( LOG_LEVEL ) );
6365 }
66+
67+ LEVEL_AT_INITIALISATION = LOG .getLevel ();
6468 }
6569
6670 @ SuppressWarnings ({"EmptyMethod" })
@@ -73,11 +77,13 @@ public Object around(ProceedingJoinPoint pjp,
7377 PowertoolsLogging powertoolsLogging ) throws Throwable {
7478 Object [] proceedArgs = pjp .getArgs ();
7579
80+ setLogLevelBasedOnSamplingRate (pjp , powertoolsLogging );
81+
7682 extractContext (pjp )
7783 .ifPresent (context -> {
78- ThreadContext . putAll (DefaultLambdaFields .values (context ));
79- ThreadContext . put ("coldStart" , null == isColdStart () ? "true" : "false" );
80- ThreadContext . put ("service" , serviceName ());
84+ appendKeys (DefaultLambdaFields .values (context ));
85+ appendKey ("coldStart" , null == isColdStart () ? "true" : "false" );
86+ appendKey ("service" , serviceName ());
8187 });
8288
8389
@@ -91,7 +97,49 @@ public Object around(ProceedingJoinPoint pjp,
9197 return proceed ;
9298 }
9399
94- private Optional <Context > extractContext (ProceedingJoinPoint pjp ) {
100+ private static void resetLogLevels (Level logLevel ) {
101+ LoggerContext ctx = (LoggerContext ) LogManager .getContext (false );
102+ Configurator .setAllLevels (LogManager .getRootLogger ().getName (), logLevel );
103+ ctx .updateLoggers ();
104+ }
105+
106+ private void setLogLevelBasedOnSamplingRate (final ProceedingJoinPoint pjp ,
107+ final PowertoolsLogging powertoolsLogging ) {
108+ if (isHandlerMethod (pjp )) {
109+ float sample = SAMPLER .nextFloat ();
110+ double samplingRate = samplingRate (powertoolsLogging );
111+
112+ if (samplingRate < 0 || samplingRate > 1 ) {
113+ LOG .debug ("Skipping sampling rate configuration because of invalid value. Sampling rate: {}" , samplingRate );
114+ return ;
115+ }
116+
117+ appendKey ("samplingRate" , String .valueOf (samplingRate ));
118+
119+ if (samplingRate > sample ) {
120+ resetLogLevels (Level .DEBUG );
121+
122+ LOG .debug ("Changed log level to DEBUG based on Sampling configuration. " +
123+ "Sampling Rate: {}, Sampler Value: {}." , samplingRate , sample );
124+ } else if (LEVEL_AT_INITIALISATION != LOG .getLevel ()) {
125+ resetLogLevels (LEVEL_AT_INITIALISATION );
126+ }
127+ }
128+ }
129+
130+ private double samplingRate (final PowertoolsLogging powertoolsLogging ) {
131+ if (null != SAMPLING_RATE ) {
132+ try {
133+ return Double .parseDouble (SAMPLING_RATE );
134+ } catch (NumberFormatException e ) {
135+ LOG .debug ("Skipping sampling rate on environment variable configuration because of invalid " +
136+ "value. Sampling rate: {}" , SAMPLING_RATE );
137+ }
138+ }
139+ return powertoolsLogging .samplingRate ();
140+ }
141+
142+ private Optional <Context > extractContext (final ProceedingJoinPoint pjp ) {
95143
96144 if (isHandlerMethod (pjp )) {
97145 if (placedOnRequestHandler (pjp )) {
@@ -106,7 +154,7 @@ private Optional<Context> extractContext(ProceedingJoinPoint pjp) {
106154 return empty ();
107155 }
108156
109- private Object [] logEvent (ProceedingJoinPoint pjp ) {
157+ private Object [] logEvent (final ProceedingJoinPoint pjp ) {
110158 Object [] args = pjp .getArgs ();
111159
112160 if (isHandlerMethod (pjp )) {
@@ -123,7 +171,7 @@ private Object[] logEvent(ProceedingJoinPoint pjp) {
123171 return args ;
124172 }
125173
126- private Object [] logFromInputStream (ProceedingJoinPoint pjp ) {
174+ private Object [] logFromInputStream (final ProceedingJoinPoint pjp ) {
127175 Object [] args = pjp .getArgs ();
128176
129177 try (ByteArrayOutputStream out = new ByteArrayOutputStream ();
@@ -136,7 +184,7 @@ private Object[] logFromInputStream(ProceedingJoinPoint pjp) {
136184 args [0 ] = new ByteArrayInputStream (bytes );
137185
138186 Logger log = logger (pjp );
139- log .info (mapper .readValue (bytes , Map .class ));
187+ log .info (MAPPER .readValue (bytes , Map .class ));
140188
141189 } catch (IOException e ) {
142190 Logger log = logger (pjp );
@@ -146,7 +194,7 @@ private Object[] logFromInputStream(ProceedingJoinPoint pjp) {
146194 return args ;
147195 }
148196
149- private Logger logger (ProceedingJoinPoint pjp ) {
197+ private Logger logger (final ProceedingJoinPoint pjp ) {
150198 return LogManager .getLogger (pjp .getSignature ().getDeclaringType ());
151199 }
152200}
0 commit comments