001/* 002 * Copyright (C) 2015-2023 The Prometheus jmx_exporter Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package io.prometheus.jmx; 018 019import io.prometheus.jmx.logger.Logger; 020import io.prometheus.jmx.logger.LoggerFactory; 021import java.util.Collections; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026import java.util.concurrent.ConcurrentHashMap; 027import java.util.logging.Level; 028import javax.management.MalformedObjectNameException; 029import javax.management.ObjectName; 030 031/** Class to implement filtering of an MBean's attributes based on the attribute's name */ 032@SuppressWarnings("unchecked") 033public class ObjectNameAttributeFilter { 034 035 private static final Logger LOGGER = LoggerFactory.getLogger(ObjectNameAttributeFilter.class); 036 037 /** Configuration constant to define a mapping of ObjectNames to attribute names */ 038 public static final String EXCLUDE_OBJECT_NAME_ATTRIBUTES = "excludeObjectNameAttributes"; 039 040 /** Configuration constant to enable auto ObjectName attributes filtering */ 041 public static final String AUTO_EXCLUDE_OBJECT_NAME_ATTRIBUTES = 042 "autoExcludeObjectNameAttributes"; 043 044 private final Map<ObjectName, Set<String>> excludeObjectNameAttributesMap; 045 046 private boolean autoExcludeObjectNameAttributes; 047 048 /** Constructor */ 049 private ObjectNameAttributeFilter() { 050 excludeObjectNameAttributesMap = new ConcurrentHashMap<>(); 051 } 052 053 /** 054 * Method to initialize the ObjectNameAttributeFilter 055 * 056 * @param yamlConfig yamlConfig 057 * @return an ObjectNameAttributeFilter 058 * @throws MalformedObjectNameException MalformedObjectNameException 059 */ 060 private ObjectNameAttributeFilter initialize(Map<String, Object> yamlConfig) 061 throws MalformedObjectNameException { 062 if (yamlConfig.containsKey(EXCLUDE_OBJECT_NAME_ATTRIBUTES)) { 063 Map<Object, Object> objectNameAttributeMap = 064 (Map<Object, Object>) yamlConfig.get(EXCLUDE_OBJECT_NAME_ATTRIBUTES); 065 066 for (Map.Entry<Object, Object> entry : objectNameAttributeMap.entrySet()) { 067 ObjectName objectName = new ObjectName((String) entry.getKey()); 068 069 List<String> attributeNames = (List<String>) entry.getValue(); 070 071 Set<String> attributeNameSet = 072 excludeObjectNameAttributesMap.computeIfAbsent( 073 objectName, o -> Collections.synchronizedSet(new HashSet<>())); 074 075 for (String attributeName : attributeNames) { 076 LOGGER.log( 077 Level.FINE, 078 "excluding object name [%d] attribute name [%s]", 079 objectName.getCanonicalName(), 080 attributeName); 081 attributeNameSet.add(attributeName); 082 } 083 084 excludeObjectNameAttributesMap.put(objectName, attributeNameSet); 085 } 086 } 087 088 if (yamlConfig.containsKey(AUTO_EXCLUDE_OBJECT_NAME_ATTRIBUTES)) { 089 autoExcludeObjectNameAttributes = 090 (Boolean) yamlConfig.get(AUTO_EXCLUDE_OBJECT_NAME_ATTRIBUTES); 091 } else { 092 autoExcludeObjectNameAttributes = true; 093 } 094 095 LOGGER.log(Level.FINE, "dynamicExclusion [%b]", autoExcludeObjectNameAttributes); 096 097 return this; 098 } 099 100 /** 101 * Method to add an attribute name to the filter if dynamic exclusion is enabled 102 * 103 * @param objectName the ObjectName 104 * @param attributeName the attribute name 105 */ 106 public void add(ObjectName objectName, String attributeName) { 107 if (autoExcludeObjectNameAttributes) { 108 Set<String> attribteNameSet = 109 excludeObjectNameAttributesMap.computeIfAbsent( 110 objectName, o -> Collections.synchronizedSet(new HashSet<>())); 111 112 LOGGER.log( 113 Level.FINE, 114 "auto adding exclusion of object name [%s] attribute name [%s]", 115 objectName.getCanonicalName(), 116 attributeName); 117 118 attribteNameSet.add(attributeName); 119 } 120 } 121 122 /** 123 * Method to check if an attribute should be excluded 124 * 125 * @param objectName the ObjectName 126 * @param attributeName the attribute name 127 * @return true if it should be excluded, false otherwise 128 */ 129 public boolean exclude(ObjectName objectName, String attributeName) { 130 boolean result = false; 131 132 if (excludeObjectNameAttributesMap.size() > 0) { 133 Set<String> attributeNameSet = excludeObjectNameAttributesMap.get(objectName); 134 if (attributeNameSet != null) { 135 result = attributeNameSet.contains(attributeName); 136 } 137 } 138 139 return result; 140 } 141 142 /** 143 * Method to create an ObjectNameAttributeFilter 144 * 145 * @param yamlConfig yamlConfig 146 * @return an ObjectNameAttributeFilter 147 */ 148 public static ObjectNameAttributeFilter create(Map<String, Object> yamlConfig) { 149 try { 150 return new ObjectNameAttributeFilter().initialize(yamlConfig); 151 } catch (MalformedObjectNameException e) { 152 throw new RuntimeException( 153 "Invalid configuration format for excludeObjectNameAttributes", e); 154 } 155 } 156}