add jaeger support, link hot container & req span (#840)

* add jaeger support, link hot container & req span

* adds jaeger support now with FN_JAEGER_URL, there's a simple tutorial in the
operating/metrics.md file now and it's pretty easy to get up and running.
* links a hot request span to a hot container span. when we change this to
sample at a lower ratio we'll need to finagle the hot container span to always
sample or something, otherwise we'll hide that info. at least, since we're
sampling at 100% for now if this is flipped on, can see freeze/unfreeze etc.
if they hit. this is useful for debugging. note that zipkin's exporter does
not follow the link at all, hence jaeger... and they're backed by the Cloud
Empire now (CNCF) so we'll probably use it anyway.

* vendor: add thrift for jaeger
This commit is contained in:
Reed Allman
2018-03-13 15:57:12 -07:00
committed by GitHub
parent a7347a88b7
commit 9eaf824398
2953 changed files with 2334535 additions and 35 deletions

View File

@@ -0,0 +1,16 @@
[package]
name = "thrift-tutorial"
version = "0.1.0"
license = "Apache-2.0"
authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
exclude = ["Makefile*", "shared.rs", "tutorial.rs"]
publish = false
[dependencies]
clap = "<2.28.0"
ordered-float = "0.3.0"
try_from = "0.2.0"
[dependencies.thrift]
path = "../../lib/rs"

View File

@@ -0,0 +1,52 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
THRIFT = $(top_builddir)/compiler/cpp/thrift
gen-rs/tutorial.rs gen-rs/shared.rs: $(top_srcdir)/tutorial/tutorial.thrift
$(THRIFT) -out src --gen rs -r $<
all-local: gen-rs/tutorial.rs
$(CARGO) build
[ -d bin ] || mkdir bin
cp target/debug/tutorial_server bin/tutorial_server
cp target/debug/tutorial_client bin/tutorial_client
check: all
tutorialserver: all
bin/tutorial_server
tutorialclient: all
bin/tutorial_client
clean-local:
$(CARGO) clean
-$(RM) Cargo.lock
-$(RM) src/shared.rs
-$(RM) src/tutorial.rs
-$(RM) -r bin
EXTRA_DIST = \
Cargo.toml \
src/lib.rs \
src/bin/tutorial_server.rs \
src/bin/tutorial_client.rs \
README.md

317
vendor/git.apache.org/thrift.git/tutorial/rs/README.md generated vendored Normal file
View File

@@ -0,0 +1,317 @@
# Rust Language Bindings for Thrift
## Getting Started
1. Get the [Thrift compiler](https://thrift.apache.org).
2. Add the following crates to your `Cargo.toml`.
```toml
thrift = "x.y.z" # x.y.z is the version of the thrift compiler
ordered_float = "0.3.0"
try_from = "0.2.0"
```
3. Add the same crates to your `lib.rs` or `main.rs`.
```rust
extern crate ordered_float;
extern crate thrift;
extern crate try_from;
```
4. Generate Rust sources for your IDL (for example, `Tutorial.thrift`).
```shell
thrift -out my_rust_program/src --gen rs -r Tutorial.thrift
```
5. Use the generated source in your code.
```rust
// add extern crates here, or in your lib.rs
extern crate ordered_float;
extern crate thrift;
extern crate try_from;
// generated Rust module
use tutorial;
use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol};
use thrift::protocol::{TInputProtocol, TOutputProtocol};
use thrift::transport::{TFramedReadTransport, TFramedWriteTransport};
use thrift::transport::{TIoChannel, TTcpChannel};
use tutorial::{CalculatorSyncClient, TCalculatorSyncClient};
use tutorial::{Operation, Work};
fn main() {
match run() {
Ok(()) => println!("client ran successfully"),
Err(e) => {
println!("client failed with {:?}", e);
std::process::exit(1);
}
}
}
fn run() -> thrift::Result<()> {
//
// build client
//
println!("connect to server on 127.0.0.1:9090");
let mut c = TTcpTransport::new();
c.open("127.0.0.1:9090")?;
let (i_chan, o_chan) = c.split()?;
let i_prot = TCompactInputProtocol::new(
TFramedReadTransport::new(i_chan)
);
let o_prot = TCompactOutputProtocol::new(
TFramedWriteTransport::new(o_chan)
);
let client = CalculatorSyncClient::new(i_prot, o_prot);
//
// alright! - let's make some calls
//
// two-way, void return
client.ping()?;
// two-way with some return
let res = client.calculate(
72,
Work::new(7, 8, Operation::MULTIPLY, None)
)?;
println!("multiplied 7 and 8, got {}", res);
// two-way and returns a Thrift-defined exception
let res = client.calculate(
77,
Work::new(2, 0, Operation::DIVIDE, None)
);
match res {
Ok(v) => panic!("shouldn't have succeeded with result {}", v),
Err(e) => println!("divide by zero failed with {:?}", e),
}
// one-way
client.zip()?;
// done!
Ok(())
}
```
## Code Generation
### Thrift Files and Generated Modules
The Thrift code generator takes each Thrift file and generates a Rust module
with the same name snake-cased. For example, running the compiler on
`ThriftTest.thrift` creates `thrift_test.rs`. To use these generated files add
`mod ...` and `use ...` declarations to your `lib.rs` or `main.rs` - one for
each generated file.
### Results and Errors
The Thrift runtime library defines a `thrift::Result` and a `thrift::Error` type,
both of which are used throught the runtime library and in all generated code.
Conversions are defined from `std::io::Error`, `str` and `String` into
`thrift::Error`.
### Thrift Type and their Rust Equivalents
Thrift defines a number of types, each of which is translated into its Rust
equivalent by the code generator.
* Primitives (bool, i8, i16, i32, i64, double, string, binary)
* Typedefs
* Enums
* Containers
* Structs
* Unions
* Exceptions
* Services
* Constants (primitives, containers, structs)
In addition, unless otherwise noted, thrift includes are translated into
`use ...` statements in the generated code, and all declarations, parameters,
traits and types in the generated code are namespaced appropriately.
The following subsections cover each type and their generated Rust equivalent.
### Primitives
Thrift primitives have straightforward Rust equivalents.
* bool: `bool`
* i8: `i8`
* i16: `i16`
* i32: `i32`
* i64: `i64`
* double: `OrderedFloat<f64>`
* string: `String`
* binary: `Vec<u8>`
### Typedefs
A typedef is translated to a `pub type` declaration.
```thrift
typedef i64 UserId
typedef map<string, UserId> MapType
```
```rust
pub type UserId = i64;
pub type MapType = BTreeMap<String, Bonk>;
```
### Enums
A Thrift enum is represented as a Rust enum, and each variant is transcribed 1:1.
```thrift
enum Numberz
{
ONE = 1,
TWO,
THREE,
FIVE = 5,
SIX,
EIGHT = 8
}
```
```rust
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Numberz {
ONE = 1,
TWO = 2,
THREE = 3,
FIVE = 5,
SIX = 6,
EIGHT = 8,
}
impl TryFrom<i32> for Numberz {
// ...
}
```
### Containers
Thrift has three container types: list, set and map. They are translated into
Rust `Vec`, `BTreeSet` and `BTreeMap` respectively. Any Thrift type (this
includes structs, enums and typedefs) can be a list/set element or a map
key/value.
#### List
```thrift
list <i32> numbers
```
```rust
numbers: Vec<i32>
```
#### Set
```thrift
set <i32> numbers
```
```rust
numbers: BTreeSet<i32>
```
#### Map
```thrift
map <string, i32> numbers
```
```rust
numbers: BTreeMap<String, i32>
```
### Structs
A Thrift struct is represented as a Rust struct, and each field transcribed 1:1.
```thrift
struct CrazyNesting {
1: string string_field,
2: optional set<Insanity> set_field,
3: required list<
map<set<i32>, map<i32,set<list<map<Insanity,string>>>>>
>
4: binary binary_field
}
```
```rust
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct CrazyNesting {
pub string_field: Option<String>,
pub set_field: Option<BTreeSet<Insanity>>,
pub list_field: Vec<
BTreeMap<
BTreeSet<i32>,
BTreeMap<i32, BTreeSet<Vec<BTreeMap<Insanity, String>>>>
>
>,
pub binary_field: Option<Vec<u8>>,
}
impl CrazyNesting {
pub fn read_from_in_protocol(i_prot: &mut TInputProtocol)
->
thrift::Result<CrazyNesting> {
// ...
}
pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol)
->
thrift::Result<()> {
// ...
}
}
```
##### Optionality
Thrift has 3 "optionality" types:
1. Required
2. Optional
3. Default
The Rust code generator encodes *Required* fields as the bare type itself, while
*Optional* and *Default* fields are encoded as `Option<TypeName>`.
```thrift
struct Foo {
1: required string bar // 1. required
2: optional string baz // 2. optional
3: string qux // 3. default
}
```
```rust
pub struct Foo {
bar: String, // 1. required
baz: Option<String>, // 2. optional
qux: Option<String>, // 3. default
}
```
## Known Issues
* Struct constants are not supported
* Map, list and set constants require a const holder struct

View File

@@ -0,0 +1,131 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
#[macro_use]
extern crate clap;
extern crate thrift;
extern crate thrift_tutorial;
use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol};
use thrift::transport::{ReadHalf, TFramedReadTransport, TFramedWriteTransport, TIoChannel,
TTcpChannel, WriteHalf};
use thrift_tutorial::shared::TSharedServiceSyncClient;
use thrift_tutorial::tutorial::{CalculatorSyncClient, Operation, TCalculatorSyncClient, Work};
fn main() {
match run() {
Ok(()) => println!("tutorial client ran successfully"),
Err(e) => {
println!("tutorial client failed with error {:?}", e);
std::process::exit(1);
}
}
}
fn run() -> thrift::Result<()> {
let options = clap_app!(rust_tutorial_client =>
(version: "0.1.0")
(author: "Apache Thrift Developers <dev@thrift.apache.org>")
(about: "Thrift Rust tutorial client")
(@arg host: --host +takes_value "host on which the tutorial server listens")
(@arg port: --port +takes_value "port on which the tutorial server listens")
);
let matches = options.get_matches();
// get any passed-in args or the defaults
let host = matches.value_of("host").unwrap_or("127.0.0.1");
let port = value_t!(matches, "port", u16).unwrap_or(9090);
// build our client and connect to the host:port
let mut client = new_client(host, port)?;
// alright!
// let's start making some calls
// let's start with a ping; the server should respond
println!("ping!");
client.ping()?;
// simple add
println!("add");
let res = client.add(1, 2)?;
println!("added 1, 2 and got {}", res);
let logid = 32;
// let's do...a multiply!
let res = client
.calculate(logid, Work::new(7, 8, Operation::MULTIPLY, None))?;
println!("multiplied 7 and 8 and got {}", res);
// let's get the log for it
let res = client.get_struct(32)?;
println!("got log {:?} for operation {}", res, logid);
// ok - let's be bad :(
// do a divide by 0
// logid doesn't matter; won't be recorded
let res = client.calculate(77, Work::new(2, 0, Operation::DIVIDE, "we bad".to_owned()));
// we should have gotten an exception back
match res {
Ok(v) => panic!("should not have succeeded with result {}", v),
Err(e) => println!("divide by zero failed with error {:?}", e),
}
// let's do a one-way call
println!("zip");
client.zip()?;
// and then close out with a final ping
println!("ping!");
client.ping()?;
Ok(())
}
type ClientInputProtocol = TCompactInputProtocol<TFramedReadTransport<ReadHalf<TTcpChannel>>>;
type ClientOutputProtocol = TCompactOutputProtocol<TFramedWriteTransport<WriteHalf<TTcpChannel>>>;
fn new_client
(
host: &str,
port: u16,
) -> thrift::Result<CalculatorSyncClient<ClientInputProtocol, ClientOutputProtocol>> {
let mut c = TTcpChannel::new();
// open the underlying TCP stream
println!("connecting to tutorial server on {}:{}", host, port);
c.open(&format!("{}:{}", host, port))?;
// clone the TCP channel into two halves, one which
// we'll use for reading, the other for writing
let (i_chan, o_chan) = c.split()?;
// wrap the raw sockets (slow) with a buffered transport of some kind
let i_tran = TFramedReadTransport::new(i_chan);
let o_tran = TFramedWriteTransport::new(o_chan);
// now create the protocol implementations
let i_prot = TCompactInputProtocol::new(i_tran);
let o_prot = TCompactOutputProtocol::new(o_tran);
// we're done!
Ok(CalculatorSyncClient::new(i_prot, o_prot))
}

View File

@@ -0,0 +1,176 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
#[macro_use]
extern crate clap;
extern crate thrift;
extern crate thrift_tutorial;
use std::collections::HashMap;
use std::convert::{From, Into};
use std::default::Default;
use std::sync::Mutex;
use thrift::protocol::{TCompactInputProtocolFactory, TCompactOutputProtocolFactory};
use thrift::server::TServer;
use thrift::transport::{TFramedReadTransportFactory, TFramedWriteTransportFactory};
use thrift_tutorial::shared::{SharedServiceSyncHandler, SharedStruct};
use thrift_tutorial::tutorial::{CalculatorSyncHandler, CalculatorSyncProcessor};
use thrift_tutorial::tutorial::{InvalidOperation, Operation, Work};
fn main() {
match run() {
Ok(()) => println!("tutorial server ran successfully"),
Err(e) => {
println!("tutorial server failed with error {:?}", e);
std::process::exit(1);
}
}
}
fn run() -> thrift::Result<()> {
let options = clap_app!(rust_tutorial_server =>
(version: "0.1.0")
(author: "Apache Thrift Developers <dev@thrift.apache.org>")
(about: "Thrift Rust tutorial server")
(@arg port: --port +takes_value "port on which the tutorial server listens")
);
let matches = options.get_matches();
let port = value_t!(matches, "port", u16).unwrap_or(9090);
let listen_address = format!("127.0.0.1:{}", port);
println!("binding to {}", listen_address);
let i_tran_fact = TFramedReadTransportFactory::new();
let i_prot_fact = TCompactInputProtocolFactory::new();
let o_tran_fact = TFramedWriteTransportFactory::new();
let o_prot_fact = TCompactOutputProtocolFactory::new();
// demux incoming messages
let processor = CalculatorSyncProcessor::new(CalculatorServer { ..Default::default() });
// create the server and start listening
let mut server = TServer::new(
i_tran_fact,
i_prot_fact,
o_tran_fact,
o_prot_fact,
processor,
10,
);
server.listen(&listen_address)
}
/// Handles incoming Calculator service calls.
struct CalculatorServer {
log: Mutex<HashMap<i32, SharedStruct>>,
}
impl Default for CalculatorServer {
fn default() -> CalculatorServer {
CalculatorServer { log: Mutex::new(HashMap::new()) }
}
}
// since Calculator extends SharedService we have to implement the
// handler for both traits.
//
// SharedService handler
impl SharedServiceSyncHandler for CalculatorServer {
fn handle_get_struct(&self, key: i32) -> thrift::Result<SharedStruct> {
let log = self.log.lock().unwrap();
log.get(&key)
.cloned()
.ok_or_else(|| format!("could not find log for key {}", key).into())
}
}
// Calculator handler
impl CalculatorSyncHandler for CalculatorServer {
fn handle_ping(&self) -> thrift::Result<()> {
println!("pong!");
Ok(())
}
fn handle_add(&self, num1: i32, num2: i32) -> thrift::Result<i32> {
println!("handling add: n1:{} n2:{}", num1, num2);
Ok(num1 + num2)
}
fn handle_calculate(&self, logid: i32, w: Work) -> thrift::Result<i32> {
println!("handling calculate: l:{}, w:{:?}", logid, w);
let res = if let Some(ref op) = w.op {
if w.num1.is_none() || w.num2.is_none() {
Err(
InvalidOperation {
what_op: Some(*op as i32),
why: Some("no operands specified".to_owned()),
},
)
} else {
// so that I don't have to call unwrap() multiple times below
let num1 = w.num1.as_ref().expect("operands checked");
let num2 = w.num2.as_ref().expect("operands checked");
match *op {
Operation::ADD => Ok(num1 + num2),
Operation::SUBTRACT => Ok(num1 - num2),
Operation::MULTIPLY => Ok(num1 * num2),
Operation::DIVIDE => {
if *num2 == 0 {
Err(
InvalidOperation {
what_op: Some(*op as i32),
why: Some("divide by 0".to_owned()),
},
)
} else {
Ok(num1 / num2)
}
}
}
}
} else {
Err(InvalidOperation::new(None, "no operation specified".to_owned()),)
};
// if the operation was successful log it
if let Ok(ref v) = res {
let mut log = self.log.lock().unwrap();
log.insert(logid, SharedStruct::new(logid, format!("{}", v)));
}
// the try! macro automatically maps errors
// but, since we aren't using that here we have to map errors manually
//
// exception structs defined in the IDL have an auto-generated
// impl of From::from
res.map_err(From::from)
}
fn handle_zip(&self) -> thrift::Result<()> {
println!("handling zip");
Ok(())
}
}

View File

@@ -0,0 +1,23 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
extern crate ordered_float;
extern crate thrift;
extern crate try_from;
pub mod shared;
pub mod tutorial;