@ -1 +1 @@ |
||||
6.3.2 |
||||
6.4.0 |
||||
|
@ -1,11 +1,11 @@ |
||||
# Auto-generated by the tools/mkowners/mkowners.py tool |
||||
# Uses OWNERS files in different modules throughout the |
||||
# repository as the source of truth for module ownership. |
||||
/**/OWNERS @markdroth @a11r |
||||
/bazel/** @jtattermusch @veblush @gnossen |
||||
/cmake/** @jtattermusch @apolcyn |
||||
/bazel/** @veblush @gnossen |
||||
/bazel/experiments.yaml |
||||
/cmake/** @veblush @apolcyn |
||||
/src/core/ext/filters/client_channel/** @markdroth |
||||
/src/core/ext/transport/chttp2/transport/** @ctiller |
||||
/src/core/ext/xds/** @markdroth |
||||
/src/core/lib/resolver/** @markdroth |
||||
/src/core/lib/service_config/** @markdroth |
||||
/tools/dockerfile/** @jtattermusch @apolcyn |
||||
/tools/dockerfile/** @drfloob @apolcyn @gnossen |
||||
/tools/run_tests/xds_k8s_test_driver/** @sergiitk @XuanWang-Amos @gnossen |
||||
|
@ -0,0 +1,15 @@ |
||||
# To get started with Dependabot version updates, you'll need to specify which |
||||
# package ecosystems to update and where the package manifests are located. |
||||
# Please see the documentation for all configuration options: |
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates |
||||
|
||||
version: 2 |
||||
updates: |
||||
- package-ecosystem: "github-actions" |
||||
directory: "/" |
||||
schedule: |
||||
interval: "monthly" |
||||
groups: |
||||
github-actions: |
||||
patterns: |
||||
- "*" |
@ -1,60 +1,65 @@ |
||||
lang/core: |
||||
- src/abseil-cpp/** |
||||
- src/boringssl/** |
||||
- src/c-ares/** |
||||
- src/core/** |
||||
- src/proto/** |
||||
- src/re2/** |
||||
- src/upb/** |
||||
- src/zlib/** |
||||
- include/grpc/** |
||||
- test/core/** |
||||
- tools/codegen/core/** |
||||
|
||||
- changed-files: |
||||
- any-glob-to-any-file: |
||||
- src/abseil-cpp/** |
||||
- src/boringssl/** |
||||
- src/c-ares/** |
||||
- src/core/** |
||||
- src/proto/** |
||||
- src/re2/** |
||||
- src/upb/** |
||||
- src/zlib/** |
||||
- include/grpc/** |
||||
- test/core/** |
||||
- tools/codegen/core/** |
||||
lang/c++: |
||||
- examples/cpp/** |
||||
- src/cpp/** |
||||
- include/grpc++/** |
||||
- include/grpcpp/** |
||||
- test/cpp/** |
||||
|
||||
- changed-files: |
||||
- any-glob-to-any-file: |
||||
- examples/cpp/** |
||||
- src/cpp/** |
||||
- include/grpc++/** |
||||
- include/grpcpp/** |
||||
- test/cpp/** |
||||
area/infra: |
||||
- .github/** |
||||
|
||||
- changed-files: |
||||
- any-glob-to-any-file: |
||||
- .github/** |
||||
lang/node: |
||||
- examples/node/** |
||||
- src/compiler/node* |
||||
|
||||
- changed-files: |
||||
- any-glob-to-any-file: |
||||
- examples/node/** |
||||
- src/compiler/node* |
||||
lang/ObjC: |
||||
- examples/objective-c/** |
||||
- src/compiler/objective_c* |
||||
- src/objective-c/** |
||||
|
||||
- changed-files: |
||||
- any-glob-to-any-file: |
||||
- examples/objective-c/** |
||||
- src/compiler/objective_c* |
||||
- src/objective-c/** |
||||
lang/php: |
||||
- examples/php/** |
||||
- src/compiler/php* |
||||
- src/php/** |
||||
|
||||
- changed-files: |
||||
- any-glob-to-any-file: |
||||
- examples/php/** |
||||
- src/compiler/php* |
||||
- src/php/** |
||||
lang/python: |
||||
- bazel/python_rules.bzl |
||||
- examples/python/** |
||||
- requirements.bazel.txt |
||||
- src/compiler/python* |
||||
- any: |
||||
- src/python/** |
||||
- "!src/python/grpcio/grpc_core_dependencies.py" |
||||
|
||||
- changed-files: |
||||
- any-glob-to-any-file: |
||||
- bazel/python_rules.bzl |
||||
- examples/python/** |
||||
- requirements.bazel.txt |
||||
- src/compiler/python* |
||||
- all-globs-to-any-file: |
||||
- src/python/** |
||||
- '!src/python/grpcio/grpc_core_dependencies.py' |
||||
- '!src/python/grpcio_observability/observability_lib_deps.py' |
||||
lang/ruby: |
||||
- examples/ruby/** |
||||
- src/compiler/ruby* |
||||
- src/ruby/** |
||||
|
||||
"lang/C#": |
||||
- src/compiler/csharp* |
||||
- src/csharp/** |
||||
|
||||
"disposition/Needs Internal Changes": |
||||
- src/core/lib/event_engine/windows/** |
||||
- src/core/lib/gpr/windows/** |
||||
- src/core/lib/gprpp/windows/** |
||||
- test/core/event_engine/windows/** |
||||
- changed-files: |
||||
- any-glob-to-any-file: |
||||
- examples/ruby/** |
||||
- src/compiler/ruby* |
||||
- src/ruby/** |
||||
'lang/C#': |
||||
- changed-files: |
||||
- any-glob-to-any-file: |
||||
- src/compiler/csharp* |
||||
- src/csharp/** |
||||
|
@ -1,32 +0,0 @@ |
||||
name: PR Title Check & Tag |
||||
on: |
||||
pull_request_target: |
||||
types: [opened, reopened, synchronize, edited] |
||||
permissions: |
||||
contents: read # to determine modified files (actions/labeler) |
||||
|
||||
jobs: |
||||
triage: |
||||
permissions: |
||||
contents: read # to determine modified files (actions/labeler) |
||||
pull-requests: write # to add labels to PRs (actions/labeler) |
||||
|
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- uses: actions/labeler@v3 |
||||
with: |
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}" |
||||
sync-labels: "" |
||||
|
||||
title-check: |
||||
permissions: |
||||
contents: read |
||||
pull-requests: write |
||||
|
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- uses: thehanimo/pr-title-checker@v1.3.5 |
||||
with: |
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
||||
pass_on_octokit_error: false |
||||
configuration_path: ".github/pr_title_checker_config.json" |
@ -0,0 +1,19 @@ |
||||
name: PR Auto Tag |
||||
on: |
||||
pull_request_target: |
||||
types: [opened, reopened, synchronize, edited] |
||||
permissions: |
||||
contents: read # to determine modified files (actions/labeler) |
||||
|
||||
jobs: |
||||
triage: |
||||
permissions: |
||||
contents: read # to determine modified files (actions/labeler) |
||||
pull-requests: write # to add labels to PRs (actions/labeler) |
||||
|
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0 |
||||
with: |
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}" |
||||
sync-labels: false |
@ -1,73 +0,0 @@ |
||||
name: PSM Interop |
||||
|
||||
on: |
||||
pull_request: |
||||
push: |
||||
branches: |
||||
- master |
||||
|
||||
permissions: |
||||
contents: read |
||||
|
||||
jobs: |
||||
unittest: |
||||
# By default, only version is printed out in parens, e.g. "unittest (3.10)" |
||||
# This changes it to "unittest (python3.10)" |
||||
name: "unittest (python${{ matrix.python_version }})" |
||||
runs-on: ubuntu-latest |
||||
strategy: |
||||
matrix: |
||||
python_version: ["3.9", "3.10", "3.11"] |
||||
fail-fast: false |
||||
permissions: |
||||
pull-requests: read # Used by paths-filter to read the diff. |
||||
defaults: |
||||
run: |
||||
working-directory: 'tools/run_tests/xds_k8s_test_driver' |
||||
|
||||
steps: |
||||
- uses: actions/checkout@v3 |
||||
|
||||
# To add this job to required GitHub checks, it's not enough to use |
||||
# the on.pull_request.paths filter. For required checks, the job needs to |
||||
# return the success status, and not be skipped. |
||||
# Using paths-filter action, we skip the setup/test steps when psm interop |
||||
# files are unchanged, and the job returns success. |
||||
- uses: dorny/paths-filter@v2 |
||||
id: paths_filter |
||||
with: |
||||
filters: | |
||||
psm_interop_src: |
||||
- 'tools/run_tests/xds_k8s_test_driver/**' |
||||
- 'src/proto/grpc/testing/empty.proto' |
||||
- 'src/proto/grpc/testing/messages.proto' |
||||
- 'src/proto/grpc/testing/test.proto' |
||||
|
||||
- uses: actions/setup-python@v4 |
||||
if: ${{ steps.paths_filter.outputs.psm_interop_src == 'true' }} |
||||
with: |
||||
python-version: "${{ matrix.python_version }}" |
||||
cache: 'pip' |
||||
cache-dependency-path: 'tools/run_tests/xds_k8s_test_driver/requirements.lock' |
||||
|
||||
- name: "Install requirements" |
||||
if: ${{ steps.paths_filter.outputs.psm_interop_src == 'true' }} |
||||
run: | |
||||
pip list |
||||
pip install --upgrade pip setuptools |
||||
pip list |
||||
pip install -r requirements.lock |
||||
pip list |
||||
|
||||
- name: "Generate protos" |
||||
if: ${{ steps.paths_filter.outputs.psm_interop_src == 'true' }} |
||||
run: > |
||||
python -m grpc_tools.protoc --proto_path=../../../ |
||||
--python_out=. --grpc_python_out=. |
||||
src/proto/grpc/testing/empty.proto |
||||
src/proto/grpc/testing/messages.proto |
||||
src/proto/grpc/testing/test.proto |
||||
|
||||
- name: "Run unit tests" |
||||
if: ${{ steps.paths_filter.outputs.psm_interop_src == 'true' }} |
||||
run: python -m tests.unit |
@ -0,0 +1,137 @@ |
||||
# Contributing to gRPC: A Step-By-Step Guide |
||||
|
||||
Note: This document is not meant for Google employees. |
||||
|
||||
## Prerequisites |
||||
|
||||
To contribute to the gRPC codebase, you need the following: |
||||
|
||||
1. An |
||||
[active GitHub account](https://docs.github.com/en/get-started/quickstart/creating-an-account-on-github) |
||||
1. [An understanding of Git and GitHub](https://docs.github.com/en/get-started/using-git/about-git) |
||||
1. [Knowledge of how to fork a repository, clone a repository, merge, rebase, |
||||
resolve, push, pull, fetch |
||||
etc.](https://docs.github.com/en/get-started/using-git/about-git) |
||||
1. [git installed and working on your machine](https://github.com/git-guides/install-git) |
||||
1. Knowledge of the language being used, which can be C++, Python, Ruby, |
||||
Objective-C, PHP, or C#. |
||||
|
||||
## Steps to Contribute gRPC C++ Code |
||||
|
||||
The GitHub repository for the C-based gRPC (C++, Python, Ruby, Objective-C, PHP, C#) |
||||
is at https://github.com/grpc/grpc. |
||||
|
||||
### Fork and Clone the Repository |
||||
|
||||
If you want to contribute to the gRPC code base, you need to make a fork of the |
||||
repository. |
||||
|
||||
1. Create your |
||||
[own fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) |
||||
from https://github.com/grpc/grpc. |
||||
|
||||
 |
||||
|
||||
1. [Clone your fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo#cloning-your-forked-repository) |
||||
on your local machine. |
||||
|
||||
### Prepare and Push Your Commit |
||||
|
||||
1. In your cloned repository, create a new branch from `master`. |
||||
1. Then prepare a commit for the files that you want to contribute. |
||||
1. Commit to this branch. |
||||
1. Push the commit to your fork on GitHub. |
||||
|
||||
Take care that your commits are aligned with these |
||||
[guidelines](https://github.com/grpc/grpc/blob/master/CONTRIBUTING.md#guidelines-for-pull-requests). |
||||
|
||||
### Prepare a Pull Request |
||||
|
||||
After pushing your commit, visit https://github.com/grpc/grpc . If the |
||||
forking, branch creation, commit and push have been successful, you will see |
||||
the following message: |
||||
|
||||
 |
||||
|
||||
Take care to allow edits by maintainers. If there is a specific issue |
||||
with your pull request, the maintainer can help if needed. This access to help will reduce |
||||
the turnaround time for your submission. |
||||
|
||||
 |
||||
|
||||
Create a pull request. |
||||
|
||||
### Pull Request Status - Safe Review |
||||
|
||||
Once the pull request is ready, you must wait for a reviewer to be |
||||
assigned to your pull request. |
||||
|
||||
If you see *Not Covered* in the EasyCLA screen, as shown in the following image, |
||||
click on the mentioned link to start the authorization process. |
||||
|
||||
 |
||||
|
||||
You will see a series of screens: |
||||
|
||||
1. Select *Authorize LF-Engineering: |
||||
|
||||
 |
||||
|
||||
1. Select your contributor type: |
||||
|
||||
 |
||||
|
||||
1. Select *SIGN CLA*: |
||||
|
||||
 |
||||
|
||||
Some time after you've digitally signed the document, the EasyCLA will appear as |
||||
*Covered*. |
||||
|
||||
 |
||||
|
||||
After a few hours, you will notice a new "assignee" assigned to the pull request. |
||||
|
||||
 |
||||
|
||||
After a reviewer is assigned to you, they will help with the next |
||||
steps, which are as follows: |
||||
|
||||
1. You complete the code review and address the comments. |
||||
1. Your reviewer may add a few labels as needed. |
||||
|
||||
### Pull Request Status - Green |
||||
|
||||
Once you have approval from the reviewer, check if the tests are running. After |
||||
the tests are complete, look at the status of all the tests. If |
||||
everything is green, everything is good. But usually some failures exist. If |
||||
there are failures, select each failure. The selection will take you to a page |
||||
that has error details. Try to fix the issue. |
||||
|
||||
### Pull Request Approval |
||||
|
||||
For pull requests that are non-trivial, there is a thorough code review process. |
||||
You can read more about the process and requirements |
||||
[here](https://github.com/grpc/grpc/blob/master/CONTRIBUTING.md#guidelines-for-pull-requests). |
||||
|
||||
After you fix the code review, you will finally get an approval. After getting |
||||
approval, you can submit the pull request. |
||||
|
||||
 |
||||
|
||||
### Submission |
||||
|
||||
You **cannot** do submission or merge of a pull request through Github. |
||||
|
||||
 |
||||
|
||||
After you have approval from a reviewer, a Google employee will trigger |
||||
the submission process. When the submission happens: |
||||
|
||||
1. A commit with your changes, along with a few additional formatting changes, will |
||||
be committed to the `grpc/master` branch. |
||||
 |
||||
|
||||
1. The pull request you originally created will be closed. |
||||
 |
||||
|
@ -1,3 +0,0 @@ |
||||
# Top level ownership |
||||
@markdroth **/OWNERS |
||||
@a11r **/OWNERS |
@ -1,5 +0,0 @@ |
||||
set noparent |
||||
@jtattermusch |
||||
@veblush |
||||
@gnossen |
||||
|
@ -1,2 +1,2 @@ |
||||
6.3.2 |
||||
5.4.1 |
||||
6.4.0 |
||||
7.0.0 |
||||
|
@ -1,3 +0,0 @@ |
||||
set noparent |
||||
@jtattermusch |
||||
@apolcyn |
After Width: | Height: | Size: 455 KiB |
After Width: | Height: | Size: 530 KiB |
After Width: | Height: | Size: 389 KiB |
After Width: | Height: | Size: 500 KiB |
After Width: | Height: | Size: 201 KiB |
After Width: | Height: | Size: 173 KiB |
After Width: | Height: | Size: 506 KiB |
After Width: | Height: | Size: 374 KiB |
After Width: | Height: | Size: 523 KiB |
After Width: | Height: | Size: 524 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 540 KiB |
After Width: | Height: | Size: 343 KiB |
@ -0,0 +1,7 @@ |
||||
gRPC Python Observability |
||||
========================= |
||||
|
||||
Module Contents |
||||
--------------- |
||||
|
||||
.. automodule:: grpc_observability |
@ -0,0 +1,39 @@ |
||||
# Copyright 2023 the gRPC authors. |
||||
# |
||||
# 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. |
||||
|
||||
licenses(["notice"]) |
||||
|
||||
cc_binary( |
||||
name = "client", |
||||
srcs = ["client.cc"], |
||||
defines = ["BAZEL_BUILD"], |
||||
deps = [ |
||||
"//:grpc++", |
||||
"//examples/protos:helloworld_cc_grpc", |
||||
"@com_google_absl//absl/flags:flag", |
||||
"@com_google_absl//absl/flags:parse", |
||||
], |
||||
) |
||||
|
||||
cc_binary( |
||||
name = "server", |
||||
srcs = ["server.cc"], |
||||
defines = ["BAZEL_BUILD"], |
||||
deps = [ |
||||
"//:grpc++", |
||||
"//examples/protos:helloworld_cc_grpc", |
||||
"@com_google_absl//absl/flags:flag", |
||||
"@com_google_absl//absl/flags:parse", |
||||
], |
||||
) |
@ -0,0 +1,70 @@ |
||||
# Copyright 2023 the gRPC authors. |
||||
# |
||||
# 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. |
||||
# |
||||
# Assumes protobuf and gRPC have been installed using cmake. |
||||
# See cmake_externalproject/CMakeLists.txt for all-in-one cmake build |
||||
# that automatically builds all the dependencies before building this example. |
||||
|
||||
cmake_minimum_required(VERSION 3.8) |
||||
|
||||
project(Deadline C CXX) |
||||
|
||||
include(../cmake/common.cmake) |
||||
|
||||
# Proto files |
||||
get_filename_component(hw_proto "../../protos/helloworld.proto" ABSOLUTE) |
||||
get_filename_component(hw_proto_path "${hw_proto}" PATH) |
||||
|
||||
# Generated sources |
||||
set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.cc") |
||||
set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.h") |
||||
set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.cc") |
||||
set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.h") |
||||
add_custom_command( |
||||
OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}" |
||||
COMMAND ${_PROTOBUF_PROTOC} |
||||
ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" |
||||
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}" |
||||
-I "${hw_proto_path}" |
||||
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" |
||||
"${hw_proto}" |
||||
DEPENDS "${hw_proto}") |
||||
|
||||
# Include generated *.pb.h files |
||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}") |
||||
|
||||
# hw_grpc_proto |
||||
add_library(hw_grpc_proto |
||||
${hw_grpc_srcs} |
||||
${hw_grpc_hdrs} |
||||
${hw_proto_srcs} |
||||
${hw_proto_hdrs}) |
||||
target_link_libraries(hw_grpc_proto |
||||
${_REFLECTION} |
||||
${_GRPC_GRPCPP} |
||||
${_PROTOBUF_LIBPROTOBUF}) |
||||
|
||||
# Targets greeter_(client|server) |
||||
foreach(_target |
||||
client server) |
||||
add_executable(${_target} "${_target}.cc") |
||||
target_link_libraries(${_target} |
||||
hw_grpc_proto |
||||
absl::flags |
||||
absl::flags_parse |
||||
absl::strings |
||||
${_REFLECTION} |
||||
${_GRPC_GRPCPP} |
||||
${_PROTOBUF_LIBPROTOBUF}) |
||||
endforeach() |
@ -0,0 +1,35 @@ |
||||
# Deadline Example |
||||
|
||||
## Overview |
||||
|
||||
This example shows you how to use deadline when calling calls. |
||||
|
||||
### Try it! |
||||
|
||||
Once you have working gRPC, you can build this example using either bazel or cmake. |
||||
|
||||
Run the server, which will listen on port 50051: |
||||
|
||||
```sh |
||||
$ ./server |
||||
``` |
||||
|
||||
Run the client (in a different terminal): |
||||
|
||||
```sh |
||||
$ ./client |
||||
``` |
||||
|
||||
To simulate the test scenario, the test server implements following functionalities: |
||||
- Response Delay: The server intentionally delays its response for `delay` request messages to induce timeout conditions. |
||||
- Deadline Propagation: Upon receiving a request with the `[propagate me]` prefix, the server forwards it back to itselt. |
||||
This simulates the propagation of deadlines within the system. |
||||
|
||||
If things go smoothly, you will see the client output: |
||||
|
||||
``` |
||||
[Successful request] wanted = 0, got = 0 |
||||
[Exceeds deadline] wanted = 4, got = 4 |
||||
[Successful request with propagated deadline] wanted = 0, got = 0 |
||||
[Exceeds propagated deadline] wanted = 4, got = 4 |
||||
``` |
@ -0,0 +1,106 @@ |
||||
// Copyright 2023 gRPC authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <condition_variable> |
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <mutex> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "absl/flags/flag.h" |
||||
#include "absl/flags/parse.h" |
||||
#include "absl/strings/str_cat.h" |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using grpc::StatusCode; |
||||
using helloworld::Greeter; |
||||
using helloworld::HelloReply; |
||||
using helloworld::HelloRequest; |
||||
|
||||
void unaryCall(std::shared_ptr<Channel> channel, std::string label, |
||||
std::string message, grpc::StatusCode expected_code) { |
||||
std::unique_ptr<Greeter::Stub> stub = Greeter::NewStub(channel); |
||||
|
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(message); |
||||
|
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
|
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
|
||||
// Set 1 second timeout
|
||||
context.set_deadline(std::chrono::system_clock::now() + |
||||
std::chrono::seconds(1)); |
||||
|
||||
// The actual RPC.
|
||||
std::mutex mu; |
||||
std::condition_variable cv; |
||||
bool done = false; |
||||
Status status; |
||||
stub->async()->SayHello(&context, &request, &reply, |
||||
[&mu, &cv, &done, &status](Status s) { |
||||
status = std::move(s); |
||||
std::lock_guard<std::mutex> lock(mu); |
||||
done = true; |
||||
cv.notify_one(); |
||||
}); |
||||
|
||||
std::unique_lock<std::mutex> lock(mu); |
||||
while (!done) { |
||||
cv.wait(lock); |
||||
} |
||||
|
||||
// Act upon its status.
|
||||
std::cout << "[" << label << "] wanted = " << expected_code |
||||
<< ", got = " << status.error_code() << std::endl; |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
absl::ParseCommandLine(argc, argv); |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint specified by
|
||||
// the argument "--target=" which is the only expected argument.
|
||||
std::string target_str = absl::GetFlag(FLAGS_target); |
||||
// We indicate that the channel isn't authenticated (use of
|
||||
// InsecureChannelCredentials()).
|
||||
std::shared_ptr<Channel> channel = |
||||
grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials()); |
||||
// Making test calls
|
||||
unaryCall(channel, "Successful request", "world", grpc::StatusCode::OK); |
||||
unaryCall(channel, "Exceeds deadline", "delay", |
||||
grpc::StatusCode::DEADLINE_EXCEEDED); |
||||
unaryCall(channel, "Successful request with propagated deadline", |
||||
"[propagate me]world", grpc::StatusCode::OK); |
||||
unaryCall(channel, "Exceeds propagated deadline", |
||||
"[propagate me][propagate me]world", |
||||
grpc::StatusCode::DEADLINE_EXCEEDED); |
||||
return 0; |
||||
} |
@ -0,0 +1,130 @@ |
||||
// Copyright 2023 gRPC authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <chrono> |
||||
#include <condition_variable> |
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
#include <thread> |
||||
#include <vector> |
||||
|
||||
#include "absl/flags/flag.h" |
||||
#include "absl/flags/parse.h" |
||||
#include "absl/strings/match.h" |
||||
#include "absl/strings/str_format.h" |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); |
||||
|
||||
using grpc::CallbackServerContext; |
||||
using grpc::Channel; |
||||
using grpc::ClientContext; |
||||
|
||||
using grpc::Server; |
||||
using grpc::ServerBidiReactor; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerUnaryReactor; |
||||
using grpc::Status; |
||||
using helloworld::Greeter; |
||||
using helloworld::HelloReply; |
||||
using helloworld::HelloRequest; |
||||
|
||||
// Logic behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::CallbackService { |
||||
public: |
||||
GreeterServiceImpl(const std::string& self_address) { |
||||
self_channel_ = |
||||
grpc::CreateChannel(self_address, grpc::InsecureChannelCredentials()); |
||||
} |
||||
|
||||
private: |
||||
ServerUnaryReactor* SayHello(CallbackServerContext* context, |
||||
const HelloRequest* request, |
||||
HelloReply* reply) override { |
||||
if (absl::StartsWith(request->name(), "[propagate me]")) { |
||||
std::unique_ptr<Greeter::Stub> stub = Greeter::NewStub(self_channel_); |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(800)); |
||||
// Forwarding this call to the self as a different call
|
||||
HelloRequest new_request; |
||||
new_request.set_name(request->name().substr(14)); |
||||
std::unique_ptr<ClientContext> new_context = |
||||
ClientContext::FromCallbackServerContext(*context); |
||||
std::mutex mu; |
||||
std::condition_variable cv; |
||||
bool done = false; |
||||
Status status; |
||||
stub->async()->SayHello(new_context.get(), &new_request, reply, |
||||
[&mu, &cv, &done, &status](Status s) { |
||||
status = std::move(s); |
||||
std::lock_guard<std::mutex> lock(mu); |
||||
done = true; |
||||
cv.notify_one(); |
||||
}); |
||||
std::unique_lock<std::mutex> lock(mu); |
||||
while (!done) { |
||||
cv.wait(lock); |
||||
} |
||||
ServerUnaryReactor* reactor = context->DefaultReactor(); |
||||
reactor->Finish(status); |
||||
return reactor; |
||||
} |
||||
|
||||
if (request->name() == "delay") { |
||||
// Intentionally delay for 1.5 seconds so that
|
||||
// the client will see deadline_exceeded.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1500)); |
||||
} |
||||
|
||||
reply->set_message(request->name()); |
||||
|
||||
ServerUnaryReactor* reactor = context->DefaultReactor(); |
||||
reactor->Finish(Status::OK); |
||||
return reactor; |
||||
} |
||||
|
||||
std::shared_ptr<Channel> self_channel_; |
||||
}; |
||||
|
||||
void RunServer(uint16_t port) { |
||||
std::string server_address = absl::StrFormat("0.0.0.0:%d", port); |
||||
GreeterServiceImpl service(server_address); |
||||
|
||||
ServerBuilder builder; |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
absl::ParseCommandLine(argc, argv); |
||||
RunServer(absl::GetFlag(FLAGS_port)); |
||||
return 0; |
||||
} |
@ -0,0 +1,42 @@ |
||||
# Copyright 2023 the gRPC authors. |
||||
# |
||||
# 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. |
||||
|
||||
licenses(["notice"]) |
||||
|
||||
cc_binary( |
||||
name = "crashing_greeter_client", |
||||
srcs = ["crashing_greeter_client.cc"], |
||||
defines = ["BAZEL_BUILD"], |
||||
deps = [ |
||||
"//:grpc++", |
||||
"//examples/protos:helloworld_cc_grpc", |
||||
"@com_google_absl//absl/flags:flag", |
||||
"@com_google_absl//absl/flags:parse", |
||||
], |
||||
) |
||||
|
||||
cc_binary( |
||||
name = "greeter_callback_server_admin", |
||||
srcs = ["greeter_callback_server_admin.cc"], |
||||
defines = ["BAZEL_BUILD"], |
||||
deps = [ |
||||
"//:grpc++", |
||||
"//:grpc++_reflection", |
||||
"//:grpcpp_admin", |
||||
"//examples/protos:helloworld_cc_grpc", |
||||
"@com_google_absl//absl/flags:flag", |
||||
"@com_google_absl//absl/flags:parse", |
||||
"@com_google_absl//absl/strings:str_format", |
||||
], |
||||
) |
@ -0,0 +1,132 @@ |
||||
# gRPC C++ Debugging Example |
||||
|
||||
This example demonstrates a handful of ways you can debug your gRPC C++ applications. |
||||
|
||||
## Enabling Trace Logs |
||||
|
||||
gRPC allows you to configure more detailed log output for various aspects of gRPC behavior. The tracing log generation might have a large overhead and result in significantly larger log file sizes, especially when you try to trace transport or timer_check. But it is a powerful tool in your debugging toolkit. |
||||
|
||||
### The Most Verbose Logging |
||||
|
||||
Specify environment variables, then run your application: |
||||
|
||||
``` |
||||
GRPC_VERBOSITY=debug |
||||
GRPC_TRACE=all |
||||
``` |
||||
|
||||
For more granularity, please see |
||||
[environment_variables](https://github.com/grpc/grpc/blob/master/doc/environment_variables.md). |
||||
|
||||
### Debug Transport Protocol |
||||
|
||||
``` |
||||
GRPC_VERBOSITY=debug |
||||
GRPC_TRACE=tcp,http,secure_endpoint,transport_security |
||||
``` |
||||
|
||||
### Debug Connection Behavior |
||||
|
||||
``` |
||||
GRPC_VERBOSITY=debug |
||||
GRPC_TRACE=call_error,connectivity_state,pick_first,round_robin,glb |
||||
``` |
||||
|
||||
## GDB and other debuggers |
||||
|
||||
`gdb` (and the like) are tools that lets you inspect your application while it is running, view stack traces on exceptions, pause and step through code at specified points or under certain conditions, etc. See https://www.sourceware.org/gdb/ |
||||
|
||||
### Inspecting errors |
||||
|
||||
``` |
||||
bazel build --config=dbg examples/cpp/debugging:crashing_greeter_client |
||||
gdb -ex run \ |
||||
--args ./bazel-bin/examples/cpp/debugging/crashing_greeter_client \ |
||||
--crash_on_errors=true \ |
||||
--target=localhork:50051 |
||||
``` |
||||
|
||||
Once the exception is thrown, you can use `bt` to see the stack trace and examine the crash, `info threads` to get the set of threads, etc. See the [GDB documentation](https://sourceware.org/gdb/current/onlinedocs/gdb.html/) for a more complete list of available features and commands. |
||||
|
||||
### Breaking inside a function |
||||
|
||||
After building the application above, this will break inside gRPC generated stub code: |
||||
|
||||
``` |
||||
gdb -ex 'b helloworld::Greeter::Stub::SayHello' \ |
||||
-ex run \ |
||||
--args ./bazel-bin/examples/cpp/debugging/crashing_greeter_client \ |
||||
--crash_on_errors=true \ |
||||
--target=localhork:50051 |
||||
``` |
||||
|
||||
## gRPC Admin Interface: Live Channel Tracing |
||||
|
||||
The [gRPC Admin Service](https://github.com/grpc/proposal/blob/master/A38-admin-interface-api.md) |
||||
provides a convenient API in each gRPC language to improve the usability of |
||||
creating a gRPC server with admin services to expose states in the gRPC library. |
||||
This includes channelz, which is a channel tracing feature; it tracks statistics |
||||
like how many messages have been sent, how many of them failed, what are the |
||||
connected sockets. See the [Channelz design doc](https://github.com/grpc/proposal/blob/master/A14-channelz.md). |
||||
|
||||
### Integrating the gRPC Admin Service Into Your Server |
||||
|
||||
As seen in the `greeter_callback_admin_server` target, you canenable admin services by using the `AddAdminServices` method. |
||||
|
||||
``` |
||||
grpc::ServerBuilder builder; |
||||
grpc::AddAdminServices(&builder); |
||||
builder.AddListeningPort(":50051", grpc::ServerCredentials(...)); |
||||
std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); |
||||
``` |
||||
|
||||
### Using grpcdebug |
||||
|
||||
grpcdebug is a tool created to access the metrics from channelz and health services. |
||||
|
||||
#### Installing the grpcdebug tool |
||||
|
||||
The source code is located in a github project |
||||
[grpc-ecosystem/grpcdebug](https://github.com/grpc-ecosystem/grpcdebug). You |
||||
can either download [the latest built version] |
||||
(https://github.com/grpc-ecosystem/grpcdebug/releases/latest) (recommended) or |
||||
follow the README.md to build it yourself. |
||||
|
||||
#### Running the grpcdebug tool |
||||
##### Usage |
||||
`grpcdebug <target address> [flags] channelz <command> [argument]` |
||||
|
||||
|
||||
| Command | Argument | Description | |
||||
| :--------- | :------------------: | :------------------------------------------------ | |
||||
| channel | \<channel id or URL> | Display channel states in a human readable way. | |
||||
| channels | | Lists client channels for the target application. | |
||||
| server | \<server ID> | Displays server state in a human readable way. | |
||||
| servers | | Lists servers in a human readable way. | |
||||
| socket | \<socket ID> | Displays socket states in a human readable way. | |
||||
| subchannel | \<id> | Display subchannel states in human readable way. | |
||||
|
||||
Generally, you will start with either `servers` or `channels` and then work down |
||||
to the details |
||||
|
||||
##### Getting overall server info |
||||
|
||||
To begin with, build and run the server binary in the background |
||||
|
||||
``` |
||||
bazel build --config=dbg examples/cpp/debugging:all |
||||
./bazel-bin/examples/cpp/debugging/greeter_callback_server_admin& |
||||
``` |
||||
|
||||
You can then inspect the server |
||||
```bash |
||||
grpcdebug localhost:50051 channelz servers |
||||
``` |
||||
|
||||
This will show you the server ids with their activity |
||||
```text |
||||
Server ID Listen Addresses Calls(Started/Succeeded/Failed) Last Call Started |
||||
1 [[::]:50051] 38/34/3 now |
||||
``` |
||||
|
||||
For more information about `grpcdebug` features, please see [the grpcdebug documentation](https://github.com/grpc-ecosystem/grpcdebug) |
@ -0,0 +1,92 @@ |
||||
// Copyright 2023 The gRPC Authors
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include "absl/flags/flag.h" |
||||
#include "absl/flags/parse.h" |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
ABSL_FLAG(bool, crash_on_errors, false, |
||||
"Crash the application on client errors"); |
||||
ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using helloworld::Greeter; |
||||
using helloworld::HelloReply; |
||||
using helloworld::HelloRequest; |
||||
|
||||
class GreeterClient { |
||||
public: |
||||
GreeterClient(std::shared_ptr<Channel> channel) |
||||
: stub_(Greeter::NewStub(channel)) {} |
||||
|
||||
// Assembles the client's payload, sends it and presents the response back
|
||||
// from the server.
|
||||
std::string SayHello(const std::string& user) { |
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(user); |
||||
|
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
|
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
|
||||
// The actual RPC.
|
||||
Status status = stub_->SayHello(&context, request, &reply); |
||||
|
||||
// Act upon the status of the actual RPC.
|
||||
if (absl::GetFlag(FLAGS_crash_on_errors)) { |
||||
assert(status.ok()); |
||||
} |
||||
if (status.ok()) { |
||||
return reply.message(); |
||||
} else { |
||||
return "RPC failed"; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
std::unique_ptr<Greeter::Stub> stub_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
absl::ParseCommandLine(argc, argv); |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint specified by
|
||||
// the argument "--target=" which is the only expected argument.
|
||||
// We indicate that the channel isn't authenticated (use of
|
||||
// InsecureChannelCredentials()).
|
||||
GreeterClient greeter(grpc::CreateChannel( |
||||
absl::GetFlag(FLAGS_target), grpc::InsecureChannelCredentials())); |
||||
std::string user("world"); |
||||
std::string reply = greeter.SayHello(user); |
||||
std::cout << "Greeter received: " << reply << std::endl; |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,86 @@ |
||||
// Copyright 2023 The gRPC Authors
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include "absl/flags/flag.h" |
||||
#include "absl/flags/parse.h" |
||||
#include "absl/strings/str_format.h" |
||||
|
||||
#include <grpcpp/ext/admin_services.h> |
||||
#include <grpcpp/ext/proto_server_reflection_plugin.h> |
||||
#include <grpcpp/grpcpp.h> |
||||
#include <grpcpp/health_check_service_interface.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); |
||||
|
||||
using grpc::CallbackServerContext; |
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerUnaryReactor; |
||||
using grpc::Status; |
||||
using helloworld::Greeter; |
||||
using helloworld::HelloReply; |
||||
using helloworld::HelloRequest; |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::CallbackService { |
||||
ServerUnaryReactor* SayHello(CallbackServerContext* context, |
||||
const HelloRequest* request, |
||||
HelloReply* reply) override { |
||||
std::string prefix("Hello "); |
||||
reply->set_message(prefix + request->name()); |
||||
|
||||
ServerUnaryReactor* reactor = context->DefaultReactor(); |
||||
reactor->Finish(Status::OK); |
||||
return reactor; |
||||
} |
||||
}; |
||||
|
||||
void RunServer(uint16_t port) { |
||||
std::string server_address = absl::StrFormat("0.0.0.0:%d", port); |
||||
GreeterServiceImpl service; |
||||
|
||||
grpc::EnableDefaultHealthCheckService(true); |
||||
grpc::reflection::InitProtoReflectionServerBuilderPlugin(); |
||||
ServerBuilder builder; |
||||
// Enable gRPC Admin Services
|
||||
grpc::AddAdminServices(&builder); |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
absl::ParseCommandLine(argc, argv); |
||||
RunServer(absl::GetFlag(FLAGS_port)); |
||||
return 0; |
||||
} |
@ -0,0 +1,40 @@ |
||||
# Copyright 2023 the gRPC authors. |
||||
# |
||||
# 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. |
||||
|
||||
licenses(["notice"]) |
||||
|
||||
cc_binary( |
||||
name = "greeter_client", |
||||
srcs = ["greeter_client.cc"], |
||||
defines = ["BAZEL_BUILD"], |
||||
deps = [ |
||||
"//:grpc++", |
||||
"//examples/protos:helloworld_cc_grpc", |
||||
"@com_google_absl//absl/flags:flag", |
||||
"@com_google_absl//absl/flags:parse", |
||||
], |
||||
) |
||||
|
||||
cc_binary( |
||||
name = "greeter_server", |
||||
srcs = ["greeter_server.cc"], |
||||
defines = ["BAZEL_BUILD"], |
||||
deps = [ |
||||
"//:grpc++", |
||||
"//examples/protos:helloworld_cc_grpc", |
||||
"@com_google_absl//absl/flags:flag", |
||||
"@com_google_absl//absl/flags:parse", |
||||
"@com_google_absl//absl/strings:str_format", |
||||
], |
||||
) |
@ -0,0 +1,70 @@ |
||||
# Copyright 2023 the gRPC authors. |
||||
# |
||||
# 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. |
||||
# |
||||
# cmake build file for C++ helloworld example. |
||||
# Assumes protobuf and gRPC have been installed using cmake. |
||||
# See cmake_externalproject/CMakeLists.txt for all-in-one cmake build |
||||
# that automatically builds all the dependencies before building helloworld. |
||||
|
||||
cmake_minimum_required(VERSION 3.8) |
||||
|
||||
project(GenericAPI C CXX) |
||||
|
||||
include(../cmake/common.cmake) |
||||
|
||||
# Proto files |
||||
get_filename_component(hw_proto "../../protos/helloworld.proto" ABSOLUTE) |
||||
get_filename_component(hw_proto_path "${hw_proto}" PATH) |
||||
|
||||
# Generated sources |
||||
set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.cc") |
||||
set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.h") |
||||
set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.cc") |
||||
set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.h") |
||||
add_custom_command( |
||||
OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}" |
||||
COMMAND ${_PROTOBUF_PROTOC} |
||||
ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" |
||||
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}" |
||||
-I "${hw_proto_path}" |
||||
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" |
||||
"${hw_proto}" |
||||
DEPENDS "${hw_proto}") |
||||
|
||||
# Include generated *.pb.h files |
||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}") |
||||
|
||||
# hw_grpc_proto |
||||
add_library(hw_grpc_proto |
||||
${hw_grpc_srcs} |
||||
${hw_grpc_hdrs} |
||||
${hw_proto_srcs} |
||||
${hw_proto_hdrs}) |
||||
target_link_libraries(hw_grpc_proto |
||||
${_REFLECTION} |
||||
${_GRPC_GRPCPP} |
||||
${_PROTOBUF_LIBPROTOBUF}) |
||||
|
||||
# Targets greeter_(client|server) |
||||
foreach(_target |
||||
greeter_client greeter_server) |
||||
add_executable(${_target} "${_target}.cc") |
||||
target_link_libraries(${_target} |
||||
hw_grpc_proto |
||||
absl::flags |
||||
absl::flags_parse |
||||
${_REFLECTION} |
||||
${_GRPC_GRPCPP} |
||||
${_PROTOBUF_LIBPROTOBUF}) |
||||
endforeach() |
@ -0,0 +1,36 @@ |
||||
# Generic API Example |
||||
|
||||
## Overview |
||||
|
||||
While generated stub code is often the simpler and best choice for sending and handling API calls, |
||||
generic APIs offer unique advantages in specific scenarios, such as proxy implementation. |
||||
Their ability to manage multiple message types with a single function makes them particularly handy |
||||
in these cases. This example demonstrates how to use generic APIs to achieve this flexibility. |
||||
|
||||
This example implements `greeter_callback_client` and `greeter_callback_server` using the generic APIs. |
||||
Therefore, looking at the difference would be helpful to understand how to use generic APIs. |
||||
|
||||
### Try it! |
||||
|
||||
Once you have working gRPC, you can build this example using either bazel or cmake. |
||||
|
||||
Run the server, which will listen on port 50051: |
||||
|
||||
```sh |
||||
$ ./greeter_server |
||||
``` |
||||
|
||||
Run the client (in a different terminal): |
||||
|
||||
```sh |
||||
$ ./greeter_client |
||||
``` |
||||
|
||||
If things go smoothly, you will see the client output: |
||||
|
||||
``` |
||||
### Send: SayHello(name=World) |
||||
Ok. ReplyMessage=Hello World |
||||
### Send: SayHello(name=gRPC) |
||||
Ok. ReplyMessage=Hello gRPC |
||||
``` |
@ -0,0 +1,112 @@ |
||||
// Copyright 2023 gRPC authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <condition_variable> |
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <mutex> |
||||
#include <string> |
||||
|
||||
#include "absl/flags/flag.h" |
||||
#include "absl/flags/parse.h" |
||||
#include "absl/strings/str_format.h" |
||||
|
||||
#include <grpcpp/generic/generic_stub.h> |
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using helloworld::Greeter; |
||||
using helloworld::HelloReply; |
||||
using helloworld::HelloRequest; |
||||
|
||||
using ProtoGenericStub = |
||||
::grpc::TemplatedGenericStub<::google::protobuf::Message, |
||||
::google::protobuf::Message>; |
||||
|
||||
class GreeterClient { |
||||
public: |
||||
GreeterClient(std::shared_ptr<Channel> channel) |
||||
: stub_(new ProtoGenericStub(channel)) {} |
||||
|
||||
// Assembles the client's payload, sends it and prints the response back
|
||||
// from the server.
|
||||
void SayHello(const std::string& user) { |
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(user); |
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
// The actual RPC.
|
||||
std::mutex mu; |
||||
std::condition_variable cv; |
||||
bool done = false; |
||||
Status status; |
||||
std::cout << absl::StrFormat("### Send: SayHello(name=%s)", user) |
||||
<< std::endl; |
||||
// Send a unary call using a generic stub. Unlike generated subs,
|
||||
// this requires to specify the name of call.
|
||||
stub_->UnaryCall(&context, "/helloworld.Greeter/SayHello", |
||||
grpc::StubOptions(), &request, &reply, [&](Status s) { |
||||
status = std::move(s); |
||||
std::lock_guard<std::mutex> lock(mu); |
||||
done = true; |
||||
cv.notify_one(); |
||||
}); |
||||
std::unique_lock<std::mutex> lock(mu); |
||||
while (!done) { |
||||
cv.wait(lock); |
||||
} |
||||
// Handles the reply
|
||||
if (status.ok()) { |
||||
std::cout << absl::StrFormat("Ok. ReplyMessage=%s", reply.message()) |
||||
<< std::endl; |
||||
} else { |
||||
std::cout << absl::StrFormat("Failed. Code=%d Message=%s", |
||||
status.error_code(), status.error_message()) |
||||
<< std::endl; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
// Instead of `Greeter::Stub`, it uses `ProtoGenericStub` to send any calls.
|
||||
std::unique_ptr<ProtoGenericStub> stub_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
absl::ParseCommandLine(argc, argv); |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint specified by
|
||||
// the argument "--target=" which is the only expected argument.
|
||||
std::string target_str = absl::GetFlag(FLAGS_target); |
||||
// We indicate that the channel isn't authenticated (use of
|
||||
// InsecureChannelCredentials()).
|
||||
GreeterClient greeter( |
||||
grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials())); |
||||
greeter.SayHello("World"); |
||||
greeter.SayHello("gRPC"); |
||||
return 0; |
||||
} |
@ -0,0 +1,143 @@ |
||||
// Copyright 2023 gRPC authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
#include <unordered_set> |
||||
|
||||
#include "absl/flags/flag.h" |
||||
#include "absl/flags/parse.h" |
||||
#include "absl/strings/str_format.h" |
||||
#include "absl/synchronization/mutex.h" |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
#include <grpcpp/health_check_service_interface.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); |
||||
|
||||
using grpc::ByteBuffer; |
||||
using grpc::CallbackGenericService; |
||||
using grpc::CallbackServerContext; |
||||
using grpc::GenericCallbackServerContext; |
||||
using grpc::ProtoBufferReader; |
||||
using grpc::ProtoBufferWriter; |
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerGenericBidiReactor; |
||||
using grpc::Status; |
||||
using grpc::StatusCode; |
||||
using helloworld::HelloReply; |
||||
using helloworld::HelloRequest; |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public CallbackGenericService { |
||||
ServerGenericBidiReactor* CreateReactor( |
||||
GenericCallbackServerContext* context) override { |
||||
if (context->method() == "/helloworld.Greeter/SayHello") { |
||||
// Let the SayHello reactor handle this now on.
|
||||
return new SayHelloReactor(); |
||||
} else { |
||||
// Forward this to the implementation of the base calss returning
|
||||
// UNIMPLEMENTED.
|
||||
return CallbackGenericService::CreateReactor(context); |
||||
} |
||||
} |
||||
|
||||
class SayHelloReactor : public ServerGenericBidiReactor { |
||||
public: |
||||
SayHelloReactor() { StartRead(&request_); } |
||||
|
||||
private: |
||||
Status OnSayHello(const HelloRequest& request, HelloReply* reply) { |
||||
if (request.name() == "") { |
||||
return Status(StatusCode::INVALID_ARGUMENT, "name is not specified"); |
||||
} |
||||
reply->set_message(absl::StrFormat("Hello %s", request.name())); |
||||
return Status::OK; |
||||
} |
||||
|
||||
void OnDone() override { delete this; } |
||||
void OnReadDone(bool ok) override { |
||||
if (!ok) { |
||||
return; |
||||
} |
||||
Status result; |
||||
// Deserialize a request message
|
||||
HelloRequest request; |
||||
result = grpc::GenericDeserialize<ProtoBufferReader, HelloRequest>( |
||||
&request_, &request); |
||||
if (!result.ok()) { |
||||
Finish(result); |
||||
return; |
||||
} |
||||
// Call the SayHello handler
|
||||
HelloReply reply; |
||||
result = OnSayHello(request, &reply); |
||||
if (!result.ok()) { |
||||
Finish(result); |
||||
return; |
||||
} |
||||
// Serialize a reply message
|
||||
bool own_buffer; |
||||
result = grpc::GenericSerialize<ProtoBufferWriter, HelloReply>( |
||||
reply, &response_, &own_buffer); |
||||
if (!result.ok()) { |
||||
Finish(result); |
||||
return; |
||||
} |
||||
StartWrite(&response_); |
||||
} |
||||
void OnWriteDone(bool ok) override { |
||||
Finish(ok ? Status::OK |
||||
: Status(StatusCode::UNKNOWN, "Unexpected failure")); |
||||
} |
||||
ByteBuffer request_; |
||||
ByteBuffer response_; |
||||
}; |
||||
|
||||
private: |
||||
absl::Mutex mu_; |
||||
}; |
||||
|
||||
void RunServer(uint16_t port) { |
||||
std::string server_address = absl::StrFormat("0.0.0.0:%d", port); |
||||
GreeterServiceImpl service; |
||||
grpc::EnableDefaultHealthCheckService(true); |
||||
ServerBuilder builder; |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterCallbackGenericService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
absl::ParseCommandLine(argc, argv); |
||||
RunServer(absl::GetFlag(FLAGS_port)); |
||||
return 0; |
||||
} |
@ -0,0 +1,29 @@ |
||||
# Copyright 2023 the gRPC authors. |
||||
# |
||||
# 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. |
||||
|
||||
licenses(["notice"]) |
||||
|
||||
cc_binary( |
||||
name = "orca_server", |
||||
srcs = ["orca_server.cc"], |
||||
defines = ["BAZEL_BUILD"], |
||||
deps = [ |
||||
"//:grpc++", |
||||
"//:grpcpp_orca_service", |
||||
"//examples/protos:helloworld_cc_grpc", |
||||
"@com_google_absl//absl/flags:flag", |
||||
"@com_google_absl//absl/flags:parse", |
||||
"@com_google_absl//absl/strings:str_format", |
||||
], |
||||
) |
@ -0,0 +1,46 @@ |
||||
# gRPC Custom Metrics Example |
||||
|
||||
You can find a complete set of instructions for building gRPC and running the |
||||
examples in the [C++ Quick Start][]. |
||||
|
||||
This example shows how to implement a server that provides custom metrics usable |
||||
by custom load balancing policies. |
||||
|
||||
Server needs to be setup with metrics recorder and Orca service for sending |
||||
these metrics to a client: |
||||
|
||||
```c++ |
||||
GreeterServiceImpl service; |
||||
// Setup custom metrics recording |
||||
auto server_metric_recorder = |
||||
grpc::experimental::ServerMetricRecorder::Create(); |
||||
grpc::experimental::OrcaService orca_service( |
||||
server_metric_recorder.get(), |
||||
grpc::experimental::OrcaService::Options().set_min_report_duration( |
||||
absl::Seconds(0.1))); |
||||
builder.RegisterService(&orca_service); |
||||
grpc::ServerBuilder::experimental_type(&builder).EnableCallMetricRecording( |
||||
nullptr); |
||||
``` |
||||
|
||||
Afterwards per-request metrics can be reported from the gRPC service |
||||
implementation using the metric recorder from the request context: |
||||
|
||||
```c++ |
||||
auto recorder = context->ExperimentalGetCallMetricRecorder(); |
||||
if (recorder == nullptr) { |
||||
return Status(grpc::StatusCode::INTERNAL, |
||||
"Unable to access metrics recorder. Make sure " |
||||
"EnableCallMetricRecording had been called."); |
||||
} |
||||
recorder->RecordCpuUtilizationMetric(0.5); |
||||
``` |
||||
|
||||
Out of band metrics can be reported using the `server_metric_recorder` |
||||
directly: |
||||
|
||||
```c++ |
||||
server_metric_recorder->SetCpuUtilization(0.75); |
||||
``` |
||||
|
||||
[C++ Quick Start]: https://grpc.io/docs/languages/cpp/quickstart |
@ -0,0 +1,101 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2023 gRPC authors. |
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
#include <cstddef> |
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include "absl/flags/flag.h" |
||||
#include "absl/flags/parse.h" |
||||
#include "absl/strings/str_format.h" |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
|
||||
#include <grpcpp/ext/call_metric_recorder.h> |
||||
#include <grpcpp/ext/orca_service.h> |
||||
#include <grpcpp/grpcpp.h> |
||||
#include <grpcpp/health_check_service_interface.h> |
||||
#include <grpcpp/support/status.h> |
||||
|
||||
using grpc::CallbackServerContext; |
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerUnaryReactor; |
||||
using grpc::Status; |
||||
using helloworld::Greeter; |
||||
using helloworld::HelloReply; |
||||
using helloworld::HelloRequest; |
||||
|
||||
ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::CallbackService { |
||||
ServerUnaryReactor* SayHello(CallbackServerContext* context, |
||||
const HelloRequest* request, |
||||
HelloReply* reply) override { |
||||
ServerUnaryReactor* reactor = context->DefaultReactor(); |
||||
// Obtain the call metric recorder and use it to report the number of
|
||||
// DB queries (custom cost metric) and CPU utilization.
|
||||
auto recorder = context->ExperimentalGetCallMetricRecorder(); |
||||
if (recorder == nullptr) { |
||||
reactor->Finish({grpc::StatusCode::INTERNAL, |
||||
"Unable to access metrics recorder. Make sure " |
||||
"EnableCallMetricRecording had been called."}); |
||||
return reactor; |
||||
} |
||||
recorder->RecordRequestCostMetric("db_queries", 10); |
||||
recorder->RecordCpuUtilizationMetric(0.5); |
||||
std::string prefix("Hello "); |
||||
reply->set_message(prefix + request->name()); |
||||
reactor->Finish(Status::OK); |
||||
return reactor; |
||||
} |
||||
}; |
||||
|
||||
void RunServer(uint16_t port) { |
||||
std::string server_address = absl::StrFormat("0.0.0.0:%d", port); |
||||
ServerBuilder builder; |
||||
GreeterServiceImpl service; |
||||
// Setup custom metrics recording. Note that this recorder may be use to send
|
||||
// the out-of-band metrics to the client.
|
||||
auto server_metric_recorder = |
||||
grpc::experimental::ServerMetricRecorder::Create(); |
||||
grpc::experimental::OrcaService orca_service( |
||||
server_metric_recorder.get(), |
||||
grpc::experimental::OrcaService::Options().set_min_report_duration( |
||||
absl::Seconds(0.1))); |
||||
builder.RegisterService(&orca_service); |
||||
grpc::ServerBuilder::experimental_type(&builder).EnableCallMetricRecording( |
||||
server_metric_recorder.get()); |
||||
// Resume setting up gRPC server as usual
|
||||
grpc::EnableDefaultHealthCheckService(true); |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
absl::ParseCommandLine(argc, argv); |
||||
RunServer(absl::GetFlag(FLAGS_port)); |
||||
return 0; |
||||
} |