/* * Copyright (c) 2010-2016 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.evolveum.midpoint.schema.internals; import com.evolveum.midpoint.prism.Objectable; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.util.PrismMonitor; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; /** * Simple monitoring object. It records the count of expensive operations * in the system. It is used in the tests to make sure such operations are not * executed more frequently than expected. It may also have some run-time value. * * @author Radovan Semancik * */ public class InternalMonitor implements PrismMonitor { private static final Trace LOGGER = TraceManager.getTrace(InternalMonitor.class); private static final String CLONE_START_TIMESTAMP_KEY = InternalMonitor.class.getName()+".cloneStartTimestamp"; private static long resourceSchemaParseCount = 0; private static long resourceSchemaFetchCount = 0; private static boolean traceResourceSchemaOperations = false; private static long connectorInstanceInitializationCount = 0; private static long connectorSchemaParseCount = 0; private static long connectorCapabilitiesFetchCount = 0; private static CachingStatistics resourceCacheStats = new CachingStatistics(); private static CachingStatistics connectorCacheStats = new CachingStatistics(); private static long scriptCompileCount = 0; private static long scriptExecutionCount = 0; private static boolean traceConnectorOperation = false; private static long connectorOperationCount = 0; private static long connectorSimulatedPagingSearchCount = 0; private static long shadowFetchOperationCount = 0; private static boolean traceShadowFetchOperation = false; private static long shadowChangeOpeartionCount = 0; /** * All provisioning operations that reach out to the resources. */ private static long provisioningAllExtOperationCount = 0; private static long prismObjectCloneCount = 0; private static long prismObjectCloneDurationMillis = 0; private static boolean tracePrismObjectClone = false; public static long getResourceSchemaParseCount() { return resourceSchemaParseCount; } public synchronized static void recordResourceSchemaParse() { resourceSchemaParseCount++; if (traceShadowFetchOperation) { traceOperation("resource schema parse", resourceSchemaParseCount, true); } } public static long getConnectorInstanceInitializationCount() { return connectorInstanceInitializationCount; } public synchronized static void recordConnectorInstanceInitialization() { connectorInstanceInitializationCount++; } public static long getResourceSchemaFetchCount() { return resourceSchemaFetchCount; } public synchronized static void recordResourceSchemaFetch() { resourceSchemaFetchCount++; provisioningAllExtOperationCount++; if (traceShadowFetchOperation) { traceOperation("resource schema fetch", resourceSchemaFetchCount, true); } } public static long getConnectorSchemaParseCount() { return connectorSchemaParseCount; } public synchronized static void recordConnectorSchemaParse() { connectorSchemaParseCount++; } public static long getConnectorCapabilitiesFetchCount() { return connectorCapabilitiesFetchCount; } public synchronized static void recordConnectorCapabilitiesFetchCount() { connectorCapabilitiesFetchCount++; provisioningAllExtOperationCount++; } public static CachingStatistics getResourceCacheStats() { return resourceCacheStats; } public static CachingStatistics getConnectorCacheStats() { return connectorCacheStats; } public static long getScriptCompileCount() { return scriptCompileCount; } public static void setScriptCompileCount(long scriptCompileCount) { InternalMonitor.scriptCompileCount = scriptCompileCount; } public static void recordScriptCompile() { scriptCompileCount++; } public static long getScriptExecutionCount() { return scriptExecutionCount; } public static void setScriptExecutionCount(long scriptExecutionCount) { InternalMonitor.scriptExecutionCount = scriptExecutionCount; } public static void recordScriptExecution() { scriptExecutionCount++; } public static long getShadowFetchOperationCount() { return shadowFetchOperationCount; } public static void recordShadowFetchOperation() { shadowFetchOperationCount++; provisioningAllExtOperationCount++; if (traceShadowFetchOperation) { traceOperation("shadow fetch", shadowFetchOperationCount, true); } } public static boolean isTraceShadowFetchOperation() { return traceShadowFetchOperation; } public static void setTraceShadowFetchOperation(boolean traceShadowFetchOperation) { LOGGER.debug("MONITOR traceShadowFetchOperation={}", traceShadowFetchOperation); InternalMonitor.traceShadowFetchOperation = traceShadowFetchOperation; } public static boolean isTraceResourceSchemaOperations() { return traceResourceSchemaOperations; } public static void setTraceResourceSchemaOperations( boolean traceResourceSchemaOperations) { LOGGER.debug("MONITOR traceResourceSchemaOperations={}", traceResourceSchemaOperations); InternalMonitor.traceResourceSchemaOperations = traceResourceSchemaOperations; } public static long getShadowChangeOpeartionCount() { return shadowChangeOpeartionCount; } public static void recordShadowChangeOperation() { shadowChangeOpeartionCount++; provisioningAllExtOperationCount++; } public static long getConnectorOperationCount() { return connectorOperationCount; } public static void recordConnectorOperation(String name) { connectorOperationCount++; if (traceConnectorOperation) { traceOperation("connector "+name, connectorOperationCount, true); } } public static long getConnectorSimulatedPagingSearchCount() { return connectorSimulatedPagingSearchCount; } public static void recordConnectorSimulatedPagingSearchCount() { connectorSimulatedPagingSearchCount++; if (traceConnectorOperation) { traceOperation("simulated paged search", connectorSimulatedPagingSearchCount, true); } } public static boolean isTraceConnectorOperation() { return traceShadowFetchOperation; } public static void setTraceConnectorOperation(boolean trace) { LOGGER.debug("MONITOR traceConnectorOperation={}", trace); InternalMonitor.traceConnectorOperation = trace; } public static long getProvisioningAllExtOperationCont() { return provisioningAllExtOperationCount; } public static void recordShadowOtherOperation() { provisioningAllExtOperationCount++; } public static long getPrismObjectCloneDurationMillis() { return prismObjectCloneDurationMillis; } public static void setPrismObjectCloneDurationMillis(long prismObjectCloneDurationMillis) { InternalMonitor.prismObjectCloneDurationMillis = prismObjectCloneDurationMillis; } public static boolean isTracePrismObjectClone() { return tracePrismObjectClone; } public static void setTracePrismObjectClone(boolean tracePrismObjectClone) { InternalMonitor.tracePrismObjectClone = tracePrismObjectClone; } @Override public <O extends Objectable> void beforeObjectClone(PrismObject<O> orig) { LOGGER.trace("MONITOR prism object clone start: {}", orig); if (!orig.isImmutable()) { orig.setUserData(CLONE_START_TIMESTAMP_KEY, System.currentTimeMillis()); } } @Override public synchronized <O extends Objectable> void afterObjectClone(PrismObject<O> orig, PrismObject<O> clone) { prismObjectCloneCount++; Object cloneStartObject = orig.getUserData(CLONE_START_TIMESTAMP_KEY); if (cloneStartObject != null && cloneStartObject instanceof Long) { long cloneDurationMillis = System.currentTimeMillis() - (Long)cloneStartObject; prismObjectCloneDurationMillis += cloneDurationMillis; LOGGER.debug("MONITOR prism object clone end: {} (duration {} ms)", orig, cloneDurationMillis); } else { LOGGER.debug("MONITOR prism object clone end: {}", orig); } if (tracePrismObjectClone) { traceOperation("prism object clone", prismObjectCloneCount, false); } } public static long getPrismObjectCloneCount() { return prismObjectCloneCount; } public static void setPrismObjectCloneCount(long prismObjectCloneCount) { InternalMonitor.prismObjectCloneCount = prismObjectCloneCount; } public static void reset() { LOGGER.info("MONITOR reset"); resourceSchemaParseCount = 0; connectorInstanceInitializationCount = 0; resourceSchemaFetchCount = 0; connectorSchemaParseCount = 0; connectorCapabilitiesFetchCount = 0; resourceCacheStats = new CachingStatistics(); connectorCacheStats = new CachingStatistics(); scriptCompileCount = 0; scriptExecutionCount = 0; shadowFetchOperationCount = 0; traceShadowFetchOperation = false; shadowChangeOpeartionCount = 0; traceConnectorOperation = false; connectorOperationCount = 0; } private static void traceOperation(String opName, long counter, boolean traceAndDebug) { LOGGER.info("MONITOR {} ({})", opName, counter); if (LOGGER.isDebugEnabled()) { StackTraceElement[] fullStack = Thread.currentThread().getStackTrace(); String immediateClass = null; String immediateMethod = null; StringBuilder sb = new StringBuilder(); for (StackTraceElement stackElement: fullStack) { if (stackElement.getClassName().equals(InternalMonitor.class.getName()) || stackElement.getClassName().equals(Thread.class.getName())) { // skip our own calls continue; } if (immediateClass == null) { immediateClass = stackElement.getClassName(); immediateMethod = stackElement.getMethodName(); } sb.append(stackElement.toString()); sb.append("\n"); } if (traceAndDebug) { LOGGER.debug("MONITOR {} ({}): {} {}", new Object[]{opName, counter, immediateClass, immediateMethod}); } LOGGER.trace("MONITOR {} ({}):\n{}", new Object[]{opName, counter, sb}); } } }