Merge branch 'master' of https://github.com/grpc/grpc into cpp_bazelness

pull/9780/head
Nicolas "Pixel" Noble 8 years ago
commit f3ca374929
  1. 30
      .vscode/launch.json
  2. 1
      CMakeLists.txt
  3. 4
      Makefile
  4. 6
      WORKSPACE
  5. 1
      build.yaml
  6. 20
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme
  7. 4
      src/objective-c/tests/build_one_example.sh
  8. 20
      src/objective-c/tests/run_tests.sh
  9. 63
      test/core/iomgr/ev_epoll_linux_test.c
  10. 2
      tools/distrib/check_copyright.py
  11. 63
      tools/grpcz/BUILD
  12. 318
      tools/grpcz/census.proto
  13. 181
      tools/grpcz/grpcz_client.cc
  14. 156
      tools/grpcz/monitoring.proto
  15. 1
      tools/run_tests/generated/sources_and_headers.json
  16. 2
      vsprojects/vcxproj/test/stress_test/stress_test.vcxproj
  17. 3
      vsprojects/vcxproj/test/stress_test/stress_test.vcxproj.filters

@ -0,0 +1,30 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Mocha Tests",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha.cmd"
},
"runtimeArgs": [
"-u",
"tdd",
"--timeout",
"999999",
"--colors",
"${workspaceRoot}/src/node/test"
],
"internalConsoleOptions": "openOnSessionStart"
},
{
"type": "node",
"request": "attach",
"name": "Attach to Process",
"port": 5858
}
]
}

@ -11363,7 +11363,6 @@ add_executable(stress_test
test/cpp/interop/interop_client.cc
test/cpp/interop/stress_interop_client.cc
test/cpp/interop/stress_test.cc
test/cpp/util/create_test_channel.cc
test/cpp/util/metrics_server.cc
third_party/googletest/src/gtest-all.cc
)

@ -15752,7 +15752,6 @@ STRESS_TEST_SRC = \
test/cpp/interop/interop_client.cc \
test/cpp/interop/stress_interop_client.cc \
test/cpp/interop/stress_test.cc \
test/cpp/util/create_test_channel.cc \
test/cpp/util/metrics_server.cc \
STRESS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(STRESS_TEST_SRC))))
@ -15798,8 +15797,6 @@ $(OBJDIR)/$(CONFIG)/test/cpp/interop/stress_interop_client.o: $(LIBDIR)/$(CONFI
$(OBJDIR)/$(CONFIG)/test/cpp/interop/stress_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
$(OBJDIR)/$(CONFIG)/test/cpp/util/metrics_server.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
deps_stress_test: $(STRESS_TEST_OBJS:.o=.dep)
@ -15812,7 +15809,6 @@ endif
$(OBJDIR)/$(CONFIG)/test/cpp/interop/interop_client.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/interop/stress_interop_client.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/interop/stress_test.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/util/metrics_server.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc

@ -77,6 +77,12 @@ local_repository(
path = "third_party/gflags",
)
git_repository(
name = "mongoose_repo",
commit = "4120a97945b41195a6223a600dae8e3b19bed19e",
remote = "https://github.com/makdharma/mongoose.git"
)
new_local_repository(
name = "submodule_benchmark",
path = "third_party/benchmark",

@ -4141,7 +4141,6 @@ targets:
- test/cpp/interop/interop_client.cc
- test/cpp/interop/stress_interop_client.cc
- test/cpp/interop/stress_test.cc
- test/cpp/util/create_test_channel.cc
- test/cpp/util/metrics_server.cc
deps:
- grpc++_test_util

@ -49,26 +49,6 @@
</Test>
</SkippedTests>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
BuildableName = "CoreCronetEnd2EndTests.xctest"
BlueprintName = "CoreCronetEnd2EndTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EAD6D231E27047400002378"
BuildableName = "CronetUnitTests.xctest"
BlueprintName = "CronetUnitTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference

@ -57,6 +57,4 @@ xcodebuild \
build \
-workspace *.xcworkspace \
-scheme $SCHEME \
-destination name="iPhone 6" \
| egrep "$XCODEBUILD_FILTER" \
| egrep -v "(GPBDictionary|GPBArray)" -
-destination name="iPhone 6" | xcpretty

@ -58,14 +58,22 @@ xcodebuild \
-workspace Tests.xcworkspace \
-scheme AllTests \
-destination name="iPhone 6" \
test \
| egrep "$XCODEBUILD_FILTER" \
| egrep -v "(GPBDictionary|GPBArray)" -
test | xcpretty
xcodebuild \
-workspace Tests.xcworkspace \
-scheme CoreCronetEnd2EndTests \
-destination name="iPhone 6" \
test | xcpretty
xcodebuild \
-workspace Tests.xcworkspace \
-scheme CronetUnitTests \
-destination name="iPhone 6" \
test | xcpretty
xcodebuild \
-workspace Tests.xcworkspace \
-scheme InteropTestsRemoteWithCronet \
-destination name="iPhone 6" \
test \
| egrep "$XCODEBUILD_FILTER" \
| egrep -v "(GPBDictionary|GPBArray)" -
test | xcpretty

@ -139,23 +139,25 @@ static void increment(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
* polling_island_merge()[ev_epoll_linux.c], where the parent relationship was
* inverted.
*/
#define NUM_FDS 2
#define NUM_POLLSETS 2
#define NUM_CLOSURES 4
static void test_pollset_queue_merge_items() {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
const int num_fds = 2;
const int num_pollsets = 2;
const int num_closures = 4;
test_fd tfds[num_fds];
int fds[num_fds];
test_pollset pollsets[num_pollsets];
grpc_closure closures[num_closures];
test_fd tfds[NUM_FDS];
int fds[NUM_FDS];
test_pollset pollsets[NUM_POLLSETS];
grpc_closure closures[NUM_CLOSURES];
int i;
int result = 0;
test_fd_init(tfds, fds, num_fds);
test_pollset_init(pollsets, num_pollsets);
test_fd_init(tfds, fds, NUM_FDS);
test_pollset_init(pollsets, NUM_POLLSETS);
/* Two distinct polling islands, each with their own FD and pollset. */
for (i = 0; i < num_fds; i++) {
for (i = 0; i < NUM_FDS; i++) {
grpc_pollset_add_fd(&exec_ctx, pollsets[i].pollset, tfds[i].fd);
grpc_exec_ctx_flush(&exec_ctx);
}
@ -173,7 +175,7 @@ static void test_pollset_queue_merge_items() {
grpc_closure_init(
closures + 3, increment, &result,
grpc_workqueue_scheduler(grpc_fd_get_polling_island(tfds[1].fd)));
for (i = 0; i < num_closures; ++i) {
for (i = 0; i < NUM_CLOSURES; ++i) {
grpc_closure_sched(&exec_ctx, closures + i, GRPC_ERROR_NONE);
}
@ -186,7 +188,7 @@ static void test_pollset_queue_merge_items() {
* the merged polling island.
*/
grpc_pollset_worker *worker = NULL;
for (i = 0; i < num_closures; ++i) {
for (i = 0; i < NUM_CLOSURES; ++i) {
const gpr_timespec deadline = gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(2, GPR_TIMESPAN));
gpr_mu_lock(pollsets[1].mu);
@ -196,13 +198,17 @@ static void test_pollset_queue_merge_items() {
gpr_now(GPR_CLOCK_MONOTONIC), deadline));
gpr_mu_unlock(pollsets[1].mu);
}
GPR_ASSERT(result == num_closures);
GPR_ASSERT(result == NUM_CLOSURES);
test_fd_cleanup(&exec_ctx, tfds, num_fds);
test_pollset_cleanup(&exec_ctx, pollsets, num_pollsets);
test_fd_cleanup(&exec_ctx, tfds, NUM_FDS);
test_pollset_cleanup(&exec_ctx, pollsets, NUM_POLLSETS);
grpc_exec_ctx_finish(&exec_ctx);
}
#undef NUM_FDS
#undef NUM_POLLSETS
#undef NUM_CLOSURES
/*
* Cases to test:
* case 1) Polling islands of both fd and pollset are NULL
@ -213,18 +219,20 @@ static void test_pollset_queue_merge_items() {
* case 4.2) Polling islands of fd and pollset are NOT-equal (This results
* in a merge)
* */
#define NUM_FDS 8
#define NUM_POLLSETS 4
static void test_add_fd_to_pollset() {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
const int num_fds = 8;
const int num_pollsets = 4;
test_fd tfds[num_fds];
int fds[num_fds];
test_pollset pollsets[num_pollsets];
test_fd tfds[NUM_FDS];
int fds[NUM_FDS];
test_pollset pollsets[NUM_POLLSETS];
void *expected_pi = NULL;
int i;
test_fd_init(tfds, fds, num_fds);
test_pollset_init(pollsets, num_pollsets);
test_fd_init(tfds, fds, NUM_FDS);
test_pollset_init(pollsets, NUM_POLLSETS);
/*Step 1.
* Create three polling islands (This will exercise test case 1 and 2) with
@ -285,22 +293,25 @@ static void test_add_fd_to_pollset() {
/* Compare Fd:0's polling island with that of all other Fds */
expected_pi = grpc_fd_get_polling_island(tfds[0].fd);
for (i = 1; i < num_fds; i++) {
for (i = 1; i < NUM_FDS; i++) {
GPR_ASSERT(grpc_are_polling_islands_equal(
expected_pi, grpc_fd_get_polling_island(tfds[i].fd)));
}
/* Compare Fd:0's polling island with that of all other pollsets */
for (i = 0; i < num_pollsets; i++) {
for (i = 0; i < NUM_POLLSETS; i++) {
GPR_ASSERT(grpc_are_polling_islands_equal(
expected_pi, grpc_pollset_get_polling_island(pollsets[i].pollset)));
}
test_fd_cleanup(&exec_ctx, tfds, num_fds);
test_pollset_cleanup(&exec_ctx, pollsets, num_pollsets);
test_fd_cleanup(&exec_ctx, tfds, NUM_FDS);
test_pollset_cleanup(&exec_ctx, pollsets, NUM_POLLSETS);
grpc_exec_ctx_finish(&exec_ctx);
}
#undef NUM_FDS
#undef NUM_POLLSETS
int main(int argc, char **argv) {
const char *poll_strategy = NULL;
grpc_test_init(argc, argv);

@ -111,6 +111,8 @@ _EXEMPT = frozenset((
# An older file originally from outside gRPC.
'src/php/tests/bootstrap.php',
# census.proto copied from github
'tools/grpcz/census.proto',
))

@ -0,0 +1,63 @@
# 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/grpc_build_system.bzl", "grpc_proto_library")
grpc_proto_library (
name = "monitoring_proto",
srcs = [
"monitoring.proto",
],
deps = [
":census_proto",
],
well_known_protos = "@submodule_protobuf//:well_known_protos",
)
grpc_proto_library (
name = "census_proto",
srcs = [
"census.proto",
],
well_known_protos = "@submodule_protobuf//:well_known_protos",
)
cc_binary(
name = "grpcz_client",
srcs = ["grpcz_client.cc",],
deps = [
"//external:gflags",
"monitoring_proto",
"@mongoose_repo//:mongoose_lib",
],
)

@ -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;
}
}

@ -0,0 +1,181 @@
/*
*
* 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 <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(
grpcz_server, "127.0.0.1:8080",
"Unix domain socket path (e.g. unix://tmp/grpcz.sock) or IP address"
"(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_to_console, false,
"print the JSON retreived from grpcz server 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' data-stats='";
static const std::string static_html_footer =
"' class='hidden'></div>\
<h1>GRPCZ Statistics</h1> <div id='table'> </div> \
<script> \
var canonical_stats = JSON.parse(\
document.getElementById('stats').getAttribute('data-stats')); \
var table = document.createElement('table'); \
if (canonical_stats['Error Message'] != undefined) { \
document.getElementById('table').innerHTML = canonical_stats['Error Message']; } \
else {\
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 =
"{\"Error Message\":\"" + status.error_message() + "\"}";
gpr_log(GPR_DEBUG, "%d: %s", status.error_code(),
status.error_message().c_str());
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_grpcz_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_grpcz_server, grpc::InsecureChannelCredentials())));
if (FLAGS_print_to_console) {
// using GPR_ERROR since this is the default verbosity. _DEBUG or _INFO
// won't print unless GRPC_VERBOSITY env var is set appropriately, which
// might confuse users of this utility.
gpr_log(GPR_ERROR, "%s\n", g_grpcz_client->GetStatsAsJson().c_str());
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 -1;
}
mg_register_http_endpoint(nc, "/grpcz", grpcz_handler);
mg_set_protocol_http_websocket(nc);
// Poll in a loop and serve /grpcz pages
for (;;) {
static const int k_sleep_millis = 100;
mg_mgr_poll(&mgr, k_sleep_millis);
}
mg_mgr_free(&mgr);
return 0;
}

@ -0,0 +1,156 @@
// 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 "google/protobuf/any.proto";
import "google/protobuf/empty.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) {
}
// 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 {
StatsResponse rpc_client_errors = 1;
StatsResponse rpc_client_completed_rpcs = 2;
StatsResponse rpc_client_started_rpcs = 3;
StatsResponse rpc_client_elapsed_time = 4;
StatsResponse rpc_client_server_elapsed_time = 5;
StatsResponse rpc_client_request_bytes = 6;
StatsResponse rpc_client_response_bytes = 7;
StatsResponse rpc_client_request_count = 8;
StatsResponse rpc_client_response_count = 9;
StatsResponse rpc_server_errors = 10;
StatsResponse rpc_server_completed_rpcs = 11;
StatsResponse rpc_server_server_elapsed_time = 12;
StatsResponse rpc_server_request_bytes = 13;
StatsResponse rpc_server_response_bytes = 14;
StatsResponse rpc_server_request_count = 15;
StatsResponse rpc_server_response_count = 16;
StatsResponse rpc_server_elapsed_time = 17;
//TODO(ericgribkoff) Add minute-hour interval stats.
}
// This message is sent when requesting a set of stats (Census Views) from
// a client system, as part of the MonitoringService API's.
message StatsRequest {
// An optional set of ViewDescriptor names. Only Views using these
// descriptors will be sent back in the response. If no names are provided,
// then all Views present in the client system will be included in every
// response. If measurement_names is also provided, then Views matching the
// intersection of the two are returned.
// TODO(aveitch): Consider making this a list of regexes or prefix matches in
// the future.
repeated string view_names = 1;
// An optional set of MeasurementDescriptor names. Only Views using these
// descriptors will be sent back in the response. If no names are provided,
// then all Views present in the client system will be included in every
// response. If view_names is also provided, then Views matching the
// intersection of the two are returned.
// TODO(aveitch): Consider making this a list of regexes or prefix matches in
// the future.
repeated string measurement_names = 2;
// By default, the MeasurementDescriptors and ViewDescriptors corresponding to
// the Views that are returned in a StatsResponse will be included in the
// first such response. Set this to true to have them not sent.
bool dont_include_descriptors_in_first_response = 3;
}
// This message contains all information relevant to a single View. It is the
// return type for GetStats and WatchStats, and used in CanonicalRpcStats.
message StatsResponse {
// A StatsResponse can optionally contain the MeasurementDescriptor and
// ViewDescriptor for the View. These will be sent in the first WatchStats
// response, or all GetStats and GetCanonicalRpcStats responses. These will
// not be set for {Get,Watch}Stats if
// dont_include_descriptors_in_first_response is set to true in the
// StatsRequest.
google.instrumentation.MeasurementDescriptor measurement_descriptor = 1;
google.instrumentation.ViewDescriptor view_descriptor = 2;
// The View data.
google.instrumentation.View view = 3;
}
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
google.protobuf.Any contents = 1;
}

@ -3810,7 +3810,6 @@
"test/cpp/interop/stress_interop_client.cc",
"test/cpp/interop/stress_interop_client.h",
"test/cpp/interop/stress_test.cc",
"test/cpp/util/create_test_channel.cc",
"test/cpp/util/create_test_channel.h",
"test/cpp/util/metrics_server.cc",
"test/cpp/util/metrics_server.h"

@ -205,8 +205,6 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\cpp\interop\stress_test.cc">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\cpp\util\create_test_channel.cc">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\cpp\util\metrics_server.cc">
</ClCompile>
</ItemGroup>

@ -22,9 +22,6 @@
<ClCompile Include="$(SolutionDir)\..\test\cpp\interop\stress_test.cc">
<Filter>test\cpp\interop</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\cpp\util\create_test_channel.cc">
<Filter>test\cpp\util</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\cpp\util\metrics_server.cc">
<Filter>test\cpp\util</Filter>
</ClCompile>

Loading…
Cancel
Save