Skip to content

Commit 01614ad

Browse files
authored
Use child loggers broadly in PolicyManager (#124896) (#124938)
* Use child loggers broadly in PolicyManager * Pass ModuleEntitlements to notEntitled * Store logger name instead of object. Some of our unit tests check for equality of `ModuleEntitlements` objects, and they are entitled to do so (no pun intended). * Alright, let's cache 'em * Memoize at point of creation, not point of use * Explanatory comments
1 parent 811e4f0 commit 01614ad

File tree

2 files changed

+88
-55
lines changed

2 files changed

+88
-55
lines changed

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java

+69-45
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@
5959
import static java.util.zip.ZipFile.OPEN_READ;
6060

6161
public class PolicyManager {
62-
private static final Logger logger = LogManager.getLogger(PolicyManager.class);
62+
/**
63+
* Use this if you don't have a {@link ModuleEntitlements} in hand.
64+
*/
65+
private static final Logger generalLogger = LogManager.getLogger(PolicyManager.class);
6366

6467
static final String UNKNOWN_COMPONENT_NAME = "(unknown)";
6568
static final String SERVER_COMPONENT_NAME = "(server)";
@@ -76,7 +79,8 @@ public class PolicyManager {
7679
record ModuleEntitlements(
7780
String componentName,
7881
Map<Class<? extends Entitlement>, List<Entitlement>> entitlementsByType,
79-
FileAccessTree fileAccess
82+
FileAccessTree fileAccess,
83+
Logger logger
8084
) {
8185

8286
ModuleEntitlements {
@@ -101,8 +105,13 @@ private FileAccessTree getDefaultFileAccess(String componentName, Path component
101105
}
102106

103107
// pkg private for testing
104-
ModuleEntitlements defaultEntitlements(String componentName, Path componentPath) {
105-
return new ModuleEntitlements(componentName, Map.of(), getDefaultFileAccess(componentName, componentPath));
108+
ModuleEntitlements defaultEntitlements(String componentName, Path componentPath, String moduleName) {
109+
return new ModuleEntitlements(
110+
componentName,
111+
Map.of(),
112+
getDefaultFileAccess(componentName, componentPath),
113+
getLogger(componentName, moduleName)
114+
);
106115
}
107116

108117
// pkg private for testing
@@ -116,7 +125,8 @@ ModuleEntitlements policyEntitlements(String componentName, Path componentPath,
116125
return new ModuleEntitlements(
117126
componentName,
118127
entitlements.stream().collect(groupingBy(Entitlement::getClass)),
119-
FileAccessTree.of(componentName, moduleName, filesEntitlement, pathLookup, componentPath, exclusivePaths)
128+
FileAccessTree.of(componentName, moduleName, filesEntitlement, pathLookup, componentPath, exclusivePaths),
129+
getLogger(componentName, moduleName)
120130
);
121131
}
122132

@@ -255,17 +265,17 @@ private void neverEntitled(Class<?> callerClass, Supplier<String> operationDescr
255265
return;
256266
}
257267

258-
String componentName = getEntitlements(requestingClass).componentName();
268+
ModuleEntitlements entitlements = getEntitlements(requestingClass);
259269
notEntitled(
260270
Strings.format(
261271
"component [%s], module [%s], class [%s], operation [%s]",
262-
componentName,
272+
entitlements.componentName(),
263273
requestingClass.getModule().getName(),
264274
requestingClass,
265275
operationDescription.get()
266276
),
267277
callerClass,
268-
componentName
278+
entitlements
269279
);
270280
}
271281

@@ -323,7 +333,7 @@ public void checkFileRead(Class<?> callerClass, File file) {
323333
private static boolean isPathOnDefaultFilesystem(Path path) {
324334
var pathFileSystemClass = path.getFileSystem().getClass();
325335
if (path.getFileSystem().getClass() != DEFAULT_FILESYSTEM_CLASS) {
326-
logger.trace(
336+
generalLogger.trace(
327337
() -> Strings.format(
328338
"File entitlement trivially allowed: path [%s] is for a different FileSystem class [%s], default is [%s]",
329339
path.toString(),
@@ -383,7 +393,7 @@ public void checkFileRead(Class<?> callerClass, Path path, boolean followLinks)
383393
realPath == null ? path : Strings.format("%s -> %s", path, realPath)
384394
),
385395
callerClass,
386-
entitlements.componentName()
396+
entitlements
387397
);
388398
}
389399
}
@@ -413,7 +423,7 @@ public void checkFileWrite(Class<?> callerClass, Path path) {
413423
path
414424
),
415425
callerClass,
416-
entitlements.componentName()
426+
entitlements
417427
);
418428
}
419429
}
@@ -502,18 +512,19 @@ private void checkFlagEntitlement(
502512
PolicyParser.getEntitlementTypeName(entitlementClass)
503513
),
504514
callerClass,
505-
classEntitlements.componentName()
515+
classEntitlements
506516
);
507517
}
508-
logger.debug(
509-
() -> Strings.format(
510-
"Entitled: component [%s], module [%s], class [%s], entitlement [%s]",
511-
classEntitlements.componentName(),
512-
requestingClass.getModule().getName(),
513-
requestingClass,
514-
PolicyParser.getEntitlementTypeName(entitlementClass)
515-
)
516-
);
518+
classEntitlements.logger()
519+
.debug(
520+
() -> Strings.format(
521+
"Entitled: component [%s], module [%s], class [%s], entitlement [%s]",
522+
classEntitlements.componentName(),
523+
requestingClass.getModule().getName(),
524+
requestingClass,
525+
PolicyParser.getEntitlementTypeName(entitlementClass)
526+
)
527+
);
517528
}
518529

519530
public void checkWriteProperty(Class<?> callerClass, String property) {
@@ -524,15 +535,16 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
524535

525536
ModuleEntitlements entitlements = getEntitlements(requestingClass);
526537
if (entitlements.getEntitlements(WriteSystemPropertiesEntitlement.class).anyMatch(e -> e.properties().contains(property))) {
527-
logger.debug(
528-
() -> Strings.format(
529-
"Entitled: component [%s], module [%s], class [%s], entitlement [write_system_properties], property [%s]",
530-
entitlements.componentName(),
531-
requestingClass.getModule().getName(),
532-
requestingClass,
533-
property
534-
)
535-
);
538+
entitlements.logger()
539+
.debug(
540+
() -> Strings.format(
541+
"Entitled: component [%s], module [%s], class [%s], entitlement [write_system_properties], property [%s]",
542+
entitlements.componentName(),
543+
requestingClass.getModule().getName(),
544+
requestingClass,
545+
property
546+
)
547+
);
536548
return;
537549
}
538550
notEntitled(
@@ -544,22 +556,34 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
544556
property
545557
),
546558
callerClass,
547-
entitlements.componentName()
559+
entitlements
548560
);
549561
}
550562

551-
private void notEntitled(String message, Class<?> callerClass, String componentName) {
563+
private void notEntitled(String message, Class<?> callerClass, ModuleEntitlements entitlements) {
552564
var exception = new NotEntitledException(message);
553565
// Don't emit a log for muted classes, e.g. classes containing self tests
554566
if (mutedClasses.contains(callerClass) == false) {
555-
var moduleName = callerClass.getModule().getName();
556-
var loggerSuffix = "." + componentName + "." + ((moduleName == null) ? ALL_UNNAMED : moduleName);
557-
var notEntitledLogger = LogManager.getLogger(PolicyManager.class.getName() + loggerSuffix);
558-
notEntitledLogger.warn("Not entitled:", exception);
567+
entitlements.logger().warn("Not entitled:", exception);
559568
}
560569
throw exception;
561570
}
562571

572+
private static Logger getLogger(String componentName, String moduleName) {
573+
var loggerSuffix = "." + componentName + "." + ((moduleName == null) ? ALL_UNNAMED : moduleName);
574+
return MODULE_LOGGERS.computeIfAbsent(PolicyManager.class.getName() + loggerSuffix, LogManager::getLogger);
575+
}
576+
577+
/**
578+
* We want to use the same {@link Logger} object for a given name, because we want {@link ModuleEntitlements}
579+
* {@code equals} and {@code hashCode} to work.
580+
* <p>
581+
* This would not be required if LogManager
582+
* <a href="https://github.com/elastic/elasticsearch/issues/87511">memoized the loggers</a>,
583+
* but here we are.
584+
*/
585+
private static final ConcurrentHashMap<String, Logger> MODULE_LOGGERS = new ConcurrentHashMap<>();
586+
563587
public void checkManageThreadsEntitlement(Class<?> callerClass) {
564588
checkEntitlementPresent(callerClass, ManageThreadsEntitlement.class);
565589
}
@@ -592,7 +616,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
592616
if (pluginName != null) {
593617
var pluginEntitlements = pluginsEntitlements.get(pluginName);
594618
if (pluginEntitlements == null) {
595-
return defaultEntitlements(pluginName, sourcePaths.get(pluginName));
619+
return defaultEntitlements(pluginName, sourcePaths.get(pluginName), requestingModule.getName());
596620
} else {
597621
return getModuleScopeEntitlements(
598622
pluginEntitlements,
@@ -613,7 +637,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
613637
);
614638
}
615639

616-
return defaultEntitlements(UNKNOWN_COMPONENT_NAME, null);
640+
return defaultEntitlements(UNKNOWN_COMPONENT_NAME, null, requestingModule.getName());
617641
}
618642

619643
private static String getScopeName(Module requestingModule) {
@@ -634,7 +658,7 @@ static Path getComponentPathFromClass(Class<?> requestingClass) {
634658
return Paths.get(codeSource.getLocation().toURI());
635659
} catch (Exception e) {
636660
// If we get a URISyntaxException, or any other Exception due to an invalid URI, we return null to safely skip this location
637-
logger.info(
661+
generalLogger.info(
638662
"Cannot get component path for [{}]: [{}] cannot be converted to a valid Path",
639663
requestingClass.getName(),
640664
codeSource.getLocation().toString()
@@ -651,7 +675,7 @@ private ModuleEntitlements getModuleScopeEntitlements(
651675
) {
652676
var entitlements = scopeEntitlements.get(scopeName);
653677
if (entitlements == null) {
654-
return defaultEntitlements(componentName, componentPath);
678+
return defaultEntitlements(componentName, componentPath, scopeName);
655679
}
656680
return policyEntitlements(componentName, componentPath, scopeName, entitlements);
657681
}
@@ -694,18 +718,18 @@ Optional<StackFrame> findRequestingFrame(Stream<StackFrame> frames) {
694718
* @return true if permission is granted regardless of the entitlement
695719
*/
696720
private static boolean isTriviallyAllowed(Class<?> requestingClass) {
697-
if (logger.isTraceEnabled()) {
698-
logger.trace("Stack trace for upcoming trivially-allowed check", new Exception());
721+
if (generalLogger.isTraceEnabled()) {
722+
generalLogger.trace("Stack trace for upcoming trivially-allowed check", new Exception());
699723
}
700724
if (requestingClass == null) {
701-
logger.debug("Entitlement trivially allowed: no caller frames outside the entitlement library");
725+
generalLogger.debug("Entitlement trivially allowed: no caller frames outside the entitlement library");
702726
return true;
703727
}
704728
if (systemModules.contains(requestingClass.getModule())) {
705-
logger.debug("Entitlement trivially allowed from system module [{}]", requestingClass.getModule().getName());
729+
generalLogger.debug("Entitlement trivially allowed from system module [{}]", requestingClass.getModule().getName());
706730
return true;
707731
}
708-
logger.trace("Entitlement not trivially allowed");
732+
generalLogger.trace("Entitlement not trivially allowed");
709733
return false;
710734
}
711735

libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java

+19-10
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,12 @@ public void testGetEntitlementsThrowsOnMissingPluginUnnamedModule() {
102102

103103
assertEquals(
104104
"No policy for the unnamed module",
105-
policyManager.defaultEntitlements("plugin1", plugin1SourcePath),
105+
policyManager.defaultEntitlements("plugin1", plugin1SourcePath, requestingModule.getName()),
106106
policyManager.getEntitlements(callerClass)
107107
);
108108

109109
assertEquals(
110-
Map.of(requestingModule, policyManager.defaultEntitlements("plugin1", plugin1SourcePath)),
110+
Map.of(requestingModule, policyManager.defaultEntitlements("plugin1", plugin1SourcePath, requestingModule.getName())),
111111
policyManager.moduleEntitlementsMap
112112
);
113113
}
@@ -132,12 +132,12 @@ public void testGetEntitlementsThrowsOnMissingPolicyForPlugin() {
132132

133133
assertEquals(
134134
"No policy for this plugin",
135-
policyManager.defaultEntitlements("plugin1", plugin1SourcePath),
135+
policyManager.defaultEntitlements("plugin1", plugin1SourcePath, requestingModule.getName()),
136136
policyManager.getEntitlements(callerClass)
137137
);
138138

139139
assertEquals(
140-
Map.of(requestingModule, policyManager.defaultEntitlements("plugin1", plugin1SourcePath)),
140+
Map.of(requestingModule, policyManager.defaultEntitlements("plugin1", plugin1SourcePath, requestingModule.getName())),
141141
policyManager.moduleEntitlementsMap
142142
);
143143
}
@@ -160,18 +160,24 @@ public void testGetEntitlementsFailureIsCached() {
160160
var callerClass = this.getClass();
161161
var requestingModule = callerClass.getModule();
162162

163-
assertEquals(policyManager.defaultEntitlements("plugin1", plugin1SourcePath), policyManager.getEntitlements(callerClass));
164163
assertEquals(
165-
Map.of(requestingModule, policyManager.defaultEntitlements("plugin1", plugin1SourcePath)),
164+
policyManager.defaultEntitlements("plugin1", plugin1SourcePath, requestingModule.getName()),
165+
policyManager.getEntitlements(callerClass)
166+
);
167+
assertEquals(
168+
Map.of(requestingModule, policyManager.defaultEntitlements("plugin1", plugin1SourcePath, requestingModule.getName())),
166169
policyManager.moduleEntitlementsMap
167170
);
168171

169172
// A second time
170-
assertEquals(policyManager.defaultEntitlements("plugin1", plugin1SourcePath), policyManager.getEntitlements(callerClass));
173+
assertEquals(
174+
policyManager.defaultEntitlements("plugin1", plugin1SourcePath, requestingModule.getName()),
175+
policyManager.getEntitlements(callerClass)
176+
);
171177

172178
// Nothing new in the map
173179
assertEquals(
174-
Map.of(requestingModule, policyManager.defaultEntitlements("plugin1", plugin1SourcePath)),
180+
Map.of(requestingModule, policyManager.defaultEntitlements("plugin1", plugin1SourcePath, requestingModule.getName())),
175181
policyManager.moduleEntitlementsMap
176182
);
177183
}
@@ -219,12 +225,15 @@ public void testGetEntitlementsThrowsOnMissingPolicyForServer() throws ClassNotF
219225

220226
assertEquals(
221227
"No policy for this module in server",
222-
policyManager.defaultEntitlements(SERVER_COMPONENT_NAME, mockServerSourcePath),
228+
policyManager.defaultEntitlements(SERVER_COMPONENT_NAME, mockServerSourcePath, requestingModule.getName()),
223229
policyManager.getEntitlements(mockServerClass)
224230
);
225231

226232
assertEquals(
227-
Map.of(requestingModule, policyManager.defaultEntitlements(SERVER_COMPONENT_NAME, mockServerSourcePath)),
233+
Map.of(
234+
requestingModule,
235+
policyManager.defaultEntitlements(SERVER_COMPONENT_NAME, mockServerSourcePath, requestingModule.getName())
236+
),
228237
policyManager.moduleEntitlementsMap
229238
);
230239
}

0 commit comments

Comments
 (0)