Skip to content

muzzle.mismatch="datadog.trace.instrumentation.springweb.DatadogByteArrayOutputStream:36 Missing class B" #7842

@lrwh

Description

@lrwh

I have created a custom class that inherits from the OutputStream class, and when the application starts and loads, a Missing class B exception occurs. I am not sure what class B is, could you help me take a look?

[dd.trace 2024-10-28 18:15:26:999 +0800] [main] DEBUG datadog.trace.agent.tooling.muzzle.MuzzleCheck - Muzzled mismatch - instrumentation.names=[spring-web] instrumentation.class=datadog.trace.instrumentation.springweb.DispatcherServletInstrumentation instrumentation.target.classloader=jdk.internal.loader.ClassLoaders$AppClassLoader@512ddf17 muzzle.mismatch="datadog.trace.instrumentation.springweb.DatadogByteArrayOutputStream:36 Missing class B"

line 36

if (this.buffers.peekLast() == null || (this.buffers.getLast()).length == this.index) {

Image

code DatadogByteArrayOutputStream

package datadog.trace.instrumentation.springweb;


import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;

public class DatadogByteArrayOutputStream extends OutputStream {
  private static final int DEFAULT_BLOCK_SIZE = 256;
  private final Deque<byte[]> buffers = new ArrayDeque();
  private final int initialBlockSize;
  private int nextBlockSize;
  private int alreadyBufferedSize;
  private int index;
  private boolean closed;

  public DatadogByteArrayOutputStream() {
    this(256);
  }

  public DatadogByteArrayOutputStream(int initialBlockSize) {
    this.nextBlockSize = 0;
    this.alreadyBufferedSize = 0;
    this.index = 0;
    this.closed = false;
    this.initialBlockSize = initialBlockSize;
    this.nextBlockSize = initialBlockSize;
  }

  public void write(int datum) throws IOException {
    if (this.closed) {
      throw new IOException("Stream closed");
    } else {
      if (this.buffers.peekLast() == null || (this.buffers.getLast()).length == this.index) {
        this.addBuffer(1);
      }

      (this.buffers.getLast())[this.index++] = (byte)datum;
    }
  }

  public void write(byte[] data, int offset, int length) throws IOException {
    if (offset >= 0 && offset + length <= data.length && length >= 0) {
      if (this.closed) {
        throw new IOException("Stream closed");
      } else {
        if (this.buffers.peekLast() == null || ((byte[])this.buffers.getLast()).length == this.index) {
          this.addBuffer(length);
        }

        if (this.index + length > ((byte[])this.buffers.getLast()).length) {
          int pos = offset;

          do {
            if (this.index == ((byte[])this.buffers.getLast()).length) {
              this.addBuffer(length);
            }

            int copyLength = ((byte[])this.buffers.getLast()).length - this.index;
            if (length < copyLength) {
              copyLength = length;
            }

            System.arraycopy(data, pos, this.buffers.getLast(), this.index, copyLength);
            pos += copyLength;
            this.index += copyLength;
            length -= copyLength;
          } while(length > 0);
        } else {
          System.arraycopy(data, offset, this.buffers.getLast(), this.index, length);
          this.index += length;
        }

      }
    } else {
      throw new IndexOutOfBoundsException();
    }
  }

  public void close() {
    this.closed = true;
  }

  public String toString() {
    return new String(this.toByteArrayUnsafe());
  }

  public int size() {
    return this.alreadyBufferedSize + this.index;
  }

  public byte[] toByteArrayUnsafe() {
    int totalSize = this.size();
    if (totalSize == 0) {
      return new byte[0];
    } else {
      this.resize(totalSize);
      return (byte[])this.buffers.getFirst();
    }
  }

  public byte[] toByteArray() {
    byte[] bytesUnsafe = this.toByteArrayUnsafe();
    return (byte[])bytesUnsafe.clone();
  }

  public void reset() {
    this.buffers.clear();
    this.nextBlockSize = this.initialBlockSize;
    this.closed = false;
    this.index = 0;
    this.alreadyBufferedSize = 0;
  }

  public void writeTo(OutputStream out) throws IOException {
    Iterator<byte[]> it = this.buffers.iterator();

    while(it.hasNext()) {
      byte[] bytes = (byte[])it.next();
      if (it.hasNext()) {
        out.write(bytes, 0, bytes.length);
      } else {
        out.write(bytes, 0, this.index);
      }
    }

  }

  public void resize(int targetCapacity) {
    if (this.buffers.peekFirst() == null) {
      this.nextBlockSize = targetCapacity - this.size();
    } else if (this.size() != targetCapacity || ((byte[])this.buffers.getFirst()).length != targetCapacity) {
      int totalSize = this.size();
      byte[] data = new byte[targetCapacity];
      int pos = 0;
      Iterator<byte[]> it = this.buffers.iterator();

      while(it.hasNext()) {
        byte[] bytes = (byte[])it.next();
        if (it.hasNext()) {
          System.arraycopy(bytes, 0, data, pos, bytes.length);
          pos += bytes.length;
        } else {
          System.arraycopy(bytes, 0, data, pos, this.index);
        }
      }

      this.buffers.clear();
      this.buffers.add(data);
      this.index = totalSize;
      this.alreadyBufferedSize = 0;
    }

  }

  private void addBuffer(int minCapacity) {
    if (this.buffers.peekLast() != null) {
      this.alreadyBufferedSize += this.index;
      this.index = 0;
    }

    if (this.nextBlockSize < minCapacity) {
      this.nextBlockSize = nextPowerOf2(minCapacity);
    }

    this.buffers.add(new byte[this.nextBlockSize]);
    this.nextBlockSize *= 2;
  }

  private static int nextPowerOf2(int val) {
    --val;
    val |= val >> 1;
    val |= val >> 2;
    val |= val >> 4;
    val |= val >> 8;
    val |= val >> 16;
    ++val;
    return val;
  }
}

DispatcherServletInstrumentation class add helperClassNames

@AutoService(InstrumenterModule.class)
public final class DispatcherServletInstrumentation extends InstrumenterModule.Tracing
    implements Instrumenter.ForSingleType {

  public DispatcherServletInstrumentation() {
    super("spring-web");
  }

  @Override
  public String instrumentedType() {
    return "org.springframework.web.servlet.DispatcherServlet";
  }

  @Override
  public String[] helperClassNames() {
    return new String[] {
      packageName + ".SpringWebHttpServerDecorator",
      packageName + ".ServletRequestURIAdapter",
      packageName + ".HandlerMappingResourceNameFilter",
      packageName + ".PathMatchingHttpServletRequestWrapper",
      packageName + ".DataDogHttpServletResponseWrapper",
      //packageName + ".DataDogHttpServletResponseWrapper$WrapperOutputStream"
      packageName + ".DataDogHttpServletResponseWrapper$CustomServletOutputStream",
      packageName+".ContentCachingResponseWrapper",
        packageName+".ContentCachingResponseWrapper$ResponseServletOutputStream",
      packageName+".ContentCachingResponseWrapper$ResponsePrintWriter",
        packageName+".DatadogByteArrayOutputStream",
    };
  }
...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions