aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--WORKSPACE26
-rw-r--r--tools/grpcz/BUILD73
-rw-r--r--tools/grpcz/any.proto139
-rw-r--r--tools/grpcz/census.proto318
-rw-r--r--tools/grpcz/empty.proto52
-rw-r--r--tools/grpcz/grpcz_client.cc174
-rw-r--r--tools/grpcz/monitoring.proto131
-rwxr-xr-xtools/run_tests/sanity/check_submodules.sh2
8 files changed, 910 insertions, 5 deletions
diff --git a/WORKSPACE b/WORKSPACE
index 4f90f06d88..5d163f78e8 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -33,26 +33,44 @@ bind(
actual = "@submodule_gtest//:gtest",
)
+bind(
+ name = "gflags",
+ actual = "@com_github_gflags_gflags//:gflags",
+)
+
new_local_repository(
name = "submodule_boringssl",
- path = "third_party/boringssl-with-bazel",
build_file = "third_party/boringssl-with-bazel/BUILD",
+ path = "third_party/boringssl-with-bazel",
)
new_local_repository(
name = "submodule_zlib",
- path = "third_party/zlib",
build_file = "third_party/zlib.BUILD",
+ path = "third_party/zlib",
)
new_local_repository(
name = "submodule_protobuf",
- path = "third_party/protobuf",
build_file = "third_party/protobuf/BUILD",
+ path = "third_party/protobuf",
)
new_local_repository(
name = "submodule_gtest",
- path = "third_party/googletest",
build_file = "third_party/gtest.BUILD",
+ path = "third_party/googletest",
+)
+
+local_repository(
+ name = "com_github_gflags_gflags",
+ path = "third_party/gflags",
+)
+# used for tools/grpcz/grpcz_client
+git_repository(
+ name = "mongoose_repo",
+ commit = "21b9ddd490783e3afaa0fa9b45d6c1133eb922dc",
+ remote = "https://github.com/makdharma/mongoose.git"
)
+
+
diff --git a/tools/grpcz/BUILD b/tools/grpcz/BUILD
new file mode 100644
index 0000000000..34bd072d00
--- /dev/null
+++ b/tools/grpcz/BUILD
@@ -0,0 +1,73 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+package(default_visibility = ["//visibility:public"])
+
+load("//:bazel/generate_cc.bzl", "generate_cc")
+
+proto_library (
+ name = "monitoring_proto_local_copy",
+ srcs = [
+ # TODO (erikgribkoff) : remove the local copies of these protos
+ "monitoring.proto",
+ "empty.proto",
+ "any.proto",
+ "census.proto",
+ ],
+)
+
+generate_cc(
+ name = "monitoring_codegen",
+ srcs = [":monitoring_proto_local_copy"],
+)
+
+generate_cc(
+ name = "monitoring_grpc_codegen",
+ srcs = [":monitoring_proto_local_copy"],
+ plugin = "//:grpc_cpp_plugin",
+)
+
+cc_library(
+ name = "proto_lib",
+ srcs = [":monitoring_codegen", ":monitoring_grpc_codegen"],
+ hdrs = [":monitoring_codegen", ":monitoring_grpc_codegen"],
+ deps = ["//:grpc++", "//:grpc++_codegen_proto", "//external:protobuf"],
+)
+
+cc_binary(
+ name = "grpcz_client",
+ srcs = ["grpcz_client.cc",],
+ deps = [
+ "proto_lib",
+ "//external:gflags",
+ "@mongoose_repo//:mongoose_lib",
+ ],
+)
diff --git a/tools/grpcz/any.proto b/tools/grpcz/any.proto
new file mode 100644
index 0000000000..a224a2b596
--- /dev/null
+++ b/tools/grpcz/any.proto
@@ -0,0 +1,139 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+//package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "github.com/golang/protobuf/ptypes/any";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "AnyProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// `Any` contains an arbitrary serialized protocol buffer message along with a
+// URL that describes the type of the serialized message.
+//
+// Protobuf library provides support to pack/unpack Any values in the form
+// of utility functions or additional generated methods of the Any type.
+//
+// Example 1: Pack and unpack a message in C++.
+//
+// Foo foo = ...;
+// Any any;
+// any.PackFrom(foo);
+// ...
+// if (any.UnpackTo(&foo)) {
+// ...
+// }
+//
+// Example 2: Pack and unpack a message in Java.
+//
+// Foo foo = ...;
+// Any any = Any.pack(foo);
+// ...
+// if (any.is(Foo.class)) {
+// foo = any.unpack(Foo.class);
+// }
+//
+// Example 3: Pack and unpack a message in Python.
+//
+// foo = Foo(...)
+// any = Any()
+// any.Pack(foo)
+// ...
+// if any.Is(Foo.DESCRIPTOR):
+// any.Unpack(foo)
+// ...
+//
+// The pack methods provided by protobuf library will by default use
+// 'type.googleapis.com/full.type.name' as the type URL and the unpack
+// methods only use the fully qualified type name after the last '/'
+// in the type URL, for example "foo.bar.com/x/y.z" will yield type
+// name "y.z".
+//
+//
+// JSON
+// ====
+// The JSON representation of an `Any` value uses the regular
+// representation of the deserialized, embedded message, with an
+// additional field `@type` which contains the type URL. Example:
+//
+// package google.profile;
+// message Person {
+// string first_name = 1;
+// string last_name = 2;
+// }
+//
+// {
+// "@type": "type.googleapis.com/google.profile.Person",
+// "firstName": <string>,
+// "lastName": <string>
+// }
+//
+// If the embedded message type is well-known and has a custom JSON
+// representation, that representation will be embedded adding a field
+// `value` which holds the custom JSON in addition to the `@type`
+// field. Example (for message [google.protobuf.Duration][]):
+//
+// {
+// "@type": "type.googleapis.com/google.protobuf.Duration",
+// "value": "1.212s"
+// }
+//
+message Any {
+ // A URL/resource name whose content describes the type of the
+ // serialized protocol buffer message.
+ //
+ // For URLs which use the scheme `http`, `https`, or no scheme, the
+ // following restrictions and interpretations apply:
+ //
+ // * If no scheme is provided, `https` is assumed.
+ // * The last segment of the URL's path must represent the fully
+ // qualified name of the type (as in `path/google.protobuf.Duration`).
+ // The name should be in a canonical form (e.g., leading "." is
+ // not accepted).
+ // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
+ // value in binary format, or produce an error.
+ // * Applications are allowed to cache lookup results based on the
+ // URL, or have them precompiled into a binary to avoid any
+ // lookup. Therefore, binary compatibility needs to be preserved
+ // on changes to types. (Use versioned type names to manage
+ // breaking changes.)
+ //
+ // Schemes other than `http`, `https` (or the empty scheme) might be
+ // used with implementation specific semantics.
+ //
+ string type_url = 1;
+
+ // Must be a valid serialized protocol buffer of the above specified type.
+ bytes value = 2;
+}
diff --git a/tools/grpcz/census.proto b/tools/grpcz/census.proto
new file mode 100644
index 0000000000..d1ff69400b
--- /dev/null
+++ b/tools/grpcz/census.proto
@@ -0,0 +1,318 @@
+// Copyright 2017, Google Inc.
+// 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.
+
+//TODO(ericgribkoff) Depend on this directly from the instrumentation-proto
+//repository.
+
+syntax = "proto3";
+
+package google.instrumentation;
+
+option java_package = "com.google.instrumentation.stats.proto";
+option java_outer_classname = "CensusProto";
+
+// All the census protos.
+//
+// Nomenclature notes:
+// * Capitalized names below (like View) are protos.
+// * Protos which describe types are named with a Descriptor suffix (e.g.
+// MesurementDescriptor).
+//
+// Census lets you define the type and description of the data being measured
+// (e.g. the latency of an RPC or the number of CPU cycles spent on an
+// operation using MeasurementDescriptor. As individual measurements (a double
+// value) for are recorded, they are aggregated together into an
+// Aggregation. There are two Aggregation types available: Distribution
+// (describes the distribution of all measurements, possibly with a histogram)
+// and IntervalStats (the count and mean of measurements across specified time
+// periods). An Aggregation is described by an AggregationDescriptor.
+//
+// You can define how your measurements (described by a MeasurementDescriptor)
+// are broken down by Tag values and which Aggregations to use through a
+// ViewDescriptor. The output (all measurements broken down by tag values into
+// specific Aggregations) is called a View.
+
+
+// The following two types are copied from
+// google/protobuf/{duration,timestamp}.proto. Ideally, we would be able to
+// import them, but this causes compilation issues on C-based systems
+// (e.g. https://koti.kapsi.fi/jpa/nanopb/), which cannot process the C++
+// headers generated from the standard protobuf distribution. See the relevant
+// proto files for full documentation of these types.
+
+message Duration {
+ // Signed seconds of the span of time. Must be from -315,576,000,000
+ // to +315,576,000,000 inclusive.
+ int64 seconds = 1;
+
+ // Signed fractions of a second at nanosecond resolution of the span
+ // of time. Durations less than one second are represented with a 0
+ // `seconds` field and a positive or negative `nanos` field. For durations
+ // of one second or more, a non-zero value for the `nanos` field must be
+ // of the same sign as the `seconds` field. Must be from -999,999,999
+ // to +999,999,999 inclusive.
+ int32 nanos = 2;
+}
+
+message Timestamp {
+ // Represents seconds of UTC time since Unix epoch
+ // 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
+ // 9999-12-31T23:59:59Z inclusive.
+ int64 seconds = 1;
+
+ // Non-negative fractions of a second at nanosecond resolution. Negative
+ // second values with fractions must still have non-negative nanos values
+ // that count forward in time. Must be from 0 to 999,999,999
+ // inclusive.
+ int32 nanos = 2;
+}
+
+// MeasurementDescriptor describes a data point (measurement) type.
+message MeasurementDescriptor {
+ // A descriptive name, e.g. rpc_latency, cpu. Must be unique.
+ string name = 1;
+
+ // More detailed description of the resource, used in documentation.
+ string description = 2;
+
+ // Fundamental units of measurement supported by Census
+ // TODO(aveitch): expand this to include other S.I. units?
+ enum BasicUnit {
+ UNKNOWN = 0; // Implementations should not use this
+ SCALAR = 1; // Dimensionless
+ BITS = 2; // A single bit
+ BYTES = 3; // An 8-bit byte
+ SECONDS = 4; // S.I. unit
+ CORES = 5; // CPU core usage
+ MAX_UNITS = 6; // Last defined value; implementations should only use
+ // this for validation.
+ }
+
+ // MeasurementUnit lets you build compound units of the form
+ // 10^n * (A * B * ...) / (X * Y * ...),
+ // where the elements in the numerator and denominator are all BasicUnits. A
+ // MeasurementUnit must have at least one BasicUnit in its numerator.
+ //
+ // To specify multiplication in the numerator or denominator, simply specify
+ // multiple numerator or denominator fields. For example:
+ //
+ // - byte-seconds (i.e. bytes * seconds):
+ // numerator: BYTES
+ // numerator: SECS
+ //
+ // - events/sec^2 (i.e. rate of change of events/sec):
+ // numerator: SCALAR
+ // denominator: SECS
+ // denominator: SECS
+ //
+ // To specify multiples (in power of 10) of units, specify a non-zero
+ // 'power10' value, for example:
+ //
+ // - MB/s (i.e. megabytes / s):
+ // power10: 6
+ // numerator: BYTES
+ // denominator: SECS
+ //
+ // - nanoseconds
+ // power10: -9
+ // numerator: SECS
+ message MeasurementUnit {
+ int32 power10 = 1;
+ repeated BasicUnit numerators = 2;
+ repeated BasicUnit denominators = 3;
+ }
+
+ // The units used by this type of measurement.
+ MeasurementUnit unit = 3;
+}
+
+// An aggregation summarizes a series of individual measurements. There are
+// two types of aggregation (IntervalAggregation and DistributionAggregation),
+// unique types of each can be set using descriptors for each.
+
+// DistributionAggregation contains summary statistics for a population of
+// values and, optionally, a histogram representing the distribution of those
+// values across a specified set of histogram buckets, as defined in
+// DistributionAggregationDescriptor.bucket_bounds.
+//
+// The summary statistics are the count, mean, minimum, and the maximum of the
+// set of population of values.
+//
+// Although it is not forbidden, it is generally a bad idea to include
+// non-finite values (infinities or NaNs) in the population of values, as this
+// will render the `mean` field meaningless.
+message DistributionAggregation {
+ // The number of values in the population. Must be non-negative.
+ int64 count = 1;
+
+ // The arithmetic mean of the values in the population. If `count` is zero
+ // then this field must be zero.
+ double mean = 2;
+
+ // The sum of the values in the population. If `count` is zero then this
+ // field must be zero.
+ double sum = 3;
+
+ // Describes a range of population values.
+ message Range {
+ // The minimum of the population values.
+ double min = 1;
+ // The maximum of the population values.
+ double max = 2;
+ }
+
+ // The range of the population values. If `count` is zero, this field will not
+ // be defined.
+ Range range = 4;
+
+ // A Distribution may optionally contain a histogram of the values in the
+ // population. The histogram is given in `bucket_count` as counts of values
+ // that fall into one of a sequence of non-overlapping buckets, as described
+ // by `DistributionAggregationDescriptor.bucket_boundaries`. The sum of the
+ // values in `bucket_counts` must equal the value in `count`.
+ //
+ // Bucket counts are given in order under the numbering scheme described
+ // above (the underflow bucket has number 0; the finite buckets, if any,
+ // have numbers 1 through N-2; the overflow bucket has number N-1).
+ //
+ // The size of `bucket_count` must be no greater than N as defined in
+ // `bucket_boundaries`.
+ //
+ // Any suffix of trailing zero bucket_count fields may be omitted.
+ repeated int64 bucket_counts = 5;
+
+ // Tags associated with this DistributionAggregation. These will be filled
+ // in based on the View specification.
+ repeated Tag tags = 6;
+}
+
+message DistributionAggregationDescriptor {
+ // A Distribution may optionally contain a histogram of the values in the
+ // population. The bucket boundaries for that histogram are described by
+ // `bucket_bounds`. This defines `size(bucket_bounds) + 1` (= N)
+ // buckets. The boundaries for bucket index i are:
+ //
+ // [-infinity, bucket_bounds[i]) for i == 0
+ // [bucket_bounds[i-1], bucket_bounds[i]) for 0 < i < N-2
+ // [bucket_bounds[i-1], +infinity) for i == N-1
+ //
+ // i.e. an underflow bucket (number 0), zero or more finite buckets (1
+ // through N - 2, and an overflow bucket (N - 1), with inclusive lower
+ // bounds and exclusive upper bounds.
+ //
+ // If `bucket_bounds` has no elements (zero size), then there is no
+ // histogram associated with the Distribution. If `bucket_bounds` has only
+ // one element, there are no finite buckets, and that single element is the
+ // common boundary of the overflow and underflow buckets. The values must
+ // be monotonically increasing.
+ repeated double bucket_bounds = 1;
+}
+
+// An IntervalAggreation records summary stats over various time
+// windows. These stats are approximate, with the degree of accuracy
+// controlled by setting the n_sub_intervals parameter in the
+// IntervalAggregationDescriptor.
+message IntervalAggregation {
+ // Summary statistic over a single time interval.
+ message Interval {
+ // The interval duration. Must be positive.
+ Duration interval_size = 1;
+ // Approximate number of measurements recorded in this interval.
+ double count = 2;
+ // The cumulative sum of measurements in this interval.
+ double sum = 3;
+ }
+
+ // Full set of intervals for this aggregation.
+ repeated Interval intervals = 1;
+
+ // Tags associated with this IntervalAggregation. These will be filled in
+ // based on the View specification.
+ repeated Tag tags = 2;
+}
+
+// An IntervalAggreationDescriptor specifies time intervals for an
+// IntervalAggregation.
+message IntervalAggregationDescriptor {
+ // Number of internal sub-intervals to use when collecting stats for each
+ // interval. The max error in interval measurements will be approximately
+ // 1/n_sub_intervals (although in practice, this will only be approached in
+ // the presence of very large and bursty workload changes), and underlying
+ // memory usage will be roughly proportional to the value of this
+ // field. Must be in the range [2, 20]. A value of 5 will be used if this is
+ // unspecified.
+ int32 n_sub_intervals = 1;
+
+ // The size of each interval, as a time duration. Must have at least one
+ // element.
+ repeated Duration interval_sizes = 2;
+}
+
+// A Tag: key-value pair.
+message Tag {
+ string key = 1;
+ string value = 2;
+}
+
+// A ViewDescriptor specifies an AggregationDescriptor and a set of tag
+// keys. Views instantiated from this descriptor will contain Aggregations
+// broken down by the unique set of matching tag values for each measurement.
+message ViewDescriptor {
+ // Name of view. Must be unique.
+ string name = 1;
+
+ // More detailed description, for documentation purposes.
+ string description = 2;
+
+ // Name of a MeasurementDescriptor to be used for this view.
+ string measurement_descriptor_name = 3;
+
+ // Aggregation type to associate with View.
+ oneof aggregation {
+ IntervalAggregationDescriptor interval_aggregation = 4;
+ DistributionAggregationDescriptor distribution_aggregation = 5;
+ }
+
+ // Tag keys to match with a given measurement. If no keys are specified,
+ // then all stats are recorded. Keys must be unique.
+ repeated string tag_keys = 6;
+}
+
+// DistributionView contains all aggregations for a view specified using a
+// DistributionAggregationDescriptor.
+message DistributionView {
+ // Aggregations - each will have a unique set of tag values for the tag_keys
+ // associated with the corresponding View.
+ repeated DistributionAggregation aggregations = 1;
+
+ // Start and end timestamps over which aggregations was accumulated.
+ Timestamp start = 2;
+ Timestamp end = 3;
+}
+
+// IntervalView contains all aggregations for a view specified using a
+// IntervalAggregationDescriptor.
+message IntervalView {
+ // Aggregations - each will have a unique set of tag values for the tag_keys
+ // associated with the corresponding View.
+ repeated IntervalAggregation aggregations = 1;
+}
+
+// A View contains the aggregations based on a ViewDescriptor.
+message View {
+ // ViewDescriptor name associated with this set of View.
+ string view_name = 1;
+
+ oneof view {
+ DistributionView distribution_view = 2;
+ IntervalView interval_view = 3;
+ }
+}
diff --git a/tools/grpcz/empty.proto b/tools/grpcz/empty.proto
new file mode 100644
index 0000000000..03cacd2330
--- /dev/null
+++ b/tools/grpcz/empty.proto
@@ -0,0 +1,52 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "github.com/golang/protobuf/ptypes/empty";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "EmptyProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option cc_enable_arenas = true;
+
+// A generic empty message that you can re-use to avoid defining duplicated
+// empty messages in your APIs. A typical example is to use it as the request
+// or the response type of an API method. For instance:
+//
+// service Foo {
+// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+// }
+//
+// The JSON representation for `Empty` is empty JSON object `{}`.
+message Empty {}
diff --git a/tools/grpcz/grpcz_client.cc b/tools/grpcz/grpcz_client.cc
new file mode 100644
index 0000000000..afca3b0532
--- /dev/null
+++ b/tools/grpcz/grpcz_client.cc
@@ -0,0 +1,174 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include <google/protobuf/util/json_util.h>
+#include <grpc++/grpc++.h>
+#include <grpc/support/log.h>
+
+#include "gflags/gflags.h"
+#include "mongoose.h"
+
+// TODO (makdharma): remove local copies of these protos
+#include "tools/grpcz/census.grpc.pb.h"
+#include "tools/grpcz/monitoring.grpc.pb.h"
+
+DEFINE_string(server, "127.0.0.1:50052",
+ "file path (or host:port) where grpcz server is running");
+DEFINE_string(http_port, "8000",
+ "Port id for accessing the HTTP server that renders /grpcz page");
+DEFINE_bool(print, false, "only print the output and quit");
+
+using grpc::Channel;
+using grpc::ClientContext;
+using grpc::Status;
+
+using ::grpc::instrumentation::v1alpha::CanonicalRpcStats;
+using ::grpc::instrumentation::v1alpha::Monitoring;
+
+static const std::string static_html_header =
+ "<!DOCTYPE html> <html> <head> <style> \
+table { border-collapse: collapse; width: 100%; } \
+table, td, th { border: 1px solid black; } \
+</style> </head> <body>\
+<div id='stats' stats='";
+
+static const std::string static_html_footer =
+ "' class='hidden'></div>\
+<h1> GRPCZ FTW </h1> <div id='table'> </div> \
+<script> \
+ var canonical_stats = JSON.parse(\
+ document.getElementById('stats').getAttribute('stats')); \
+ var table = document.createElement('table'); \
+ for (var key in canonical_stats) { \
+ name = canonical_stats[key]['view']['viewName']; \
+ distribution = canonical_stats[key]['view']['distributionView']; \
+ interval = canonical_stats[key]['view']['intervalView']; \
+ value = (interval == undefined) ? \
+ JSON.stringify(distribution, null, ' ') : \
+ JSON.stringify(interval, null, ' '); \
+ var row = table.insertRow(-1); \
+ var col1 = row.insertCell(0); \
+ var col2 = row.insertCell(1); \
+ col1.innerHTML = name; \
+ col2.innerHTML = '<pre>' + value + '</pre>'; \
+ } \
+ document.getElementById('table').appendChild(table); \
+</script> </body> </html>";
+
+class GrpczClient {
+ public:
+ GrpczClient(std::shared_ptr<Channel> channel)
+ : stub_(Monitoring::NewStub(channel)) {}
+
+ std::string GetStatsAsJson() {
+ const ::google::protobuf::Empty request;
+ CanonicalRpcStats reply;
+ ClientContext context;
+ Status status = stub_->GetCanonicalRpcStats(&context, request, &reply);
+
+ if (status.ok()) {
+ std::string json_str;
+ ::google::protobuf::util::MessageToJsonString(reply, &json_str);
+ return json_str;
+ } else {
+ static const std::string error_message_json =
+ "{\"grpcz Access Error\"\
+ :{\"view\":{\"viewName\":\"grpcz Access Error\",\
+ \"intervalView\":\"Server not running?\"}}}";
+ std::cout << status.error_code() << ":= " << status.error_message()
+ << std::endl;
+ return error_message_json;
+ }
+ }
+
+ private:
+ std::unique_ptr<Monitoring::Stub> stub_;
+};
+
+static struct mg_serve_http_opts s_http_server_opts;
+std::unique_ptr<GrpczClient> g_grpcz_client;
+
+static void ev_handler(struct mg_connection *nc, int ev, void *p) {
+ if (ev == MG_EV_HTTP_REQUEST) {
+ mg_serve_http(nc, (struct http_message *)p, s_http_server_opts);
+ }
+}
+
+static void grpcz_handler(struct mg_connection *nc, int ev, void *ev_data) {
+ (void)ev;
+ (void)ev_data;
+ gpr_log(GPR_INFO, "fetching grpcz stats from %s", FLAGS_server.c_str());
+ std::string json_str = g_grpcz_client->GetStatsAsJson();
+ std::string rendered_html =
+ static_html_header + json_str + static_html_footer;
+ mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n%s", rendered_html.c_str());
+ nc->flags |= MG_F_SEND_AND_CLOSE;
+}
+
+int main(int argc, char **argv) {
+ gflags::ParseCommandLineFlags(&argc, &argv, true);
+
+ // Create a client
+ g_grpcz_client.reset(new GrpczClient(
+ grpc::CreateChannel(FLAGS_server, grpc::InsecureChannelCredentials())));
+ if (FLAGS_print) {
+ g_grpcz_client->GetStatsAsJson();
+ return 0;
+ }
+
+ // Set up a mongoose webserver handler
+ struct mg_mgr mgr;
+ mg_mgr_init(&mgr, NULL);
+ gpr_log(GPR_INFO, "Starting grpcz web server on port %s\n",
+ FLAGS_http_port.c_str());
+
+ struct mg_connection *nc = mg_bind(&mgr, FLAGS_http_port.c_str(), ev_handler);
+ if (nc == NULL) {
+ gpr_log(GPR_ERROR, "Failed to create listener on port %s\n",
+ FLAGS_http_port.c_str());
+ return -11;
+ }
+ mg_register_http_endpoint(nc, "/grpcz", grpcz_handler);
+ mg_set_protocol_http_websocket(nc);
+
+ // Poll in a loop and serve /grpcz pages
+ for (;;) {
+ mg_mgr_poll(&mgr, 100);
+ }
+ mg_mgr_free(&mgr);
+ return 0;
+}
diff --git a/tools/grpcz/monitoring.proto b/tools/grpcz/monitoring.proto
new file mode 100644
index 0000000000..ec3dfe9f74
--- /dev/null
+++ b/tools/grpcz/monitoring.proto
@@ -0,0 +1,131 @@
+// Copyright 2017, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file defines an interface for exporting monitoring information
+// out of gRPC servers.
+syntax = "proto3";
+
+// TODO(ericgribkoff) Figure out how to manage the external Census proto
+// dependency.
+import "tools/grpcz/census.proto";
+import "tools/grpcz/empty.proto";
+import "tools/grpcz/any.proto";
+
+package grpc.instrumentation.v1alpha;
+
+option java_multiple_files = true;
+option java_package = "io.grpc.instrumentation.v1alpha";
+option java_outer_classname = "MonitoringProto";
+
+service Monitoring {
+ // Return canonical RPC stats
+ rpc GetCanonicalRpcStats(google.protobuf.Empty) returns (CanonicalRpcStats) {
+ }
+
+ // Query the server for specific stats
+ rpc GetStats(StatsRequest) returns (StatsResponse) {
+ // TODO(aveitch, ericgribkoff): Pease define the stats response message
+ // StatsRequest would specifically identify the stats to be returned.
+ }
+
+ // Request the server to stream back snapshots of the requested stats
+ rpc WatchStats(StatsRequest) returns (stream StatsResponse) {
+ }
+
+
+ // Return request traces.
+ rpc GetRequestTraces(TraceRequest) returns(TraceResponse) {
+ // TODO(aveitch): Please define the messages here
+ }
+
+ // Return application-defined groups of monitoring data.
+ // This is a low level facility to allow extension of the monitoring API to
+ // application-specific monitoring data. Frameworks may use this to define
+ // additional groups of monitoring data made available by servers.
+ rpc GetCustomMonitoringData(MonitoringDataGroup)
+ returns (CustomMonitoringData) {
+ }
+
+}
+
+// Canonical RPC stats exported by gRPC.
+message CanonicalRpcStats {
+ // Wrapper combining View and ViewDescriptor.
+ message View {
+ google.instrumentation.MeasurementDescriptor measurement_descriptor = 1;
+ google.instrumentation.ViewDescriptor view_descriptor = 2;
+ google.instrumentation.View view = 3;
+ }
+
+ View rpc_client_errors = 1;
+ View rpc_client_completed_rpcs = 2;
+ View rpc_client_started_rpcs = 3;
+ View rpc_client_elapsed_time = 4;
+ View rpc_client_server_elapsed_time = 5;
+ View rpc_client_request_bytes = 6;
+ View rpc_client_response_bytes = 7;
+ View rpc_client_request_count = 8;
+ View rpc_client_response_count = 9;
+ View rpc_server_errors = 10;
+ View rpc_server_completed_rpcs = 11;
+ View rpc_server_server_elapsed_time = 12;
+ View rpc_server_request_bytes = 13;
+ View rpc_server_response_bytes = 14;
+ View rpc_server_request_count = 15;
+ View rpc_server_response_count = 16;
+ View rpc_server_elapsed_time = 17;
+ //TODO(ericgribkoff) Add minute-hour interval stats.
+}
+
+message StatsRequest {
+ // TODO(aveitch): Complete definition of this type
+}
+
+message StatsResponse {
+ // TODO(aveitch): Complete definition of this type
+}
+
+message TraceRequest {
+ // TODO(aveitch): Complete definition of this type
+}
+
+message TraceResponse {
+ // TODO(aveitch): Complete definition of this type
+}
+
+message MonitoringDataGroup {
+ string name = 1; // name of a group of monitoring data
+}
+
+// The wrapper for custom monitoring data.
+message CustomMonitoringData {
+ // can be any application specific monitoring data
+ Any contents = 1;
+}
+
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index 0b68319d29..cfe4e2731c 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -44,7 +44,7 @@ cat << EOF | awk '{ print $1 }' | sort > $want_submodules
44c25c892a6229b20db7cd9dc05584ea865896de third_party/benchmark (v0.1.0-343-g44c25c8)
78684e5b222645828ca302e56b40b9daff2b2d27 third_party/boringssl (78684e5)
886e7d75368e3f4fab3f4d0d3584e4abfc557755 third_party/boringssl-with-bazel (version_for_cocoapods_7.0-857-g886e7d7)
- f8a0efe03aa69b3336d8e228b37d4ccb17324b88 third_party/gflags (v2.2.0)
+ 30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e third_party/gflags (v2.2.0)
c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
a428e42072765993ff674fda72863c9f1aa2d268 third_party/protobuf (v3.1.0-alpha-1)
bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c third_party/thrift (bcad917)