/* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2006-2010 Sun Microsystems, Inc. * Portions Copyright 2012-2016 ForgeRock AS. */ package org.opends.server.protocols.ldap; import static org.opends.messages.ProtocolMessages.*; import static org.opends.server.protocols.ldap.LDAPConstants.*; import static org.opends.server.util.ServerConstants.*; import java.util.concurrent.atomic.AtomicLong; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.opendj.config.server.ConfigException; import org.forgerock.opendj.ldap.schema.ObjectClass; import org.forgerock.opendj.server.config.server.MonitorProviderCfg; import org.opends.server.api.MonitorData; import org.opends.server.api.MonitorProvider; import org.opends.server.core.DirectoryServer; import org.opends.server.types.OperationType; /** * This class defines a data structure that will be used to keep track * of various metrics related to LDAP communication that the server has * conducted. The statistics that will be tracked include: * *
*
* This class may also be used in a hierarchical form if it is desirable * to get specific and general statistics at the same time (e.g., * information about the interaction with a specific client or * aggregated for all clients). */ public class LDAPStatistics extends MonitorProvider { // The statistics maintained by this class. private AtomicLong abandonRequests = new AtomicLong(0); private AtomicLong addRequests = new AtomicLong(0); private AtomicLong bindRequests = new AtomicLong(0); private AtomicLong addResponses = new AtomicLong(0); private AtomicLong bindResponses = new AtomicLong(0); private AtomicLong bytesRead = new AtomicLong(0); private AtomicLong bytesWritten = new AtomicLong(0); private AtomicLong compareRequests = new AtomicLong(0); private AtomicLong compareResponses = new AtomicLong(0); private AtomicLong connectionsClosed = new AtomicLong(0); private AtomicLong connectionsEstablished = new AtomicLong(0); private AtomicLong deleteRequests = new AtomicLong(0); private AtomicLong deleteResponses = new AtomicLong(0); private AtomicLong extendedRequests = new AtomicLong(0); private AtomicLong extendedResponses = new AtomicLong(0); private AtomicLong messagesRead = new AtomicLong(0); private AtomicLong messagesWritten = new AtomicLong(0); private AtomicLong modifyRequests = new AtomicLong(0); private AtomicLong modifyResponses = new AtomicLong(0); private AtomicLong modifyDNRequests = new AtomicLong(0); private AtomicLong modifyDNResponses = new AtomicLong(0); private AtomicLong operationsAbandoned = new AtomicLong(0); private AtomicLong operationsCompleted = new AtomicLong(0); private AtomicLong operationsInitiated = new AtomicLong(0); private AtomicLong searchRequests = new AtomicLong(0); private AtomicLong searchOneRequests = new AtomicLong(0); private AtomicLong searchSubRequests = new AtomicLong(0); private AtomicLong searchResultEntries = new AtomicLong(0); private AtomicLong searchResultReferences = new AtomicLong(0); private AtomicLong searchResultsDone = new AtomicLong(0); private AtomicLong unbindRequests = new AtomicLong(0); /** The instance name for this monitor provider instance. */ private final String instanceName; // Monitor Objects : for Operations (count and time) private AtomicLong addOperationCount = new AtomicLong(0); private AtomicLong addOperationTime = new AtomicLong(0); private AtomicLong searchOperationCount = new AtomicLong(0); private AtomicLong searchOperationTime = new AtomicLong(0); private AtomicLong delOperationCount = new AtomicLong(0); private AtomicLong delOperationTime = new AtomicLong(0); private AtomicLong bindOperationCount = new AtomicLong(0); private AtomicLong bindOperationTime = new AtomicLong(0); private AtomicLong unbindOperationCount = new AtomicLong(0); private AtomicLong unbindOperationTime = new AtomicLong(0); private AtomicLong compOperationCount = new AtomicLong(0); private AtomicLong compOperationTime = new AtomicLong(0); private AtomicLong modOperationCount = new AtomicLong(0); private AtomicLong modOperationTime = new AtomicLong(0); private AtomicLong moddnOperationCount = new AtomicLong(0); private AtomicLong moddnOperationTime = new AtomicLong(0); private AtomicLong abandonOperationCount = new AtomicLong(0); private AtomicLong abandonOperationTime = new AtomicLong(0); private AtomicLong extOperationCount = new AtomicLong(0); private AtomicLong extOperationTime = new AtomicLong(0); /** * Creates a new instance of this class with the specified parent. * * @param instanceName * The name for this monitor provider instance. */ public LDAPStatistics(String instanceName) { this.instanceName = instanceName; } @Override public void initializeMonitorProvider(MonitorProviderCfg configuration) throws ConfigException { // Throw an exception, because this monitor is not intended to be // dynamically loaded from the configuration. Rather, it should be // explicitly created and registered by the LDAP connection handler // or an LDAP client connection. LocalizableMessage message = ERR_LDAP_STATS_INVALID_MONITOR_INITIALIZATION.get(configuration.dn()); throw new ConfigException(message); } /** * Retrieves the name of this monitor provider. It should be unique * among all monitor providers, including all instances of the same * monitor provider. * * @return The name of this monitor provider. */ @Override public String getMonitorInstanceName() { return instanceName; } @Override public ObjectClass getMonitorObjectClass() { return DirectoryServer.getSchema().getObjectClass(OC_MONITOR_CONNHANDLERSTATS); } @Override public MonitorData getMonitorData() { // Construct the list of attributes to return. /* TODO : the attribute names should be constant (in ServerConstants.java * and associated with their objectclass * OC_MONITOR_CONNHANDLERSTATS */ final MonitorData attrs = new MonitorData(31 + 10 * 2); attrs.add("connectionsEstablished", connectionsEstablished); attrs.add("connectionsClosed", connectionsClosed); attrs.add("bytesRead", bytesRead); attrs.add("bytesWritten", bytesWritten); attrs.add("ldapMessagesRead", messagesRead); attrs.add("ldapMessagesWritten", messagesWritten); attrs.add("operationsAbandoned", operationsAbandoned); attrs.add("operationsInitiated", operationsInitiated); attrs.add("operationsCompleted", operationsCompleted); attrs.add("abandonRequests", abandonRequests); attrs.add("addRequests", addRequests); attrs.add("addResponses", addResponses); attrs.add("bindRequests", bindRequests); attrs.add("bindResponses", bindResponses); attrs.add("compareRequests", compareRequests); attrs.add("compareResponses", compareResponses); attrs.add("deleteRequests", deleteRequests); attrs.add("deleteResponses", deleteResponses); attrs.add("extendedRequests", extendedRequests); attrs.add("extendedResponses", extendedResponses); attrs.add("modifyRequests", modifyRequests); attrs.add("modifyResponses", modifyResponses); attrs.add("modifyDNRequests", modifyDNRequests); attrs.add("modifyDNResponses", modifyDNResponses); attrs.add("searchRequests", searchRequests); attrs.add("searchOneRequests", searchOneRequests); attrs.add("searchSubRequests", searchSubRequests); attrs.add("searchResultEntries", searchResultEntries); attrs.add("searchResultReferences", searchResultReferences); attrs.add("searchResultsDone", searchResultsDone); attrs.add("unbindRequests", unbindRequests); // adds attrs.add("ds-mon-add-operations-total-count", addOperationCount); attrs.add("ds-mon-resident-time-add-operations-total-time", addOperationTime); // search attrs.add("ds-mon-search-operations-total-count", searchOperationCount); attrs.add("ds-mon-resident-time-search-operations-total-time", searchOperationTime); // bind attrs.add("ds-mon-bind-operations-total-count", bindOperationCount); attrs.add("ds-mon-resident-time-bind-operations-total-time", bindOperationTime); // unbind attrs.add("ds-mon-unbind-operations-total-count", unbindOperationCount); attrs.add("ds-mon-resident-time-unbind-operations-total-time", unbindOperationTime); // compare attrs.add("ds-mon-compare-operations-total-count", compOperationCount); attrs.add("ds-mon-resident-time-compare-operations-total-time", compOperationTime); // del attrs.add("ds-mon-delete-operations-total-count", delOperationCount); attrs.add("ds-mon-resident-time-delete-operations-total-time", delOperationTime); // mod attrs.add("ds-mon-mod-operations-total-count", modOperationCount); attrs.add("ds-mon-resident-time-mod-operations-total-time", modOperationTime); // moddn attrs.add("ds-mon-moddn-operations-total-count", moddnOperationCount); attrs.add("ds-mon-resident-time-moddn-operations-total-time", moddnOperationTime); // abandon attrs.add("ds-mon-abandon-operations-total-count", abandonOperationCount); attrs.add("ds-mon-resident-time-abandon-operations-total-time", abandonOperationTime); // extended attrs.add("ds-mon-extended-operations-total-count", extOperationCount); attrs.add("ds-mon-resident-time-extended-operations-total-time", extOperationTime); return attrs; } /** Clears any statistical information collected to this point. */ public void clearStatistics() { abandonRequests.set(0); addRequests.set(0); addResponses.set(0); bindRequests.set(0); bindResponses.set(0); bytesRead.set(0); bytesWritten.set(0); compareRequests.set(0); compareResponses.set(0); connectionsClosed.set(0); connectionsEstablished.set(0); deleteRequests.set(0); deleteResponses.set(0); extendedRequests.set(0); extendedResponses.set(0); messagesRead.set(0); messagesWritten.set(0); modifyRequests.set(0); modifyResponses.set(0); modifyDNRequests.set(0); modifyDNResponses.set(0); operationsAbandoned.set(0); operationsCompleted.set(0); operationsInitiated.set(0); searchRequests.set(0); searchOneRequests.set(0); searchSubRequests.set(0); searchResultEntries.set(0); searchResultReferences.set(0); searchResultsDone.set(0); unbindRequests.set(0); addOperationCount.set(0); addOperationTime.set(0); searchOperationCount.set(0); searchOperationTime.set(0); delOperationCount.set(0); delOperationTime.set(0); bindOperationCount.set(0); bindOperationTime.set(0); unbindOperationCount.set(0); unbindOperationTime.set(0); compOperationCount.set(0); compOperationTime.set(0); modOperationCount.set(0); modOperationTime.set(0); moddnOperationCount.set(0); moddnOperationTime.set(0); abandonOperationCount.set(0); abandonOperationTime.set(0); extOperationCount.set(0); extOperationTime.set(0); } /** * Updates the appropriate set of counters to indicate that a new * connection has been established. */ public void updateConnect() { connectionsEstablished.getAndIncrement(); } /** Updates the appropriate set of counters to indicate that a connection has been closed. */ public void updateDisconnect() { connectionsClosed.getAndIncrement(); } /** * Updates the appropriate set of counters to indicate that the * specified number of bytes have been read by the client. * * @param bytesRead * The number of bytes read by the client. */ public void updateBytesRead(int bytesRead) { this.bytesRead.getAndAdd(bytesRead); } /** * Updates the appropriate set of counters to indicate that the * specified number of bytes have been written to the client. * * @param bytesWritten * The number of bytes written to the client. */ public void updateBytesWritten(int bytesWritten) { this.bytesWritten.getAndAdd(bytesWritten); } /** * Updates the appropriate set of counters based on the provided * message that has been read from the client. * * @param message * The message that was read from the client. */ public void updateMessageRead(LDAPMessage message) { messagesRead.getAndIncrement(); operationsInitiated.getAndIncrement(); switch (message.getProtocolOp().getType()) { case OP_TYPE_ABANDON_REQUEST: abandonRequests.getAndIncrement(); break; case OP_TYPE_ADD_REQUEST: addRequests.getAndIncrement(); break; case OP_TYPE_BIND_REQUEST: bindRequests.getAndIncrement(); break; case OP_TYPE_COMPARE_REQUEST: compareRequests.getAndIncrement(); break; case OP_TYPE_DELETE_REQUEST: deleteRequests.getAndIncrement(); break; case OP_TYPE_EXTENDED_REQUEST: extendedRequests.getAndIncrement(); break; case OP_TYPE_MODIFY_REQUEST: modifyRequests.getAndIncrement(); break; case OP_TYPE_MODIFY_DN_REQUEST: modifyDNRequests.getAndIncrement(); break; case OP_TYPE_SEARCH_REQUEST: searchRequests.getAndIncrement(); SearchRequestProtocolOp s = (SearchRequestProtocolOp)message .getProtocolOp(); switch (s.getScope().asEnum()) { case BASE_OBJECT: // we don't count base object searches as // this value can be derived from the others break; case SINGLE_LEVEL: searchOneRequests.getAndIncrement(); break; case WHOLE_SUBTREE: searchSubRequests.getAndIncrement(); break; default: break; } break; case OP_TYPE_UNBIND_REQUEST: unbindRequests.getAndIncrement(); break; } } /** * Updates the appropriate set of counters based on the provided * message that has been written to the client. * * @param messageType * The message type that was written to the client. * @param messageId * The message id that was written to the client */ public void updateMessageWritten(byte messageType, int messageId) { messagesWritten.getAndIncrement(); switch (messageType) { case OP_TYPE_ADD_RESPONSE: addResponses.getAndIncrement(); operationsCompleted.getAndIncrement(); break; case OP_TYPE_BIND_RESPONSE: bindResponses.getAndIncrement(); operationsCompleted.getAndIncrement(); break; case OP_TYPE_COMPARE_RESPONSE: compareResponses.getAndIncrement(); operationsCompleted.getAndIncrement(); break; case OP_TYPE_DELETE_RESPONSE: deleteResponses.getAndIncrement(); operationsCompleted.getAndIncrement(); break; case OP_TYPE_EXTENDED_RESPONSE: extendedResponses.getAndIncrement(); // We don't want to include unsolicited notifications as // "completed" operations. if (messageId > 0) { operationsCompleted.getAndIncrement(); } break; case OP_TYPE_MODIFY_RESPONSE: modifyResponses.getAndIncrement(); operationsCompleted.getAndIncrement(); break; case OP_TYPE_MODIFY_DN_RESPONSE: modifyDNResponses.getAndIncrement(); operationsCompleted.getAndIncrement(); break; case OP_TYPE_SEARCH_RESULT_ENTRY: searchResultEntries.getAndIncrement(); break; case OP_TYPE_SEARCH_RESULT_REFERENCE: searchResultReferences.getAndIncrement(); break; case OP_TYPE_SEARCH_RESULT_DONE: searchResultsDone.getAndIncrement(); operationsCompleted.getAndIncrement(); break; } } /** * Updates the appropriate set of counters based on the provided * message that has been written to the client. * * @param message * The message that was written to the client. */ public void updateMessageWritten(LDAPMessage message) { updateMessageWritten(message.getProtocolOp().getType(), message.getMessageID()); } /** * Updates the appropriate set of counters to indicate that an * operation was abandoned without sending a response to the client. */ public void updateAbandonedOperation() { operationsAbandoned.getAndIncrement(); } /** * Retrieves the number of client connections that have been * established. * * @return The number of client connections that have been * established. */ public long getConnectionsEstablished() { return connectionsEstablished.get(); } /** * Retrieves the number of client connections that have been closed. * * @return The number of client connections that have been closed. */ public long getConnectionsClosed() { return connectionsClosed.get(); } /** * Retrieves the number of bytes that have been received from clients. * * @return The number of bytes that have been received from clients. */ public long getBytesRead() { return bytesRead.get(); } /** * Retrieves the number of bytes that have been written to clients. * * @return The number of bytes that have been written to clients. */ public long getBytesWritten() { return bytesWritten.get(); } /** * Retrieves the number of LDAP messages that have been received from * clients. * * @return The number of LDAP messages that have been received from * clients. */ public long getMessagesRead() { return messagesRead.get(); } /** * Retrieves the number of LDAP messages that have been written to * clients. * * @return The number of LDAP messages that have been written to * clients. */ public long getMessagesWritten() { return messagesWritten.get(); } /** * Retrieves the number of operations that have been initiated by * clients. * * @return The number of operations that have been initiated by * clients. */ public long getOperationsInitiated() { return operationsInitiated.get(); } /** * Retrieves the number of operations for which the server has * completed processing. * * @return The number of operations for which the server has completed * processing. */ public long getOperationsCompleted() { return operationsCompleted.get(); } /** * Retrieves the number of operations that have been abandoned by * clients. * * @return The number of operations that have been abandoned by * clients. */ public long getOperationsAbandoned() { return operationsAbandoned.get(); } /** * Retrieves the number of abandon requests that have been received. * * @return The number of abandon requests that have been received. */ public long getAbandonRequests() { return abandonRequests.get(); } /** * Retrieves the number of add requests that have been received. * * @return The number of add requests that have been received. */ public long getAddRequests() { return addRequests.get(); } /** * Retrieves the number of add responses that have been sent. * * @return The number of add responses that have been sent. */ public long getAddResponses() { return addResponses.get(); } /** * Retrieves the number of bind requests that have been received. * * @return The number of bind requests that have been received. */ public long getBindRequests() { return bindRequests.get(); } /** * Retrieves the number of bind responses that have been sent. * * @return The number of bind responses that have been sent. */ public long getBindResponses() { return bindResponses.get(); } /** * Retrieves the number of compare requests that have been received. * * @return The number of compare requests that have been received. */ public long getCompareRequests() { return compareRequests.get(); } /** * Retrieves the number of compare responses that have been sent. * * @return The number of compare responses that have been sent. */ public long getCompareResponses() { return compareResponses.get(); } /** * Retrieves the number of delete requests that have been received. * * @return The number of delete requests that have been received. */ public long getDeleteRequests() { return deleteRequests.get(); } /** * Retrieves the number of delete responses that have been sent. * * @return The number of delete responses that have been sent. */ public long getDeleteResponses() { return deleteResponses.get(); } /** * Retrieves the number of extended requests that have been received. * * @return The number of extended requests that have been received. */ public long getExtendedRequests() { return extendedRequests.get(); } /** * Retrieves the number of extended responses that have been sent. * * @return The number of extended responses that have been sent. */ public long getExtendedResponses() { return extendedResponses.get(); } /** * Retrieves the number of modify requests that have been received. * * @return The number of modify requests that have been received. */ public long getModifyRequests() { return modifyRequests.get(); } /** * Retrieves the number of modify responses that have been sent. * * @return The number of modify responses that have been sent. */ public long getModifyResponses() { return modifyResponses.get(); } /** * Retrieves the number of modify DN requests that have been received. * * @return The number of modify DN requests that have been received. */ public long getModifyDNRequests() { return modifyDNRequests.get(); } /** * Retrieves the number of modify DN responses that have been sent. * * @return The number of modify DN responses that have been sent. */ public long getModifyDNResponses() { return modifyDNResponses.get(); } /** * Retrieves the number of search requests that have been received. * * @return The number of search requests that have been received. */ public long getSearchRequests() { return searchRequests.get(); } /** * Retrieves the number of one-level search requests that have been received. * * @return The number of one-level search requests that have been received. */ public long getSearchOneRequests() { return searchOneRequests.get(); } /** * Retrieves the number of subtree search requests that have been received. * * @return The number of subtree search requests that have been received. */ public long getSearchSubRequests() { return searchSubRequests.get(); } /** * Retrieves the number of search result entries that have been sent. * * @return The number of search result entries that have been sent. */ public long getSearchResultEntries() { return searchResultEntries.get(); } /** * Retrieves the number of search result references that have been * sent. * * @return The number of search result references that have been sent. */ public long getSearchResultReferences() { return searchResultReferences.get(); } /** * Retrieves the number of search result done messages that have been * sent. * * @return The number of search result done messages that have been * sent. */ public long getSearchResultsDone() { return searchResultsDone.get(); } /** * Retrieves the number of unbind requests that have been received. * * @return The number of unbind requests that have been received. */ public long getUnbindRequests() { return unbindRequests.get(); } /** * Update the operation counters and times depending on the OperationType. * @param type of the operation. * @param time of the operation execution. */ public void updateOperationMonitoringData(OperationType type, long time) { if (type.equals(OperationType.ADD)) { addOperationCount.getAndIncrement(); addOperationTime.getAndAdd(time); } else if (type.equals(OperationType.SEARCH)) { searchOperationCount.getAndIncrement(); searchOperationTime.getAndAdd(time); } else if (type.equals(OperationType.ABANDON)) { abandonOperationCount.getAndIncrement(); abandonOperationTime.getAndAdd(time); } else if (type.equals(OperationType.BIND)) { bindOperationCount.getAndIncrement(); bindOperationTime.getAndAdd(time); } else if (type.equals(OperationType.UNBIND)) { unbindOperationCount.getAndIncrement(); unbindOperationTime.getAndAdd(time); } else if (type.equals(OperationType.COMPARE)) { compOperationCount.getAndIncrement(); compOperationTime.getAndAdd(time); } else if (type.equals(OperationType.DELETE)) { delOperationCount.getAndIncrement(); delOperationTime.getAndAdd(time); } else if (type.equals(OperationType.EXTENDED)) { extOperationCount.getAndIncrement(); extOperationTime.getAndAdd(time); } else if (type.equals(OperationType.MODIFY)) { modOperationCount.getAndIncrement(); modOperationTime.getAndAdd(time); } else if (type.equals(OperationType.MODIFY_DN)) { moddnOperationCount.getAndIncrement(); moddnOperationTime.getAndAdd(time); } } }