From: Josh Date: Sun, 11 Dec 2016 08:47:46 +0000 (+0200) Subject: mdsaltrace utility for debugging X-Git-Tag: release/nitrogen~275 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=0aae219a77e306178b6ea184fa3cbd8ad98e6bce mdsaltrace utility for debugging Moved back to controller per decision from kernel meeting a few weeks ago. TracingBroker logs 'write' operations and listener registrations to the md-sal. It logs the instance identifier path, the objects themselves, as well as the stack trace of the call invoking the registration or write operation. It works by operating as a "bump on the stack" between the application and actual DataBroker, intercepting write and registration calls and writing to the log.` + karaf4 Change-Id: Ie7d27901429f6e7bcac7ff62e49e4e3115f5915f Signed-off-by: Josh Signed-off-by: Robert Varga --- diff --git a/opendaylight/md-sal/mdsal-artifacts/pom.xml b/opendaylight/md-sal/mdsal-artifacts/pom.xml index 28b641133c..00e6fecbf4 100644 --- a/opendaylight/md-sal/mdsal-artifacts/pom.xml +++ b/opendaylight/md-sal/mdsal-artifacts/pom.xml @@ -106,6 +106,21 @@ sal-schema-service ${project.version} + + ${project.groupId} + mdsal-trace-api + ${project.version} + + + ${project.groupId} + mdsal-trace-dom-impl + ${project.version} + + + ${project.groupId} + mdsal-trace-binding-impl + ${project.version} + diff --git a/opendaylight/md-sal/mdsal-trace/api/pom.xml b/opendaylight/md-sal/mdsal-trace/api/pom.xml new file mode 100644 index 0000000000..ea1f7bbf77 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/api/pom.xml @@ -0,0 +1,53 @@ + + + + 4.0.0 + + + org.opendaylight.mdsal + binding-parent + 0.11.0-SNAPSHOT + + + + org.opendaylight.controller + mdsal-trace-api + 1.6.0-SNAPSHOT + bundle + + + + + org.opendaylight.controller + mdsal-artifacts + ${project.version} + pom + import + + + + + + + org.opendaylight.controller + sal-broker-impl + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + checkstyle.violationSeverity=error + + + + + diff --git a/opendaylight/md-sal/mdsal-trace/api/src/main/java/org/opendaylight/controller/md/sal/trace/api/TracingDOMDataBroker.java b/opendaylight/md-sal/mdsal-trace/api/src/main/java/org/opendaylight/controller/md/sal/trace/api/TracingDOMDataBroker.java new file mode 100644 index 0000000000..14d30b123e --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/api/src/main/java/org/opendaylight/controller/md/sal/trace/api/TracingDOMDataBroker.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.trace.api; + +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; + +/** + * Tagging interface so that the tracing broker service can be more explicitly imported. + */ +public interface TracingDOMDataBroker extends DOMDataBroker { + +} diff --git a/opendaylight/md-sal/mdsal-trace/api/src/main/yang/mdsaltrace.yang b/opendaylight/md-sal/mdsal-trace/api/src/main/yang/mdsaltrace.yang new file mode 100644 index 0000000000..ce72da7508 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/api/src/main/yang/mdsaltrace.yang @@ -0,0 +1,28 @@ +module mdsaltrace { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:mdsaltrace"; + prefix "mdsaltrace"; + + organization + "Red Hat, Inc."; + + description + "Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License v1.0 which accompanies this distribution, + and is available at http://www.eclipse.org/legal/epl-v10.html"; + + revision "2016-09-08" { + description "Initial revision of mdsaltrace model"; + } + + container config { + leaf-list registration-watches { + type string; + } + leaf-list write-watches { + type string; + } + } +} diff --git a/opendaylight/md-sal/mdsal-trace/binding-impl/pom.xml b/opendaylight/md-sal/mdsal-trace/binding-impl/pom.xml new file mode 100644 index 0000000000..5e14745ad8 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/binding-impl/pom.xml @@ -0,0 +1,88 @@ + + + + + 4.0.0 + + + org.opendaylight.controller + config-parent + 0.7.0-SNAPSHOT + + + + org.opendaylight.controller + mdsal-trace-binding-impl + 1.6.0-SNAPSHOT + bundle + + + + + org.opendaylight.controller + mdsal-artifacts + ${project.version} + pom + import + + + + + + + ${project.groupId} + mdsal-trace-api + + + ${project.groupId} + mdsal-trace-dom-impl + + + + + junit + junit + test + + + + org.mockito + mockito-core + test + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + org.opendaylight.controller.md.sal.trace.api,org.opendaylight.mdsal.binding.generator.api, + org.opendaylight.controller.md.sal.trace.dom.impl,org.opendaylight.controller.md.sal.dom.api, + org.opendaylight.controller.md.sal.binding.api, + org.opendaylight.controller.md.sal.dom.broker.impl,org.opendaylight.controller.md.sal.binding.impl, + org.opendaylight.controller.sal.core.api.model,* + + true + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + checkstyle.violationSeverity=error + + + + + diff --git a/opendaylight/md-sal/mdsal-trace/binding-impl/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml b/opendaylight/md-sal/mdsal-trace/binding-impl/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml new file mode 100644 index 0000000000..dc79224004 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/binding-impl/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opendaylight/md-sal/mdsal-trace/deploy-site.xml b/opendaylight/md-sal/mdsal-trace/deploy-site.xml new file mode 100644 index 0000000000..6a7256400a --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/deploy-site.xml @@ -0,0 +1,50 @@ + + + + + 4.0.0 + + org.opendaylight.mdsal + deploy-site + 0.1.0-SNAPSHOT + pom + + + latest + dav:https://nexus.opendaylight.org/content/sites/site/${project.groupId}/${stream}/ + + + + + + org.apache.maven.wagon + wagon-webdav-jackrabbit + 2.9 + + + + + + org.apache.maven.plugins + maven-site-plugin + 3.4 + + ${project.build.directory}/staged-site + + + + + + + + opendaylight-site + ${nexus.site.url} + + + diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/pom.xml b/opendaylight/md-sal/mdsal-trace/dom-impl/pom.xml new file mode 100644 index 0000000000..d0f7dd5762 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/pom.xml @@ -0,0 +1,96 @@ + + + + + 4.0.0 + + + org.opendaylight.controller + config-parent + 0.7.0-SNAPSHOT + + + + org.opendaylight.controller + mdsal-trace-dom-impl + 1.6.0-SNAPSHOT + bundle + + + + + org.opendaylight.controller + mdsal-artifacts + ${project.version} + pom + import + + + + + + + ${project.groupId} + mdsal-trace-api + + + ${project.groupId} + sal-binding-api + + + ${project.groupId} + sal-core-api + + + ${project.groupId} + sal-broker-impl + + + + + junit + junit + test + + + + org.mockito + mockito-core + test + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + + org.opendaylight.controller.md.sal.binding.api, + org.opendaylight.controller.md.sal.dom.broker.impl,org.opendaylight.controller.md.sal.binding.impl, + org.opendaylight.controller.sal.core.api.model,* + + org.opendaylight.controller.md.sal.trace.dom.impl + true + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + checkstyle.violationSeverity=error + + + + + diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingBroker.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingBroker.java new file mode 100644 index 0000000000..c971ec300d --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingBroker.java @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.trace.dom.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import javax.annotation.Nonnull; + +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; +import org.opendaylight.controller.md.sal.trace.api.TracingDOMDataBroker; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsaltrace.rev160908.Config; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@SuppressWarnings("checkstyle:JavadocStyle") +//...because otherwise it whines about the elements in the @code block even though it's completely valid Javadoc + +/** + * TracingBroker logs "write" operations and listener registrations to the md-sal. It logs the instance identifier path, + * the objects themselves, as well as the stack trace of the call invoking the registration or write operation. + * It works by operating as a "bump on the stack" between the application and actual DataBroker, intercepting write + * and registration calls and writing to the log. + *

Wiring:

+ * TracingBroker is designed to be easy to use. In fact, for bundles using Blueprint to inject their DataBroker + * TracingBroker can be used without modifying your code at all in two simple steps: + *
    + *
  1. + * Simply add the dependency "mdsaltrace-features" to + * your karaf pom: + *
    + * {@code
    + *  
    + *    org.opendaylight.controller
    + *    mdsal-trace-features
    + *    features
    + *    xml
    + *    runtime
    + *    0.1.5-SNAPSHOT
    + *  
    + * }
    + * 
    + *
  2. + *
  3. + * Then just load the odl-mdsal-trace feature before your feature and you're done. + *
  4. + *
+ * This works because the mdsaltrace-impl bundle registers its service implementing DOMDataBroker with a higher + * rank than sal-binding-broker. As such, any OSGi service lookup for DataBroker will receive the TracingBroker. + *

+ *

Avoiding log bloat:

+ * TracingBroker can be configured to only print registrations or write ops pertaining to certain subtrees of the + * md-sal. This can be done in the code via the methods of this class or via a config file. TracingBroker uses a more + * convenient but non-standard representation of the instance identifiers. Each instance identifier segment's + * class.getSimpleName() is used separated by a '/'. + *

+ *

Known issues

+ *
    + *
  • + * Filtering by paths. For some registrations the codec that converts back from the DOM to binding paths is + * busted. As such, an aproximated path is used in the output. For now it is recommended not to use + * watchRegistrations and allow all registrations to be logged. + *
  • + *
+ * + */ +public class TracingBroker implements TracingDOMDataBroker { + + static final Logger LOG = LoggerFactory.getLogger(TracingBroker.class); + + private static final int STACK_TRACE_FIRST_RELEVANT_FRAME = 2; + + private final BindingNormalizedNodeSerializer codec; + private final DOMDataBroker delegate; + private List registrationWatches = new ArrayList<>(); + private List writeWatches = new ArrayList<>(); + + + private class Watch { + final String iidString; + final LogicalDatastoreType store; + + Watch(String iidString, LogicalDatastoreType storeOrNull) { + this.store = storeOrNull; + this.iidString = iidString; + } + + private String toIidCompString(YangInstanceIdentifier iid) { + StringBuilder builder = new StringBuilder(); + toPathString(iid, builder); + builder.append('/'); + return builder.toString(); + } + + private boolean isParent(String parent, String child) { + return child.startsWith(parent); + } + + public boolean subtreesOverlap(YangInstanceIdentifier iid, LogicalDatastoreType store, + AsyncDataBroker.DataChangeScope scope) { + if (this.store != null && !this.store.equals(store)) { + return false; + } + + String otherIidString = toIidCompString(iid); + + switch (scope) { + case BASE: + return isParent(iidString, otherIidString); + case ONE: //for now just treat like SUBTREE, even though it's not + case SUBTREE: + return isParent(iidString, otherIidString) || isParent(otherIidString, iidString); + default: + return false; + } + } + + public boolean eventIsOfInterest(YangInstanceIdentifier iid, LogicalDatastoreType store) { + if (this.store != null && !this.store.equals(store)) { + return false; + } + + return isParent(iidString, toPathString(iid)); + } + } + + public TracingBroker(DOMDataBroker delegate, Config config, BindingNormalizedNodeSerializer codec) { + this.delegate = Objects.requireNonNull(delegate); + this.codec = Objects.requireNonNull(codec); + configure(config); + } + + private void configure(Config config) { + registrationWatches.clear(); + List paths = config.getRegistrationWatches(); + if (paths != null) { + for (String path : paths) { + watchRegistrations(path, null); + } + } + + writeWatches.clear(); + paths = config.getWriteWatches(); + if (paths != null) { + for (String path : paths) { + watchWrites(path, null); + } + } + } + + /** + * Log registrations to this subtree of the md-sal. + * @param iidString the iid path of the root of the subtree + * @param store Which LogicalDataStore? or null for both + */ + public void watchRegistrations(String iidString, LogicalDatastoreType store) { + registrationWatches.add(new Watch(iidString, store)); + } + + /** + * Log writes to this subtree of the md-sal. + * @param iidString the iid path of the root of the subtree + * @param store Which LogicalDataStore? or null for both + */ + public void watchWrites(String iidString, LogicalDatastoreType store) { + Watch watch = new Watch(iidString, store); + writeWatches.add(watch); + } + + private boolean isRegistrationWatched(YangInstanceIdentifier iid, + LogicalDatastoreType store, DataChangeScope scope) { + if (registrationWatches.isEmpty()) { + return true; + } + + for (Watch regInterest : registrationWatches) { + if (regInterest.subtreesOverlap(iid, store, scope)) { + return true; + } + } + + return false; + } + + boolean isWriteWatched(YangInstanceIdentifier iid, LogicalDatastoreType store) { + if (writeWatches.isEmpty()) { + return true; + } + + for (Watch watch : writeWatches) { + if (watch.eventIsOfInterest(iid, store)) { + return true; + } + } + + return false; + } + + static void toPathString(InstanceIdentifier iid, StringBuilder builder) { + for (InstanceIdentifier.PathArgument pathArg : iid.getPathArguments()) { + builder.append('/').append(pathArg.getType().getSimpleName()); + } + } + + String toPathString(YangInstanceIdentifier yiid) { + StringBuilder sb = new StringBuilder(); + toPathString(yiid, sb); + return sb.toString(); + } + + + void toPathString(YangInstanceIdentifier yiid, StringBuilder sb) { + InstanceIdentifier iid = codec.fromYangInstanceIdentifier(yiid); + if (null == iid) { + reconstructIidPathString(yiid, sb); + } else { + toPathString(iid, sb); + } + } + + private void reconstructIidPathString(YangInstanceIdentifier yiid, StringBuilder sb) { + sb.append("RECONSTRUCTED: "); + for (YangInstanceIdentifier.PathArgument pathArg : yiid.getPathArguments()) { + if (pathArg instanceof YangInstanceIdentifier.AugmentationIdentifier) { + sb.append('/').append("AUGMENTATION"); + continue; + } + sb.append('/').append(pathArg.getNodeType().getLocalName()); + } + sb.append(" ->->-> [[[ ").append(yiid.toString()).append(" ]]]"); + } + + String getStackSummary() { + StackTraceElement[] stack = Thread.currentThread().getStackTrace(); + + StringBuilder sb = new StringBuilder(); + for (int i = STACK_TRACE_FIRST_RELEVANT_FRAME; i < stack.length; i++) { + StackTraceElement frame = stack[i]; + sb.append("\n\t(TracingBroker)\t").append(frame.getClassName()).append('.').append(frame.getMethodName()); + } + + return sb.toString(); + } + + @Override + public DOMDataReadWriteTransaction newReadWriteTransaction() { + return new TracingReadWriteTransaction(delegate.newReadWriteTransaction(), this); + } + + @Override + public DOMDataWriteTransaction newWriteOnlyTransaction() { + return new TracingWriteTransaction(delegate.newWriteOnlyTransaction(), this); + } + + @Override + public ListenerRegistration registerDataChangeListener( + LogicalDatastoreType store, YangInstanceIdentifier yiid, + DOMDataChangeListener listener, DataChangeScope scope) { + if (isRegistrationWatched(yiid, store, scope)) { + LOG.warn("Registration (registerDataChangeListener) for {} from {}", + toPathString(yiid), getStackSummary()); + } + return delegate.registerDataChangeListener(store, yiid, listener, scope); + } + + @Override + public DOMTransactionChain createTransactionChain(TransactionChainListener transactionChainListener) { + return delegate.createTransactionChain(transactionChainListener); + } + + @Override + public DOMDataReadOnlyTransaction newReadOnlyTransaction() { + return delegate.newReadOnlyTransaction(); + } + + @Nonnull + @Override + public Map, DOMDataBrokerExtension> getSupportedExtensions() { + Map, DOMDataBrokerExtension> res = delegate.getSupportedExtensions(); + DOMDataTreeChangeService treeChangeSvc = (DOMDataTreeChangeService) res.get(DOMDataTreeChangeService.class); + if (treeChangeSvc == null) { + return res; + } + + res = new HashMap<>(res); + + res.put(DOMDataTreeChangeService.class, new DOMDataTreeChangeService() { + @Nonnull + @Override + public ListenerRegistration registerDataTreeChangeListener( + @Nonnull DOMDataTreeIdentifier domDataTreeIdentifier, @Nonnull L listener) { + if (isRegistrationWatched(domDataTreeIdentifier.getRootIdentifier(), + domDataTreeIdentifier.getDatastoreType(), DataChangeScope.SUBTREE)) { + LOG.warn("Registration (registerDataTreeChangeListener) for {} from {}", + toPathString(domDataTreeIdentifier.getRootIdentifier()), getStackSummary()); + } + return treeChangeSvc.registerDataTreeChangeListener(domDataTreeIdentifier, listener); + } + }); + + return res; + } +} diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadWriteTransaction.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadWriteTransaction.java new file mode 100644 index 0000000000..c906ef933b --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadWriteTransaction.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.trace.dom.impl; + + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import java.util.Objects; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + + +class TracingReadWriteTransaction extends TracingWriteTransaction implements DOMDataReadWriteTransaction { + + private final DOMDataReadWriteTransaction delegate; + + TracingReadWriteTransaction(DOMDataReadWriteTransaction delegate, TracingBroker tracingBroker) { + super(delegate, tracingBroker); + this.delegate = Objects.requireNonNull(delegate); + } + + @Override + public CheckedFuture>, ReadFailedException> read( + LogicalDatastoreType store, YangInstanceIdentifier yiid) { + return delegate.read(store, yiid); + } + + @Override + public CheckedFuture exists(LogicalDatastoreType store, YangInstanceIdentifier yiid) { + return delegate.exists(store, yiid); + } +} diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingWriteTransaction.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingWriteTransaction.java new file mode 100644 index 0000000000..a895e983c2 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingWriteTransaction.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.trace.dom.impl; + +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.ListenableFuture; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +class TracingWriteTransaction implements DOMDataWriteTransaction { + + private final DOMDataWriteTransaction delegate; + private final TracingBroker tracingBroker; + private final List logs = new ArrayList<>(); + + TracingWriteTransaction(DOMDataWriteTransaction delegate, TracingBroker tracingBroker) { + this.delegate = Objects.requireNonNull(delegate); + this.tracingBroker = Objects.requireNonNull(tracingBroker); + } + + private void recordOp(LogicalDatastoreType store, YangInstanceIdentifier yiid, + String method, NormalizedNode node) { + if (!tracingBroker.isWriteWatched(yiid, store)) { + return; + } + + Object value = null; + if (node != null) { + value = node.getValue(); + } + + if (value != null && value instanceof ImmutableSet && ((Set)value).isEmpty()) { + if (tracingBroker.LOG.isDebugEnabled()) { + tracingBroker.LOG.debug("Empty data set write to {}", tracingBroker.toPathString(yiid)); + } + } else { + StringBuilder sb = new StringBuilder(); + sb.append("Method \"").append(method); + sb.append("\" to ").append(store); + sb.append(" at ").append(tracingBroker.toPathString(yiid)).append('.'); + sb.append(" Data: "); + if (node != null) { + sb.append(node.getValue()); + } else { + sb.append("null"); + } + sb.append(" Stack:").append(tracingBroker.getStackSummary()); + synchronized (this) { + logs.add(sb.toString()); + } + } + } + + private synchronized void logOps() { + for (String log : logs) { + tracingBroker.LOG.warn(log); + } + logs.clear(); + } + + @Override + public void put(LogicalDatastoreType store, YangInstanceIdentifier yiid, NormalizedNode node) { + recordOp(store, yiid, "put", node); + delegate.put(store, yiid, node); + } + + @Override + public void merge(LogicalDatastoreType store, YangInstanceIdentifier yiid, NormalizedNode node) { + recordOp(store, yiid, "merge", node); + delegate.merge(store, yiid, node); + } + + @Override + public boolean cancel() { + logs.clear(); + return delegate.cancel(); + } + + @Override + public void delete(LogicalDatastoreType store, YangInstanceIdentifier yiid) { + recordOp(store, yiid, "delete", null); + delegate.delete(store, yiid); + } + + @Override + public CheckedFuture submit() { + logOps(); + return delegate.submit(); + } + + @Override + public ListenableFuture> commit() { + logOps(); + return delegate.commit(); + } + + @Override + public Object getIdentifier() { + return delegate.getIdentifier(); + } +} diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml new file mode 100644 index 0000000000..7535f95d4d --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + org.opendaylight.controller.md.sal.dom.api.DOMDataBroker + org.opendaylight.controller.md.sal.trace.api.TracingDOMDataBroker + + + + + + + + + + diff --git a/opendaylight/md-sal/mdsal-trace/features/features-mdsal-trace/pom.xml b/opendaylight/md-sal/mdsal-trace/features/features-mdsal-trace/pom.xml new file mode 100644 index 0000000000..d6751a9a0f --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/features/features-mdsal-trace/pom.xml @@ -0,0 +1,64 @@ + + + + 4.0.0 + + + org.opendaylight.odlparent + features-parent + 1.9.0-SNAPSHOT + + + + org.opendaylight.controller + mdsal-trace-features + 1.6.0-SNAPSHOT + ${project.artifactId} + + + + + + org.opendaylight.mdsal + mdsal-artifacts + 2.3.0-SNAPSHOT + pom + import + + + org.opendaylight.controller + mdsal-artifacts + ${project.version} + pom + import + + + + + + + org.opendaylight.controller + features-mdsal + features + xml + + + ${project.groupId} + mdsal-trace-dom-impl + + + ${project.groupId} + mdsal-trace-binding-impl + + + ${project.groupId} + mdsal-trace-api + + + diff --git a/opendaylight/md-sal/mdsal-trace/features/features-mdsal-trace/src/main/features/features.xml b/opendaylight/md-sal/mdsal-trace/features/features-mdsal-trace/src/main/features/features.xml new file mode 100644 index 0000000000..ac91121309 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/features/features-mdsal-trace/src/main/features/features.xml @@ -0,0 +1,23 @@ + + + + + mvn:org.opendaylight.controller/features-mdsal/{{VERSION}}/xml/features + mvn:org.opendaylight.yangtools/features-yangtools/{{VERSION}}/xml/features + + + odl-mdsal-broker + odl-mdsal-broker-local + mvn:org.opendaylight.controller/mdsal-trace-api/{{VERSION}} + mvn:org.opendaylight.controller/mdsal-trace-dom-impl/{{VERSION}} + mvn:org.opendaylight.controller/mdsal-trace-binding-impl/{{VERSION}} + + diff --git a/opendaylight/md-sal/mdsal-trace/features/features4-mdsal-trace/pom.xml b/opendaylight/md-sal/mdsal-trace/features/features4-mdsal-trace/pom.xml new file mode 100644 index 0000000000..8fc80b492a --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/features/features4-mdsal-trace/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + + org.opendaylight.odlparent + feature-repo-parent + 1.9.0-SNAPSHOT + + + + org.opendaylight.controller + features4-mdsal-trace + 1.6.0-SNAPSHOT + OpenDaylight :: TracingBroker + feature + + + org.opendaylight.controller + odl-mdsal-trace + ${project.version} + xml + features + + + diff --git a/opendaylight/md-sal/mdsal-trace/features/odl-mdsal-trace/pom.xml b/opendaylight/md-sal/mdsal-trace/features/odl-mdsal-trace/pom.xml new file mode 100644 index 0000000000..27d9c6deaa --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/features/odl-mdsal-trace/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + + org.opendaylight.odlparent + single-feature-parent + 1.9.0-SNAPSHOT + + + + org.opendaylight.controller + odl-mdsal-trace + 1.6.0-SNAPSHOT + OpenDaylight :: TracingBroker + feature + + + + + org.opendaylight.controller + mdsal-artifacts + ${project.version} + pom + import + + + + + + + + org.opendaylight.controller + odl-mdsal-broker + ${project.version} + xml + features + + + org.opendaylight.controller + odl-mdsal-broker-local + ${project.version} + xml + features + + + org.opendaylight.controller + mdsal-trace-api + ${project.version} + + + org.opendaylight.controller + mdsal-trace-dom-impl + ${project.version} + + + org.opendaylight.controller + mdsal-trace-binding-impl + ${project.version} + + + diff --git a/opendaylight/md-sal/mdsal-trace/features/pom.xml b/opendaylight/md-sal/mdsal-trace/features/pom.xml new file mode 100644 index 0000000000..72ac610799 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/features/pom.xml @@ -0,0 +1,29 @@ + + + + 4.0.0 + + + org.opendaylight.odlparent + odlparent-lite + 1.9.0-SNAPSHOT + + + + org.opendaylight.controller + mdsal-trace-feature-aggregator + 1.6.0-SNAPSHOT + pom + + + features-mdsal-trace + odl-mdsal-trace + features4-mdsal-trace + + diff --git a/opendaylight/md-sal/mdsal-trace/pom.xml b/opendaylight/md-sal/mdsal-trace/pom.xml new file mode 100644 index 0000000000..215cdc82fa --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/pom.xml @@ -0,0 +1,107 @@ + + + + 4.0.0 + + + org.opendaylight.odlparent + odlparent-lite + 1.9.0-SNAPSHOT + + + + org.opendaylight.controller + mdsal-trace-aggregator + 1.6.0-SNAPSHOT + mdsaltrace + pom + + + api + dom-impl + binding-impl + features + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + + + + + + maven-site + + + ${user.dir}/deploy-site.xml + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + false + + + aggregate + + aggregate + + package + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + checkstyle.violationSeverity=error + + + + + + + + + ${odl.site.url}/${project.groupId}/${stream}/ + + + + opendaylight-site + ${nexus.site.url}/ + + + diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index 7734ded2ff..1c4ad1c5f2 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -89,6 +89,9 @@ mdsal-it-base mdsal-it-parent + + mdsal-trace +