folly::Optional MessagePrinter::filterAndBuildOutput()

in mcrouter/tools/mcpiper/MessagePrinter-inl.h [138:332]


folly::Optional<StyledString> MessagePrinter::filterAndBuildOutput(
    uint64_t msgId,
    const Message& message,
    const std::string& key,
    carbon::Result result,
    const folly::SocketAddress& from,
    const folly::SocketAddress& to,
    mc_protocol_t protocol,
    int64_t latencyUs,
    const ServerLoad& serverLoad) {
  ++stats_.totalMessages;

  if (!matchAddress(from, to)) {
    return folly::none;
  }
  if (filter_.protocol.hasValue() && filter_.protocol.value() != protocol) {
    return folly::none;
  }

  auto value = carbon::valueRangeSlow(const_cast<Message&>(message));
  if (value.size() < filter_.valueMinSize ||
      value.size() > filter_.valueMaxSize) {
    return folly::none;
  }

  // if latency is 0 and the filter is not set, we let it pass through
  if (latencyUs < filter_.minLatencyUs) {
    return folly::none;
  }

  StyledString out;
  out.append("\n");

  if (options_.script) {
    out.append("{\n", format_.dataOpColor);
    /* always present, makes comma accounting simpler */
    out.append(folly::sformat("  \"reqid\": {}", msgId));
  }

  if (options_.printTimeFn) {
    timeval ts;
    gettimeofday(&ts, nullptr);

    if (options_.script) {
      out.append(
          folly::sformat(",\n  \"ts\": \"{}\"", options_.printTimeFn(ts)));
    } else {
      out.append(options_.printTimeFn(ts));
      out.append(" ");
    }
  }

  out.append(serializeConnectionDetails(from, to, protocol));

  if (!options_.script) {
    out.append("\n{\n", format_.dataOpColor);
  }

  auto msgHeader =
      serializeMessageHeader(detail::getName<Message>(), result, key);
  if (!msgHeader.empty()) {
    if (options_.script) {
      out.append(",\n  ");
    } else {
      out.append("  ");
    }
    out.append(std::move(msgHeader), format_.headerColor);
  }

  // Msg attributes
  if (!options_.script) {
    /* Rendered above for script mode */
    out.append("\n  reqid: ", format_.msgAttrColor);
    out.append(folly::sformat("0x{:x}", msgId), format_.dataValueColor);
  }

  if (latencyUs > 0) { // it is 0 only for requests
    if (options_.script) {
      out.append(",\n  \"rtt_us\": ");
    } else {
      out.append("\n  request/response latency (us): ", format_.msgAttrColor);
    }
    out.append(folly::to<std::string>(latencyUs), format_.dataValueColor);
  }

  if (!serverLoad.isZero()) {
    if (options_.script) {
      out.append(",\n  \"server_load_percent\": ");
    } else {
      out.append("\n  server load: ", format_.msgAttrColor);
    }
    out.append(
        folly::sformat("{:.2f}%", serverLoad.percentLoad()),
        format_.dataValueColor);
  }

  if (options_.script) {
    out.append(",\n  \"flags\": ");
    out.append(folly::to<std::string>(getFlagsIfExist(message)));
  } else {
    out.append("\n  flags: ", format_.msgAttrColor);
    out.append(
        folly::sformat("0x{:x}", getFlagsIfExist(message)),
        format_.dataValueColor);
  }
  if (!options_.script && getFlagsIfExist(message)) {
    auto flagDesc = describeFlags(getFlagsIfExist(message));
    if (!flagDesc.empty()) {
      out.pushAppendColor(format_.attrColor);
      out.append(" [");
      bool first = true;
      for (auto& s : flagDesc) {
        if (!first) {
          out.append(", ");
        }
        first = false;
        out.append(s);
      }
      out.pushBack(']');
      out.popAppendColor();
    }
  }
  auto typeSpecificAttr = getTypeSpecificAttributes(message);
  if (options_.script && !typeSpecificAttr.empty()) {
    out.pushBack(',');
  }
  out.append(typeSpecificAttr);

  if (!value.empty()) {
    size_t uncompressedSize;
    auto formattedValue = valueFormatter_->uncompressAndFormat(
        value,
        getFlagsIfExist(message),
        format_,
        options_.script,
        uncompressedSize);

    if (options_.script) {
      out.append(folly::sformat(",\n  \"value_wire_bytes\": {}", value.size()));
      out.append(folly::sformat(
          ",\n  \"value_uncompressed_bytes\": {}", uncompressedSize));
    } else {
      out.append("\n  value size: ", format_.msgAttrColor);
      if (uncompressedSize != value.size()) {
        out.append(
            folly::sformat(
                "{} uncompressed, {} compressed, {:.2f}% savings",
                uncompressedSize,
                value.size(),
                100.0 - 100.0 * value.size() / uncompressedSize),
            format_.dataValueColor);
      } else {
        out.append(
            folly::to<std::string>(value.size()), format_.dataValueColor);
      }
    }

    if (!options_.quiet) {
      if (options_.script) {
        out.append(",\n  \"value\": ");
      } else {
        out.append("\n  value: ", format_.msgAttrColor);
      }
      out.append(formattedValue);
    }
  }

  if (options_.script) {
    out.append("\n},\n");
  } else {
    out.append("\n}\n", format_.dataOpColor);
  }

  // Match pattern
  if (filter_.pattern) {
    auto matches = matchAll(out.text(), *filter_.pattern);
    auto success = matches.empty() == filter_.invertMatch;

    if (!success && afterMatchCount_ == 0) {
      return folly::none;
    }
    if (!filter_.invertMatch) {
      for (auto& m : matches) {
        out.setFg(m.first, m.second, format_.matchColor);
      }
    }

    // Reset after match
    if (success && options_.numAfterMatch > 0) {
      afterMatchCount_ = options_.numAfterMatch + 1;
    }
  }

  return out;
}