001/* 002 * Copyright (C) 2015-present 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>> configExcludeObjectNameAttributesMap; 045 private final Map<ObjectName, Set<String>> dynamicExcludeObjectNameAttributesMap; 046 047 private boolean autoExcludeObjectNameAttributes; 048 049 /** Constructor */ 050 private ObjectNameAttributeFilter() { 051 configExcludeObjectNameAttributesMap = new ConcurrentHashMap<>(); 052 dynamicExcludeObjectNameAttributesMap = new ConcurrentHashMap<>(); 053 } 054 055 /** 056 * Method to initialize the ObjectNameAttributeFilter 057 * 058 * @param yamlConfig yamlConfig 059 * @return an ObjectNameAttributeFilter 060 * @throws MalformedObjectNameException MalformedObjectNameException 061 */ 062 private ObjectNameAttributeFilter initialize(Map<String, Object> yamlConfig) 063 throws MalformedObjectNameException { 064 if (yamlConfig.containsKey(EXCLUDE_OBJECT_NAME_ATTRIBUTES)) { 065 Map<Object, Object> objectNameAttributeMap = 066 (Map<Object, Object>) yamlConfig.get(EXCLUDE_OBJECT_NAME_ATTRIBUTES); 067 068 for (Map.Entry<Object, Object> entry : objectNameAttributeMap.entrySet()) { 069 ObjectName objectName = new ObjectName((String) entry.getKey()); 070 071 List<String> attributeNames = (List<String>) entry.getValue(); 072 073 Set<String> attributeNameSet = 074 configExcludeObjectNameAttributesMap.computeIfAbsent( 075 objectName, o -> Collections.synchronizedSet(new HashSet<>())); 076 077 attributeNameSet.addAll(attributeNames); 078 } 079 } 080 081 if (yamlConfig.containsKey(AUTO_EXCLUDE_OBJECT_NAME_ATTRIBUTES)) { 082 autoExcludeObjectNameAttributes = 083 (Boolean) yamlConfig.get(AUTO_EXCLUDE_OBJECT_NAME_ATTRIBUTES); 084 } else { 085 autoExcludeObjectNameAttributes = true; 086 } 087 088 LOGGER.log(Level.FINE, "dynamicExclusion [%b]", autoExcludeObjectNameAttributes); 089 090 return this; 091 } 092 093 /** 094 * Method to add an attribute name to the filter if dynamic exclusion is enabled 095 * 096 * @param objectName the ObjectName 097 * @param attributeName the attribute name 098 */ 099 public void add(ObjectName objectName, String attributeName) { 100 if (autoExcludeObjectNameAttributes) { 101 Set<String> attribteNameSet = 102 dynamicExcludeObjectNameAttributesMap.computeIfAbsent( 103 objectName, o -> Collections.synchronizedSet(new HashSet<>())); 104 105 LOGGER.log( 106 Level.FINE, 107 "auto adding exclusion of object name [%s] attribute name [%s]", 108 objectName.getCanonicalName(), 109 attributeName); 110 111 attribteNameSet.add(attributeName); 112 } 113 } 114 115 /** 116 * Method to only keep "alive" mBeans, remove old mBeans to prevent memory growth 117 * 118 * @param aliveMBeans aliveMBeans 119 */ 120 public void onlyKeepMBeans(Set<ObjectName> aliveMBeans) { 121 if (autoExcludeObjectNameAttributes) { 122 for (ObjectName prevName : dynamicExcludeObjectNameAttributesMap.keySet()) { 123 if (!aliveMBeans.contains(prevName)) { 124 dynamicExcludeObjectNameAttributesMap.remove(prevName); 125 } 126 } 127 } 128 } 129 130 /** 131 * Method to check if an attribute should be excluded 132 * 133 * @param objectName the ObjectName 134 * @param attributeName the attribute name 135 * @return true if it should be excluded, false otherwise 136 */ 137 public boolean exclude(ObjectName objectName, String attributeName) { 138 return exclude(configExcludeObjectNameAttributesMap, objectName, attributeName) 139 || exclude(dynamicExcludeObjectNameAttributesMap, objectName, attributeName); 140 } 141 142 private boolean exclude( 143 Map<ObjectName, Set<String>> exclusionMap, 144 ObjectName objectName, 145 String attributeName) { 146 boolean result = false; 147 if (!exclusionMap.isEmpty()) { 148 Set<String> attributeNameSet = exclusionMap.get(objectName); 149 if (attributeNameSet != null) { 150 result = attributeNameSet.contains(attributeName); 151 } 152 } 153 return result; 154 } 155 156 /** 157 * Method to create an ObjectNameAttributeFilter 158 * 159 * @param yamlConfig yamlConfig 160 * @return an ObjectNameAttributeFilter 161 */ 162 public static ObjectNameAttributeFilter create(Map<String, Object> yamlConfig) { 163 try { 164 return new ObjectNameAttributeFilter().initialize(yamlConfig); 165 } catch (MalformedObjectNameException e) { 166 throw new RuntimeException( 167 "Invalid configuration format for excludeObjectNameAttributes", e); 168 } 169 } 170}