11package dev .vml .es .acm .core .instance ;
22
3+ import dev .vml .es .acm .core .code .*;
4+ import dev .vml .es .acm .core .code .script .ExtensionScriptSyntax ;
35import dev .vml .es .acm .core .osgi .*;
46import dev .vml .es .acm .core .repo .Repo ;
7+ import dev .vml .es .acm .core .util .ExceptionUtils ;
58import dev .vml .es .acm .core .util .ResourceUtils ;
69import java .util .*;
710import java .util .stream .Collectors ;
811import org .apache .commons .collections .CollectionUtils ;
912import org .apache .commons .io .FilenameUtils ;
1013import org .apache .commons .lang3 .ArrayUtils ;
14+ import org .apache .commons .lang3 .StringUtils ;
1115import org .apache .sling .api .resource .ResourceResolver ;
1216import org .apache .sling .api .resource .ResourceResolverFactory ;
1317import org .apache .sling .discovery .DiscoveryService ;
@@ -38,6 +42,9 @@ public class HealthChecker implements EventHandler {
3842 @ Reference
3943 private ResourceResolverFactory resourceResolverFactory ;
4044
45+ @ Reference
46+ private Executor executor ;
47+
4148 @ Reference
4249 private InstanceInfo instanceInfo ;
4350
@@ -85,6 +92,7 @@ private HealthStatus checkStatus(ResourceResolver resourceResolver) {
8592 checkBundles (result );
8693 checkEvents (result );
8794 checkComponents (result );
95+ checkCodeExecutor (result , resourceResolver );
8896 result .healthy = CollectionUtils .isEmpty (result .issues );
8997 return result ;
9098 }
@@ -94,7 +102,8 @@ private void checkCluster(HealthStatus result) {
94102 return ;
95103 }
96104 if (!isClusterLeader ()) {
97- result .issues .add (new HealthIssue (HealthIssueSeverity .CRITICAL , "Instance is not a cluster leader" ));
105+ result .issues .add (new HealthIssue (
106+ HealthIssueSeverity .CRITICAL , HealthIssueCategory .INSTANCE , "Not a cluster leader" , null ));
98107 }
99108 }
100109
@@ -115,12 +124,16 @@ private void checkInstaller(HealthStatus result, ResourceResolver resourceResolv
115124 if (state .isActive ()) {
116125 result .issues .add (new HealthIssue (
117126 HealthIssueSeverity .CRITICAL ,
118- String .format ("Sling Installer is active (%d)" , state .getActiveResourceCount ())));
127+ HealthIssueCategory .INSTALLER ,
128+ String .format ("Active resource count: %d" , state .getActiveResourceCount ()),
129+ null ));
119130 }
120131 if (state .isPaused ()) {
121132 result .issues .add (new HealthIssue (
122133 HealthIssueSeverity .CRITICAL ,
123- String .format ("Sling Installer is paused (%d)" , state .getPauseCount ())));
134+ HealthIssueCategory .INSTALLER ,
135+ String .format ("Pause count: %d" , state .getPauseCount ()),
136+ null ));
124137 }
125138 }
126139
@@ -130,14 +143,20 @@ private void checkRepository(HealthStatus result, ResourceResolver resourceResol
130143 }
131144 Repo repo = new Repo (resourceResolver );
132145 if ((instanceInfo .getType () == InstanceType .CLOUD_CONTAINER ) && !repo .isCompositeNodeStore ()) {
133- result .issues .add (
134- new HealthIssue (HealthIssueSeverity .CRITICAL , "Repository is not yet using composite node store" ));
146+ result .issues .add (new HealthIssue (
147+ HealthIssueSeverity .CRITICAL ,
148+ HealthIssueCategory .REPOSITORY ,
149+ "Composite node store not available" ,
150+ null ));
135151 }
136152 if (ArrayUtils .isNotEmpty (config .repositoryPathsExisted ())) {
137153 Arrays .stream (config .repositoryPathsExisted ()).forEach (path -> {
138154 if (!repo .get (path ).exists ()) {
139155 result .issues .add (new HealthIssue (
140- HealthIssueSeverity .CRITICAL , String .format ("Repository path '%s' does not exist" , path )));
156+ HealthIssueSeverity .CRITICAL ,
157+ HealthIssueCategory .REPOSITORY ,
158+ String .format ("Path does not exist: '%s'" , path ),
159+ null ));
141160 }
142161 });
143162 }
@@ -152,13 +171,17 @@ private void checkBundles(HealthStatus result) {
152171 if (!osgiScanner .isBundleResolved (bundle )) {
153172 result .issues .add (new HealthIssue (
154173 HealthIssueSeverity .CRITICAL ,
155- String .format ("Bundle fragment '%s' is not resolved" , bundle .getSymbolicName ())));
174+ HealthIssueCategory .OSGI ,
175+ String .format ("Bundle fragment not resolved: '%s'" , bundle .getSymbolicName ()),
176+ null ));
156177 }
157178 } else {
158179 if (!osgiScanner .isBundleActive (bundle )) {
159180 result .issues .add (new HealthIssue (
160181 HealthIssueSeverity .CRITICAL ,
161- String .format ("Bundle '%s' is not active" , bundle .getSymbolicName ())));
182+ HealthIssueCategory .OSGI ,
183+ String .format ("Bundle not active: '%s'" , bundle .getSymbolicName ()),
184+ null ));
162185 }
163186 }
164187 });
@@ -186,7 +209,10 @@ private void checkEvents(HealthStatus result) {
186209 Map <String , Long > eventCounts =
187210 recentEvents .stream ().collect (Collectors .groupingBy (OsgiEvent ::getTopic , Collectors .counting ()));
188211 eventCounts .forEach ((topic , count ) -> result .issues .add (new HealthIssue (
189- HealthIssueSeverity .CRITICAL , String .format ("Event '%s' occurred (%d)" , topic , count ))));
212+ HealthIssueSeverity .CRITICAL ,
213+ HealthIssueCategory .OSGI ,
214+ String .format ("Event occurred (%d): %s" , count , topic ),
215+ null )));
190216 }
191217 }
192218
@@ -213,6 +239,30 @@ private void checkComponents(HealthStatus result) {
213239 // TODO ...
214240 }
215241
242+ private void checkCodeExecutor (HealthStatus result , ResourceResolver resourceResolver ) {
243+ try (ExecutionContext context = executor .createContext (
244+ ExecutionId .generate (), ExecutionMode .RUN , Code .consoleMinimal (), resourceResolver )) {
245+ context .setHistory (false );
246+ Execution execution = executor .execute (context );
247+ if (execution .getStatus () != ExecutionStatus .SUCCEEDED ) {
248+ result .issues .add (new HealthIssue (
249+ HealthIssueSeverity .CRITICAL ,
250+ HealthIssueCategory .CODE_EXECUTOR ,
251+ String .format (
252+ "Execution not succeeded: %s" ,
253+ execution .getStatus ().name ().toLowerCase ()),
254+ execution .getError ()));
255+ }
256+ } catch (Exception e ) {
257+ String error = ExceptionUtils .toString (e );
258+ String issue = StringUtils .contains (error , ExtensionScriptSyntax .MAIN_CLASS + ":" )
259+ ? "Extension script error"
260+ : "Execution context error" ;
261+ result .issues .add (
262+ new HealthIssue (HealthIssueSeverity .CRITICAL , HealthIssueCategory .CODE_EXECUTOR , issue , error ));
263+ }
264+ }
265+
216266 @ ObjectClassDefinition (name = "AEM Content Manager - Health Checker" )
217267 public @interface Config {
218268
0 commit comments