1313import org .elasticsearch .common .settings .ClusterSettings ;
1414import org .elasticsearch .core .TimeValue ;
1515import org .elasticsearch .xcontent .json .JsonStringEncoder ;
16+ import org .elasticsearch .xpack .core .security .SecurityContext ;
17+ import org .elasticsearch .xpack .core .security .user .User ;
1618import org .elasticsearch .xpack .esql .session .Result ;
1719
1820import java .nio .charset .StandardCharsets ;
1921import java .util .HashMap ;
2022import java .util .Map ;
2123
24+ import static org .elasticsearch .xpack .esql .plugin .EsqlPlugin .ESQL_SLOWLOG_THRESHOLD_INCLUDE_USER_SETTING ;
2225import static org .elasticsearch .xpack .esql .plugin .EsqlPlugin .ESQL_SLOWLOG_THRESHOLD_QUERY_DEBUG_SETTING ;
2326import static org .elasticsearch .xpack .esql .plugin .EsqlPlugin .ESQL_SLOWLOG_THRESHOLD_QUERY_INFO_SETTING ;
2427import static org .elasticsearch .xpack .esql .plugin .EsqlPlugin .ESQL_SLOWLOG_THRESHOLD_QUERY_TRACE_SETTING ;
@@ -31,18 +34,28 @@ public final class EsqlSlowLog {
3134 public static final String SLOWLOG_PREFIX = "esql.slowlog" ;
3235
3336 private static final Logger queryLogger = LogManager .getLogger (SLOWLOG_PREFIX + ".query" );
37+ private final SecurityContext security ;
3438
3539 private volatile long queryWarnThreshold ;
3640 private volatile long queryInfoThreshold ;
3741 private volatile long queryDebugThreshold ;
3842 private volatile long queryTraceThreshold ;
3943
40- public EsqlSlowLog (ClusterSettings settings ) {
44+ private volatile boolean includeUser ;
45+
46+ public EsqlSlowLog (ClusterSettings settings , SecurityContext security ) {
4147 settings .initializeAndWatch (ESQL_SLOWLOG_THRESHOLD_QUERY_WARN_SETTING , this ::setQueryWarnThreshold );
4248 settings .initializeAndWatch (ESQL_SLOWLOG_THRESHOLD_QUERY_INFO_SETTING , this ::setQueryInfoThreshold );
4349 settings .initializeAndWatch (ESQL_SLOWLOG_THRESHOLD_QUERY_DEBUG_SETTING , this ::setQueryDebugThreshold );
4450 settings .initializeAndWatch (ESQL_SLOWLOG_THRESHOLD_QUERY_TRACE_SETTING , this ::setQueryTraceThreshold );
51+ settings .initializeAndWatch (ESQL_SLOWLOG_THRESHOLD_INCLUDE_USER_SETTING , this ::setIncludeUser );
4552 this .clusterSettings = settings ;
53+
54+ this .security = security ;
55+ }
56+
57+ public EsqlSlowLog (ClusterSettings settings ) {
58+ this (settings , null );
4659 }
4760
4861 public void onQueryPhase (Result esqlResult , String query ) {
@@ -51,28 +64,36 @@ public void onQueryPhase(Result esqlResult, String query) {
5164 }
5265 long tookInNanos = esqlResult .executionInfo ().overallTook ().nanos ();
5366 if (queryWarnThreshold >= 0 && tookInNanos > queryWarnThreshold ) {
54- queryLogger .warn (Message .of (esqlResult , query ));
67+ queryLogger .warn (Message .of (esqlResult , query , user () ));
5568 } else if (queryInfoThreshold >= 0 && tookInNanos > queryInfoThreshold ) {
56- queryLogger .info (Message .of (esqlResult , query ));
69+ queryLogger .info (Message .of (esqlResult , query , user () ));
5770
5871 } else if (queryDebugThreshold >= 0 && tookInNanos > queryDebugThreshold ) {
59- queryLogger .debug (Message .of (esqlResult , query ));
72+ queryLogger .debug (Message .of (esqlResult , query , user () ));
6073
6174 } else if (queryTraceThreshold >= 0 && tookInNanos > queryTraceThreshold ) {
62- queryLogger .trace (Message .of (esqlResult , query ));
75+ queryLogger .trace (Message .of (esqlResult , query , user () ));
6376
6477 }
6578 }
6679
80+ private User user () {
81+ User user = null ;
82+ if (includeUser && security != null ) {
83+ user = security .getUser ();
84+ }
85+ return user ;
86+ }
87+
6788 public void onQueryFailure (String query , Exception ex , long tookInNanos ) {
6889 if (queryWarnThreshold >= 0 && tookInNanos > queryWarnThreshold ) {
69- queryLogger .warn (Message .of (query , tookInNanos , ex ));
90+ queryLogger .warn (Message .of (query , tookInNanos , ex , user () ));
7091 } else if (queryInfoThreshold >= 0 && tookInNanos > queryInfoThreshold ) {
71- queryLogger .info (Message .of (query , tookInNanos , ex ));
92+ queryLogger .info (Message .of (query , tookInNanos , ex , user () ));
7293 } else if (queryDebugThreshold >= 0 && tookInNanos > queryDebugThreshold ) {
73- queryLogger .debug (Message .of (query , tookInNanos , ex ));
94+ queryLogger .debug (Message .of (query , tookInNanos , ex , user () ));
7495 } else if (queryTraceThreshold >= 0 && tookInNanos > queryTraceThreshold ) {
75- queryLogger .trace (Message .of (query , tookInNanos , ex ));
96+ queryLogger .trace (Message .of (query , tookInNanos , ex , user () ));
7697 }
7798 }
7899
@@ -92,30 +113,37 @@ public void setQueryTraceThreshold(TimeValue queryTraceThreshold) {
92113 this .queryTraceThreshold = queryTraceThreshold .nanos ();
93114 }
94115
116+ public void setIncludeUser (boolean includeUser ) {
117+ this .includeUser = includeUser ;
118+ }
119+
95120 static final class Message {
96121
97122 private static String escapeJson (String text ) {
98123 byte [] sourceEscaped = JsonStringEncoder .getInstance ().quoteAsUTF8 (text );
99124 return new String (sourceEscaped , StandardCharsets .UTF_8 );
100125 }
101126
102- public static ESLogMessage of (Result esqlResult , String query ) {
103- Map <String , Object > jsonFields = prepareMap (esqlResult , query , true );
127+ public static ESLogMessage of (Result esqlResult , String query , User user ) {
128+ Map <String , Object > jsonFields = prepareMap (esqlResult , query , true , user );
104129
105130 return new ESLogMessage ().withFields (jsonFields );
106131 }
107132
108- public static ESLogMessage of (String query , long took , Exception exception ) {
109- Map <String , Object > jsonFields = prepareMap (null , query , false );
133+ public static ESLogMessage of (String query , long took , Exception exception , User user ) {
134+ Map <String , Object > jsonFields = prepareMap (null , query , false , user );
110135 jsonFields .put ("elasticsearch.slowlog.error.message" , exception .getMessage () == null ? "" : exception .getMessage ());
111136 jsonFields .put ("elasticsearch.slowlog.error.type" , exception .getClass ().getName ());
112137 jsonFields .put ("elasticsearch.slowlog.took" , took );
113138 jsonFields .put ("elasticsearch.slowlog.took_millis" , took / 1_000_000 );
114139 return new ESLogMessage ().withFields (jsonFields );
115140 }
116141
117- private static Map <String , Object > prepareMap (Result esqlResult , String query , boolean success ) {
142+ private static Map <String , Object > prepareMap (Result esqlResult , String query , boolean success , User user ) {
118143 Map <String , Object > messageFields = new HashMap <>();
144+ if (user != null ) {
145+ messageFields .put ("user.name" , user .principal ());
146+ }
119147 if (esqlResult != null ) {
120148 messageFields .put ("elasticsearch.slowlog.took" , esqlResult .executionInfo ().overallTook ().nanos ());
121149 messageFields .put ("elasticsearch.slowlog.took_millis" , esqlResult .executionInfo ().overallTook ().millis ());
0 commit comments