Compare commits

...
Author SHA1 Message Date
Jon Gjengset b4cb3226ab Bump 0.1 versions for latest changes (#1240)
[ci-release]
2019-07-03 09:21:33 -07:00
Eliza Weisman 4446eb4db8 chore: remove tokio-trace, add "Related Projects" to README (v0.1) (#1223)
* chore: remove `tokio-trace`, add "Related Projects" to README (#1221)

The `tokio-trace` and `tokio-trace-core` crates have been renamed to
`tracing` and `tracing-core`, and moved to their own repository
(`tokio-rs/tracing`).

This branch removes `tokio-trace` and `tokio-trace-core` from the
`tokio` repository. In addition, I've added a "Related Projects" section
to the root README, which lists `tracing` (as well as  `mio`, and
`bytes`) as other libraries maintained by the Tokio project. I thought
that this would help folks looking for `tokio-trace` here find it in its
new home.

In addition, it changes `tokio` to depend on `tracing-core` rather than
`tokio-trace-core`.

Closes #1159

Signed-off-by: Eliza Weisman <[email protected]>

* Remove erroneous add of `tokio-macros`

* Some more tokio-trace remnants

* Remove tokio-trace remnants from Cirrus CI

* disable tracing-core feature by default

It can't build on Rust 1.26.0

Signed-off-by: Eliza Weisman <[email protected]>

* fix feature flagging

Signed-off-by: Eliza Weisman <[email protected]>
2019-07-01 16:18:12 -07:00
Sean McArthur cad0c35623 executor: add executor::exit (#1155)
This allows blocking on executors from within a `threadpool::blocking` call.
2019-06-24 09:22:54 -07:00
Kevin Leimkuhler 5dcb379f6d Bump tokio-sync to 0.1.6 (#1123) 2019-06-05 12:19:06 -07:00
Kevin Leimkuhler 970f75f830 sync: Add Sync impl for Lock (#1117) 2019-06-04 17:04:35 -07:00
Carl Lerche 01052f930a Bump tokio version to v0.1.21. (#1113) 2019-05-30 14:39:30 -07:00
Lucio Franco 940f2c3431 Update tokio-trace-core to 0.2 (#1111)
Also includes 1b498e8aa2
2019-05-30 11:33:55 -07:00
Carl Lerche 475dabe96d Release tokio v0.1.20, tokio-timer v0.2.21, and remove async-await-preview feature. (#1089)
The `async-await-preview` feature is removed as 0.1 will no longer track
Rust nightly.

This also bumps:
- tokio-timer (0.2.11).
2019-05-14 11:21:24 -07:00
Carl Lerche 951f2fd910 test: re-export macro dependencies (#1077)
Callers may not always have `futures` available at the root of the
crate. Re-exporting dependencies makes them available to the macro at a
deterministic location.
2019-05-03 20:43:40 -07:00
Carl Lerche 4ef736b9d5 async-await: add current_thread::Runtime::block_on_async (#1072)
This function is used by the Tokio macros introduced by #1058  but was
omitted from the PR.
2019-04-30 19:55:22 -07:00
Steven Fackler 219f24cbf1 timer: Replace Handle::deadline with Handle::timeout (#1074)
Deadline was deprecated a while ago and replaced with Timeout, but the
methods on Handle got missed.

Fixes #1071
2019-04-30 10:29:54 -07:00
Carl Lerche ea282efb2e ci: fix isRelease condition (#1066) 2019-04-29 10:37:00 -07:00
Michal 'vorner' Vaner 042224d33c signal: Smaller dependency (#1069)
The signal-hook library got split into lower-level and higher-level
parts. The tokio-signal uses only API from the lower-level one, so it
can depend on it directly.

The only effect of this change is smaller amount of compiled (and
unused) code during compilation. There's no change in the code actually
used.
2019-04-28 19:12:40 -07:00
Ian Hamlin 927eb80ad4 Fix an error in the mit-url in the README.md (#1068) 2019-04-27 12:56:40 -07:00
Carl Lerche 6a8934e897 Fix threadpool dependency (#1061) 2019-04-25 22:23:24 -04:00
Carl Lerche 0e400af78c Async/await polish (#1058)
A general refresh of Tokio's experimental async / await support.
2019-04-25 22:22:32 -04:00
Carl Lerche df702130d6 tcp: fix some tests that spuriously fail (#1060)
This does not remove all cases of using a fixed port in doc tests, but
removing some should reduce the likelihood of spurious failures.
2019-04-25 12:01:39 -07:00
Carl Lerche 949adbb887 chore: remember to remove path deps on release (#1057) 2019-04-24 10:42:39 -07:00
Ryan Dahl b2b796a228 rt: forward panic_handler to tokio::runtime::Builder (#1055) 2019-04-24 10:41:42 -07:00
Igor Gnatenko abb014efc2 tokio: Bump min version of tokio-sync (#1054)
It is needed for lock functionality which tokio now uses.
2019-04-24 08:24:59 -07:00
Lucio Franco e5cf0cc717 Introduce tokio-test crate (#1030) 2019-04-23 20:17:57 -07:00
145 changed files with 1402 additions and 9383 deletions
+2 -4
View File
@@ -31,13 +31,11 @@ task:
folder: $HOME/.cargo/registry
test_script:
- . $HOME/.cargo/env
- cargo test --all --no-fail-fast
- (cd tokio-trace/test-log-support && cargo test)
- (cd tokio-trace/test_static_max_level_features && cargo test)
- cargo test --all
- cargo doc --all
i686_test_script:
- . $HOME/.cargo/env
- |
cargo test --all --exclude tokio-tls --no-fail-fast --target i686-unknown-freebsd
cargo test --all --exclude tokio-tls --exclude tokio-macros --target i686-unknown-freebsd
before_cache_script:
- rm -rf $HOME/.cargo/registry/index
+3 -3
View File
@@ -2,22 +2,22 @@
members = [
"tokio",
"tokio-async-await",
"tokio-buf",
"tokio-codec",
"tokio-current-thread",
"tokio-executor",
"tokio-fs",
"tokio-futures",
"tokio-io",
"tokio-macros",
"tokio-reactor",
"tokio-signal",
"tokio-sync",
"tokio-test",
"tokio-threadpool",
"tokio-timer",
"tokio-tcp",
"tokio-tls",
"tokio-trace",
"tokio-trace/tokio-trace-core",
"tokio-udp",
"tokio-uds",
]
+30 -10
View File
@@ -20,7 +20,7 @@ the Rust programming language. It is:
[crates-badge]: https://img.shields.io/crates/v/tokio.svg
[crates-url]: https://crates.io/crates/tokio
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
[mit-url]: LICENSE-MIT
[mit-url]: LICENSE
[azure-badge]: https://dev.azure.com/tokio-rs/Tokio/_apis/build/status/tokio-rs.tokio?branchName=master
[azure-url]: https://dev.azure.com/tokio-rs/Tokio/_build/latest?definitionId=1&branchName=master
[gitter-badge]: https://img.shields.io/gitter/room/tokio-rs/tokio.svg
@@ -28,7 +28,7 @@ the Rust programming language. It is:
[Website](https://tokio.rs) |
[Guides](https://tokio.rs/docs/getting-started/hello-world/) |
[API Docs](https://docs.rs/tokio/0.1.19/tokio) |
[API Docs](https://docs.rs/tokio/0.1.20/tokio) |
[Chat](https://gitter.im/tokio-rs/tokio)
The API docs for the master branch are published [here][master-dox].
@@ -49,9 +49,9 @@ level, it provides a few major components:
These components provide the runtime components necessary for building
an asynchronous application.
[net]: https://docs.rs/tokio/0.1.19/tokio/net/index.html
[reactor]: https://docs.rs/tokio/0.1.19/tokio/reactor/index.html
[scheduler]: https://docs.rs/tokio/0.1.19/tokio/runtime/index.html
[net]: https://docs.rs/tokio/0.1.20/tokio/net/index.html
[reactor]: https://docs.rs/tokio/0.1.20/tokio/reactor/index.html
[scheduler]: https://docs.rs/tokio/0.1.20/tokio/runtime/index.html
## Example
@@ -126,10 +126,6 @@ have greater guarantees of stability.
The crates included as part of Tokio are:
* [`tokio-async-await`]: Experimental `async` / `await` support.
* [`tokio-codec`]: Utilities for encoding and decoding protocol frames.
* [`tokio-current-thread`]: Schedule the execution of futures on the current
thread.
@@ -137,8 +133,14 @@ The crates included as part of Tokio are:
* [`tokio-fs`]: Filesystem (and standard in / out) APIs.
* [`tokio-futures`]: Experimental `std::future::Future` and `async` / `await` support.
* [`tokio-codec`]: Utilities for encoding and decoding protocol frames.
* [`tokio-io`]: Asynchronous I/O related traits and utilities.
* [`tokio-macros`]: Macros for usage with Tokio.
* [`tokio-reactor`]: Event loop that drives I/O resources (like TCP and UDP
sockets).
@@ -154,12 +156,13 @@ The crates included as part of Tokio are:
* [`tokio-uds`]: Unix Domain Socket bindings for use with `tokio-io` and
`tokio-reactor`.
[`tokio-async-await`]: tokio-async-await
[`tokio-codec`]: tokio-codec
[`tokio-current-thread`]: tokio-current-thread
[`tokio-executor`]: tokio-executor
[`tokio-fs`]: tokio-fs
[`tokio-futures`]: tokio-futures
[`tokio-io`]: tokio-io
[`tokio-macros`]: tokio-macros
[`tokio-reactor`]: tokio-reactor
[`tokio-tcp`]: tokio-tcp
[`tokio-threadpool`]: tokio-threadpool
@@ -167,6 +170,23 @@ The crates included as part of Tokio are:
[`tokio-udp`]: tokio-udp
[`tokio-uds`]: tokio-uds
## Related Projects
In addition to the crates in this repository, the Tokio project also maintains
several other libraries, including:
* [`tracing`] (formerly `tokio-trace`): A framework for application-level
tracing and async-aware diagnostics.
* [`mio`]: A low-level, cross-platform abstraction over OS I/O APIs that powers
`tokio`.
* [`bytes`]: Utilities for working with bytes, including efficient byte buffers.
[`tracing`]: https://github.com/tokio-rs/tracing
[`mio`]: https://github.com/tokio-rs/mio
[`bytes`]: https://github.com/tokio-rs/bytes
## Supported Rust Versions
Tokio is built against the latest stable, nightly, and beta Rust releases. The
+2
View File
@@ -0,0 +1,2 @@
[build]
target-dir = "../target"
+49
View File
@@ -0,0 +1,49 @@
[package]
name = "examples"
edition = "2018"
version = "0.1.0"
authors = ["Carl Lerche <[email protected]>"]
license = "MIT"
# Break out of the parent workspace
[workspace]
[[bin]]
name = "chat"
path = "src/chat.rs"
[[bin]]
name = "echo_client"
path = "src/echo_client.rs"
[[bin]]
name = "echo_server"
path = "src/echo_server.rs"
[[bin]]
name = "hyper"
path = "src/hyper.rs"
[dependencies]
tokio = { version = "0.1.18", features = ["async-await-preview"] }
futures = "0.1.23"
bytes = "0.4.9"
hyper = "0.12.8"
# Avoid using crates.io for Tokio dependencies
[patch.crates-io]
tokio = { path = "../tokio" }
tokio-codec = { path = "../tokio-codec" }
tokio-current-thread = { path = "../tokio-current-thread" }
tokio-executor = { path = "../tokio-executor" }
tokio-fs = { path = "../tokio-fs" }
tokio-futures = { path = "../tokio-futures" }
tokio-io = { path = "../tokio-io" }
tokio-reactor = { path = "../tokio-reactor" }
tokio-signal = { path = "../tokio-signal" }
tokio-tcp = { path = "../tokio-tcp" }
tokio-threadpool = { path = "../tokio-threadpool" }
tokio-timer = { path = "../tokio-timer" }
tokio-tls = { path = "../tokio-tls" }
tokio-udp = { path = "../tokio-udp" }
tokio-uds = { path = "../tokio-uds" }
@@ -1,9 +1,6 @@
#![feature(await_macro, async_await, futures_api)]
#[macro_use]
extern crate tokio;
extern crate futures; // v0.1
#![feature(await_macro, async_await)]
use tokio::await;
use tokio::codec::{LinesCodec, Decoder};
use tokio::net::{TcpListener, TcpStream};
use tokio::prelude::*;
@@ -95,7 +92,8 @@ async fn process(stream: TcpStream, state: Arc<Mutex<Shared>>) -> io::Result<()>
Ok(())
}
fn main() {
#[tokio::main]
async fn main() {
// Create the shared state. This is how all the peers communicate.
//
// The server task will hold a handle to this. For every new client, the
@@ -113,23 +111,21 @@ fn main() {
println!("server running on localhost:6142");
// Start the Tokio runtime.
tokio::run_async(async move {
let mut incoming = listener.incoming();
let mut incoming = listener.incoming();
while let Some(stream) = await!(incoming.next()) {
let stream = match stream {
Ok(stream) => stream,
Err(_) => continue,
};
while let Some(stream) = await!(incoming.next()) {
let stream = match stream {
Ok(stream) => stream,
Err(_) => continue,
};
let state = state.clone();
let state = state.clone();
tokio::spawn_async(async move {
if let Err(_) = await!(process(stream, state)) {
eprintln!("failed to process connection");
}
});
}
});
tokio::spawn_async(async move {
if let Err(_) = await!(process(stream, state)) {
eprintln!("failed to process connection");
}
});
}
}
@@ -1,8 +1,6 @@
#![feature(await_macro, async_await, futures_api)]
#[macro_use]
extern crate tokio;
#![feature(await_macro, async_await)]
use tokio::await;
use tokio::net::TcpStream;
use tokio::prelude::*;
@@ -36,7 +34,8 @@ async fn run_client(addr: &SocketAddr) -> io::Result<()> {
Ok(())
}
fn main() {
#[tokio::main]
async fn main() {
use std::env;
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
@@ -44,10 +43,8 @@ fn main() {
// Connect to the echo serveer
tokio::run_async(async move {
match await!(run_client(&addr)) {
Ok(_) => println!("done."),
Err(e) => eprintln!("echo client failed; error = {:?}", e),
}
});
match await!(run_client(&addr)) {
Ok(_) => println!("done."),
Err(e) => eprintln!("echo client failed; error = {:?}", e),
}
}
@@ -1,8 +1,6 @@
#![feature(await_macro, async_await, futures_api)]
#[macro_use]
extern crate tokio;
#![feature(await_macro, async_await)]
use tokio::await;
use tokio::net::{TcpListener, TcpStream};
use tokio::prelude::*;
@@ -24,7 +22,8 @@ fn handle(mut stream: TcpStream) {
});
}
fn main() {
#[tokio::main]
async fn main() {
use std::env;
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
@@ -34,12 +33,10 @@ fn main() {
let listener = TcpListener::bind(&addr).unwrap();
println!("Listening on: {}", addr);
tokio::run_async(async {
let mut incoming = listener.incoming();
let mut incoming = listener.incoming();
while let Some(stream) = await!(incoming.next()) {
let stream = stream.unwrap();
handle(stream);
}
});
while let Some(stream) = await!(incoming.next()) {
let stream = stream.unwrap();
handle(stream);
}
}
+29
View File
@@ -0,0 +1,29 @@
#![feature(await_macro, async_await)]
use tokio::await;
use tokio::prelude::*;
use hyper::Client;
use std::time::Duration;
use std::str;
#[tokio::main]
async fn main() {
let client = Client::new();
let uri = "http://httpbin.org/ip".parse().unwrap();
let response = await!({
client.get(uri)
.timeout(Duration::from_secs(10))
}).unwrap();
println!("Response: {}", response.status());
let mut body = response.into_body();
while let Some(chunk) = await!(body.next()) {
let chunk = chunk.unwrap();
println!("chunk = {}", str::from_utf8(&chunk[..]).unwrap());
}
}
+22
View File
@@ -0,0 +1,22 @@
#![feature(await_macro, async_await)]
use tokio::await;
use tokio::timer::Delay;
use std::time::{Duration, Instant};
#[tokio::test]
async fn success_no_async() {
assert!(true);
}
#[tokio::test]
#[should_panic]
async fn fail_no_async() {
assert!(false);
}
#[tokio::test]
async fn use_timer() {
let when = Instant::now() + Duration::from_millis(10);
await!(Delay::new(when));
}
+10 -17
View File
@@ -1,5 +1,5 @@
trigger: ["master"]
pr: ["master"]
trigger: ["master", "v0.1.x"]
pr: ["master", "v0.1.x"]
jobs:
# Check formatting
@@ -45,10 +45,7 @@ jobs:
- tokio-sync
- tokio-threadpool
- tokio-timer
- tokio-trace
- tokio-trace/tokio-trace-core
- tokio-trace/test-log-support
- tokio-trace/test_static_max_level_features
- tokio-test
- template: ci/azure-cargo-check.yml
parameters:
@@ -67,20 +64,16 @@ jobs:
- udp
- uds
- sync
- experimental-tracing
tokio-buf:
- util
# Check async / await
- template: ci/azure-cargo-check.yml
# Run async-await tests
- template: ci/azure-test-nightly.yml
parameters:
name: async_await
displayName: Async / Await
rust: nightly-2019-04-22
noDefaultFeatures: ''
benches: true
crates:
tokio:
- async-await-preview
name: test_nightly
displayName: Test Async / Await
rust: nightly-2019-04-25
# Try cross compiling
- template: ci/azure-cross-compile.yml
@@ -112,7 +105,7 @@ jobs:
- test_sub_cross
- test_linux
- features
- async_await
- test_nightly
- cross_32bit_linux
- minrust
- tsan
-4
View File
@@ -27,7 +27,3 @@ jobs:
- script: cargo check ${{ parameters.noDefaultFeatures }} --features ${{ feature }}
displayName: Check `${{ crate.key }}`, features = ${{ feature }}
workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }}
- ${{ if parameters.benches }}:
- script: cargo check --benches --all
displayName: Check benchmarks
+3
View File
@@ -8,6 +8,9 @@ jobs:
parameters:
rust_version: stable
- script: sudo apt-get update
displayName: "apt-get update"
- script: sudo apt-get install gcc-multilib
displayName: "Install gcc-multilib"
+9 -3
View File
@@ -2,7 +2,10 @@ steps:
# Linux and macOS.
- script: |
set -e
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUSTUP_TOOLCHAIN
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none
export PATH=$PATH:$HOME/.cargo/bin
rustup toolchain install $RUSTUP_TOOLCHAIN
rustup default $RUSTUP_TOOLCHAIN
echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin"
env:
RUSTUP_TOOLCHAIN: ${{parameters.rust_version}}
@@ -11,13 +14,16 @@ steps:
# Windows.
- script: |
echo "windows"
curl -sSf -o rustup-init.exe https://win.rustup.rs
rustup-init.exe -y --default-toolchain %RUSTUP_TOOLCHAIN%
rustup-init.exe -y --default-toolchain none
set PATH=%PATH%;%USERPROFILE%\.cargo\bin
rustup toolchain install %RUSTUP_TOOLCHAIN%
rustup default %RUSTUP_TOOLCHAIN%
echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin"
env:
RUSTUP_TOOLCHAIN: ${{parameters.rust_version}}
displayName: "Install rust (windows)"
displayName: Install rust (windows)
condition: eq(variables['Agent.OS'], 'Windows_NT')
# All platforms.
+1 -1
View File
@@ -2,7 +2,7 @@ steps:
- bash: |
set -e
if git log --no-merges -1 --format='%s' | grep -q '[ci-release]'; then
if git log --no-merges -1 --format='%B' | grep -qF '[ci-release]'; then
echo "##vso[task.setvariable variable=isRelease]true"
fi
failOnStderr: true
+19
View File
@@ -0,0 +1,19 @@
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
pool:
vmImage: ubuntu-16.04
steps:
- template: azure-install-rust.yml
parameters:
rust_version: ${{ parameters.rust }}
- template: azure-patch-crates.yml
- script: cargo check --all
displayName: cargo check --all
# Check benches
- script: cargo check --benches --all
displayName: Check benchmarks
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
CI: 'True'
displayName: cargo test -p ${{ crate }}
workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
condition: and(succeeded(), not(variables['isRelease']))
condition: and(succeeded(), ne(variables['isRelease'], 'true'))
- template: azure-patch-crates.yml
+1 -3
View File
@@ -2,12 +2,12 @@
# repository.
[patch.crates-io]
tokio = { path = "tokio" }
tokio-async-await = { path = "tokio-async-await" }
tokio-buf = { path = "tokio-buf" }
tokio-codec = { path = "tokio-codec" }
tokio-current-thread = { path = "tokio-current-thread" }
tokio-executor = { path = "tokio-executor" }
tokio-fs = { path = "tokio-fs" }
tokio-futures = { path = "tokio-futures" }
tokio-io = { path = "tokio-io" }
tokio-reactor = { path = "tokio-reactor" }
tokio-signal = { path = "tokio-signal" }
@@ -16,7 +16,5 @@ tokio-threadpool = { path = "tokio-threadpool" }
tokio-timer = { path = "tokio-timer" }
tokio-tcp = { path = "tokio-tcp" }
tokio-tls = { path = "tokio-tls" }
tokio-trace = { path = "tokio-trace" }
tokio-trace-core = { path = "tokio-trace/tokio-trace-core" }
tokio-udp = { path = "tokio-udp" }
tokio-uds = { path = "tokio-uds" }
-2
View File
@@ -1,2 +0,0 @@
[build]
target-dir = "../../target"
-49
View File
@@ -1,49 +0,0 @@
[package]
name = "examples"
edition = "2018"
version = "0.1.0"
authors = ["Carl Lerche <[email protected]>"]
license = "MIT"
# Break out of the parent workspace
[workspace]
[[bin]]
name = "chat"
path = "src/chat.rs"
[[bin]]
name = "echo_client"
path = "src/echo_client.rs"
[[bin]]
name = "echo_server"
path = "src/echo_server.rs"
[[bin]]
name = "hyper"
path = "src/hyper.rs"
[dependencies]
tokio = { version = "0.1.18", features = ["async-await-preview"] }
futures = "0.1.23"
bytes = "0.4.9"
hyper = "0.12.8"
# Avoid using crates.io for Tokio dependencies
[patch.crates-io]
tokio = { path = "../../tokio" }
tokio-async-await = { path = "../" }
tokio-codec = { path = "../../tokio-codec" }
tokio-current-thread = { path = "../../tokio-current-thread" }
tokio-executor = { path = "../../tokio-executor" }
tokio-fs = { path = "../../tokio-fs" }
tokio-io = { path = "../../tokio-io" }
tokio-reactor = { path = "../../tokio-reactor" }
tokio-signal = { path = "../../tokio-signal" }
tokio-tcp = { path = "../../tokio-tcp" }
tokio-threadpool = { path = "../../tokio-threadpool" }
tokio-timer = { path = "../../tokio-timer" }
tokio-tls = { path = "../../tokio-tls" }
tokio-udp = { path = "../../tokio-udp" }
tokio-uds = { path = "../../tokio-uds" }
-33
View File
@@ -1,33 +0,0 @@
#![feature(await_macro, async_await, futures_api)]
#[macro_use]
extern crate tokio;
extern crate hyper;
use tokio::prelude::*;
use hyper::Client;
use std::time::Duration;
use std::str;
pub fn main() {
tokio::run_async(async {
let client = Client::new();
let uri = "http://httpbin.org/ip".parse().unwrap();
let response = await!({
client.get(uri)
.timeout(Duration::from_secs(10))
}).unwrap();
println!("Response: {}", response.status());
let mut body = response.into_body();
while let Some(chunk) = await!(body.next()) {
let chunk = chunk.unwrap();
println!("chunk = {}", str::from_utf8(&chunk[..]).unwrap());
}
});
}
-4
View File
@@ -1,4 +0,0 @@
#![doc(hidden)]
pub mod backward;
pub mod forward;
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "tokio-buf"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
+4 -2
View File
@@ -1,9 +1,11 @@
[package]
name = "tokio-codec"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc URL.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.1"
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "tokio-current-thread"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
+5
View File
@@ -1,3 +1,8 @@
# 0.1.8 (June 2, 2019)
### Added
- Add `executor::exit` to allow other executors inside `threadpool::blocking` (#1155).
# 0.1.7 (March 22, 2019)
### Added
+4 -4
View File
@@ -1,14 +1,14 @@
[package]
name = "tokio-executor"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update CHANGELOG.md.
# - Update doc URL.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.7"
version = "0.1.8"
documentation = "https://docs.rs/tokio-executor/0.1.7/tokio_executor"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://github.com/tokio-rs/tokio"
+5 -5
View File
@@ -2,7 +2,7 @@
Task execution related traits and utilities.
[Documentation](https://docs.rs/tokio-executor/0.1.7/tokio_executor)
[Documentation](https://docs.rs/tokio-executor/0.1.8/tokio_executor)
## Overview
@@ -31,10 +31,10 @@ executor, including:
* [`Park`] abstracts over blocking and unblocking the current thread.
[`Executor`]: https://docs.rs/tokio-executor/0.1.7/tokio_executor/trait.Executor.html
[`enter`]: https://docs.rs/tokio-executor/0.1.7/tokio_executor/fn.enter.html
[`DefaultExecutor`]: https://docs.rs/tokio-executor/0.1.7/tokio_executor/struct.DefaultExecutor.html
[`Park`]: https://docs.rs/tokio-executor/0.1.7/tokio_executor/park/trait.Park.html
[`Executor`]: https://docs.rs/tokio-executor/0.1.8/tokio_executor/trait.Executor.html
[`enter`]: https://docs.rs/tokio-executor/0.1.8/tokio_executor/fn.enter.html
[`DefaultExecutor`]: https://docs.rs/tokio-executor/0.1.8/tokio_executor/struct.DefaultExecutor.html
[`Park`]: https://docs.rs/tokio-executor/0.1.8/tokio_executor/park/trait.Park.html
## License
+36
View File
@@ -67,6 +67,42 @@ pub fn enter() -> Result<Enter, EnterError> {
})
}
// Forces the current "entered" state to be cleared while the closure
// is executed.
//
// # Warning
//
// This is hidden for a reason. Do not use without fully understanding
// executors. Misuing can easily cause your program to deadlock.
#[doc(hidden)]
pub fn exit<F: FnOnce() -> R, R>(f: F) -> R {
// Reset in case the closure panics
struct Reset;
impl Drop for Reset {
fn drop(&mut self) {
ENTERED.with(|c| {
c.set(true);
});
}
}
ENTERED.with(|c| {
debug_assert!(c.get());
c.set(false);
});
let reset = Reset;
let ret = f();
::std::mem::forget(reset);
ENTERED.with(|c| {
assert!(!c.get(), "closure claimed permanent executor");
c.set(true);
});
ret
}
impl Enter {
/// Register a callback to be invoked if and when the thread
/// ceased to act as an executor.
+4 -2
View File
@@ -1,5 +1,7 @@
#![deny(missing_docs, missing_debug_implementations, warnings)]
#![doc(html_root_url = "https://docs.rs/tokio-executor/0.1.7")]
#![doc(html_root_url = "https://docs.rs/tokio-executor/0.1.8")]
// Our MSRV doesn't allow us to fix these warnings yet
#![allow(rust_2018_idioms)]
//! Task execution related traits and utilities.
//!
@@ -61,7 +63,7 @@ mod global;
pub mod park;
mod typed;
pub use enter::{enter, Enter, EnterError};
pub use enter::{enter, exit, Enter, EnterError};
pub use error::SpawnError;
pub use executor::Executor;
pub use global::{spawn, with_default, DefaultExecutor};
+3 -3
View File
@@ -1,12 +1,12 @@
[package]
name = "tokio-fs"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update CHANGELOG.md.
# - Update doc URL.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.6"
authors = ["Carl Lerche <[email protected]>"]
@@ -1,16 +1,16 @@
[package]
name = "tokio-async-await"
name = "tokio-futures"
# When releasing to crates.io:
# - Update html_root_url.
version = "0.1.7"
version = "0.1.0"
authors = ["Carl Lerche <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-async-await/0.1.7"
documentation = "https://docs.rs/tokio-futures/0.1.0"
description = """
Experimental async/await support for Tokio
Experimental std::future::Future and async/await support for Tokio
"""
categories = ["asynchronous"]
@@ -25,5 +25,5 @@ tokio-io = "0.1.7"
[dev-dependencies]
bytes = "0.4.9"
tokio = "0.1.8"
hyper = "0.12.8"
tokio = { version = "0.1.8", path = "../tokio" }
@@ -25,9 +25,9 @@ Then, get started. In your application, add:
```rust
// The nightly features that are commonly needed with async / await
#![feature(await_macro, async_await, futures_api)]
#![feature(await_macro, async_await)]
// This pulls in the `tokio-async-await` crate. While Rust 2018 doesn't require
// This pulls in the `tokio-futures` crate. While Rust 2018 doesn't require
// `extern crate`, we need to pull in the macros.
#[macro_use]
extern crate tokio;
@@ -1,3 +1,5 @@
//! Converts a `std::future::Future` into an 0.1 `Future.
use futures::{Future, Poll};
use std::future::Future as StdFuture;
@@ -5,18 +7,18 @@ use std::pin::Pin;
use std::ptr;
use std::task::{Context, Poll as StdPoll, RawWaker, RawWakerVTable, Waker};
/// Convert an 0.3 `Future` to an 0.1 `Future`.
/// Converts a `std::future::Future` into an 0.1 `Future.
#[derive(Debug)]
pub struct Compat<T>(Pin<Box<T>>);
impl<T> Compat<T> {
/// Create a new `Compat` backed by `future`.
pub fn new(future: T) -> Compat<T> {
pub(crate) fn new(future: T) -> Compat<T> {
Compat(Box::pin(future))
}
}
/// Convert a value into one that can be used with `await!`.
#[doc(hidden)]
pub trait IntoAwaitable {
type Awaitable;
@@ -74,7 +76,11 @@ unsafe fn clone_raw(_data: *const ()) -> RawWaker {
unsafe fn drop_raw(_data: *const ()) {}
unsafe fn wake(_data: *const ()) {
unimplemented!("async-await-preview currently only supports futures 0.1. Use the compatibility layer of futures 0.3 instead, if you want to use futures 0.3.");
unimplemented!(
"async-await-preview currently only supports futures 0.1. Use \
the compatibility layer of futures 0.3 instead, if you want \
to use futures 0.3."
);
}
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake, wake, drop_raw);
@@ -1,10 +1,12 @@
//! Converts an 0.1 `Future` into a `std::future::Future`.
//!
use futures::{Async, Future};
use std::future::Future as StdFuture;
use std::pin::Pin;
use std::task::{Context, Poll as StdPoll};
/// Converts an 0.1 `Future` into an 0.3 `Future`.
/// Converts an 0.1 `Future` into a `std::future::Future`.
#[derive(Debug)]
pub struct Compat<T>(T);
@@ -31,7 +33,7 @@ pub(crate) fn convert_poll_stream<T, E>(
}
}
/// Convert a value into one that can be used with `await!`.
#[doc(hidden)]
pub trait IntoAwaitable {
type Awaitable;
+42
View File
@@ -0,0 +1,42 @@
//! Compatibility layer between futures 0.1 and `std`.
pub mod backward;
pub mod forward;
/// Convert a `std::future::Future` yielding `Result` into an 0.1 `Future`.
pub fn into_01<T, Item, Error>(future: T) -> backward::Compat<T>
where
T: std::future::Future<Output = Result<Item, Error>>,
{
backward::Compat::new(future)
}
/// Convert a `std::future::Future` into an 0.1 `Future` with unit error.
pub fn infallible_into_01<T>(future: T) -> impl futures::Future<Item = T::Output, Error = ()>
where
T: std::future::Future,
{
use std::pin::Pin;
use std::task::{Context, Poll};
pub struct Map<T>(T);
impl<T> Map<T> {
fn future<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) }
}
}
impl<T: std::future::Future> std::future::Future for Map<T> {
type Output = Result<T::Output, ()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
match self.future().poll(cx) {
Poll::Ready(v) => Poll::Ready(Ok(v)),
Poll::Pending => Poll::Pending,
}
}
}
into_01(Map(future))
}
@@ -25,7 +25,7 @@ pub trait AsyncReadExt: AsyncRead {
/// # Examples
///
/// ```edition2018
/// #![feature(async_await, await_macro, futures_api)]
/// #![feature(async_await, await_macro)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
@@ -59,7 +59,7 @@ pub trait AsyncReadExt: AsyncRead {
/// # Examples
///
/// ```edition2018
/// #![feature(async_await, await_macro, futures_api)]
/// #![feature(async_await, await_macro)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
@@ -78,7 +78,7 @@ pub trait AsyncReadExt: AsyncRead {
/// ## EOF is hit before `buf` is filled
///
/// ```edition2018
/// #![feature(async_await, await_macro, futures_api)]
/// #![feature(async_await, await_macro)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
@@ -110,7 +110,7 @@ pub trait AsyncWriteExt: AsyncWrite {
/// # Examples
///
/// ```edition2018
/// #![feature(async_await, await_macro, futures_api)]
/// #![feature(async_await, await_macro)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
@@ -139,7 +139,7 @@ pub trait AsyncWriteExt: AsyncWrite {
/// # Examples
///
/// ```edition2018
/// #![feature(async_await, await_macro, futures_api)]
/// #![feature(async_await, await_macro)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
@@ -163,7 +163,7 @@ pub trait AsyncWriteExt: AsyncWrite {
/// # Examples
///
/// ```edition2018
/// #![feature(async_await, await_macro, futures_api)]
/// #![feature(async_await, await_macro)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
@@ -1,6 +1,6 @@
#![cfg(feature = "async-await-preview")]
#![feature(rust_2018_preview, async_await, await_macro, futures_api)]
#![doc(html_root_url = "https://docs.rs/tokio-async-await/0.1.7")]
#![feature(await_macro)]
#![doc(html_root_url = "https://docs.rs/tokio-futures/0.1.0")]
#![deny(missing_docs, missing_debug_implementations)]
#![cfg_attr(test, deny(warnings))]
@@ -13,7 +13,7 @@ pub trait StreamExt: Stream {
/// # Examples
///
/// ```edition2018
/// #![feature(await_macro, async_await, futures_api)]
/// #![feature(await_macro, async_await)]
/// tokio::run_async(async {
/// // The extension trait can also be imported with
/// // `use tokio::prelude::*`.
+4 -4
View File
@@ -1,12 +1,12 @@
[package]
name = "tokio-io"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update CHANGELOG.md.
# - Update doc URL.
# - Update doc url
# - Cargo.toml
# - Readme.md
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.12"
authors = ["Carl Lerche <[email protected]>"]
+27
View File
@@ -0,0 +1,27 @@
[package]
name = "tokio-macros"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.0"
authors = ["Tokio Contributors <[email protected]>"]
edition = "2018"
publish = false
[lib]
proc-macro = true
[features]
# This feature comes with no promise of stability. Things will
# break with each patch release. Use at your own risk.
async-await-preview = []
[dependencies]
proc-macro2 = "0.4.27"
quote = "0.6.11"
syn = { version = "0.15.27", features = ["full", "extra-traits", "visit-mut"] }
+47
View File
@@ -0,0 +1,47 @@
Copyright (c) 2019 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
The MIT License (MIT)
Copyright (c) 2019 Yoshua Wuyts
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+13
View File
@@ -0,0 +1,13 @@
# Tokio Macros
Procedural macros for use with Tokio
## License
This project is licensed under the [MIT license](LICENSE).
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Tokio by you, shall be licensed as MIT, without any additional
terms or conditions.
+81
View File
@@ -0,0 +1,81 @@
#![cfg(feature = "async-await-preview")]
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
/// Define the program entry point
///
/// # Examples
///
/// ```
/// #[tokio::main]
/// async fn main() {
/// println!("Hello world");
/// }
#[proc_macro_attribute]
pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let ret = &input.decl.output;
let name = &input.ident;
let body = &input.block;
if input.asyncness.is_none() {
let tokens = quote_spanned! { input.span() =>
compile_error!("the async keyword is missing from the function declaration");
};
return TokenStream::from(tokens);
}
let result = quote! {
fn #name() #ret {
let mut rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on_async(async { #body })
}
};
result.into()
}
/// Define a Tokio aware unit test
///
/// # Examples
///
/// ```
/// #[tokio::test]
/// async fn my_test() {
/// assert!(true);
/// }
/// ```
#[proc_macro_attribute]
pub fn test(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let ret = &input.decl.output;
let name = &input.ident;
let body = &input.block;
let attrs = &input.attrs;
if input.asyncness.is_none() {
let tokens = quote_spanned! { input.span() =>
compile_error!("the async keyword is missing from the function declaration");
};
return TokenStream::from(tokens);
}
let result = quote! {
#[test]
#(#attrs)*
fn #name() #ret {
let mut rt = tokio::runtime::current_thread::Runtime::new().unwrap();
rt.block_on_async(async { #body })
}
};
result.into()
}
+3 -3
View File
@@ -1,12 +1,12 @@
[package]
name = "tokio-reactor"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update CHANGELOG.md.
# - Update doc URL.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.9"
authors = ["Carl Lerche <[email protected]>"]
+5 -3
View File
@@ -1,10 +1,12 @@
[package]
name = "tokio-signal"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Update doc URL.
# - Create "v0.2.x" git tag.
version = "0.2.8"
authors = ["Tokio Contributors <[email protected]>"]
@@ -31,7 +33,7 @@ tokio-io = "0.1"
[target.'cfg(unix)'.dependencies]
libc = "0.2"
mio-uds = "0.6"
signal-hook = "0.1"
signal-hook-registry = "~1"
[dev-dependencies]
tokio = "0.1.8"
+4 -3
View File
@@ -8,7 +8,7 @@
pub extern crate libc;
extern crate mio;
extern crate mio_uds;
extern crate signal_hook;
extern crate signal_hook_registry;
use std::io::prelude::*;
use std::io::{self, Error, ErrorKind};
@@ -153,7 +153,7 @@ fn action(slot: &SignalInfo, mut sender: &UnixStream) {
/// This will register the signal handler if it hasn't already been registered,
/// returning any error along the way if that fails.
fn signal_enable(signal: c_int) -> io::Result<()> {
if signal_hook::FORBIDDEN.contains(&signal) {
if signal_hook_registry::FORBIDDEN.contains(&signal) {
return Err(Error::new(
ErrorKind::Other,
format!("Refusing to register signal {}", signal),
@@ -168,7 +168,8 @@ fn signal_enable(signal: c_int) -> io::Result<()> {
let mut registered = Ok(());
siginfo.init.call_once(|| {
registered = unsafe {
signal_hook::register(signal, move || action(siginfo, &globals.sender)).map(|_| ())
signal_hook_registry::register(signal, move || action(siginfo, &globals.sender))
.map(|_| ())
};
if registered.is_ok() {
siginfo.initialized.store(true, Ordering::Relaxed);
+5
View File
@@ -1,3 +1,8 @@
# 0.1.6 (June 4, 2019)
### Added
- Add Sync impl for Lock (#1117).
# 0.1.5 (April 22, 2019)
### Added
+3 -2
View File
@@ -1,18 +1,19 @@
[package]
name = "tokio-sync"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.5"
version = "0.1.6"
authors = ["Carl Lerche <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-sync/0.1.5/tokio_sync"
documentation = "https://docs.rs/tokio-sync/0.1.6/tokio_sync"
description = """
Synchronization utilities.
"""
+1 -1
View File
@@ -2,7 +2,7 @@
Synchronization utilities
[Documentation](https://docs.rs/tokio-sync/0.1.5/tokio_sync/)
[Documentation](https://docs.rs/tokio-sync/0.1.6/tokio_sync/)
## Overview
+1 -1
View File
@@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/tokio-sync/0.1.5")]
#![doc(html_root_url = "https://docs.rs/tokio-sync/0.1.6")]
#![deny(missing_debug_implementations, missing_docs, unreachable_pub)]
#![cfg_attr(test, deny(warnings))]
+4 -2
View File
@@ -72,9 +72,11 @@ pub struct Lock<T> {
#[derive(Debug)]
pub struct LockGuard<T>(Lock<T>);
// As long as T: Send, it's fine to send Lock<T> to other threads.
// If T was not Send, sending a Lock<T> would be bad, since you can access T through Lock<T>.
// As long as T: Send, it's fine to send and share Lock<T> between threads.
// If T was not Send, sending and sharing a Lock<T> would be bad, since you can access T through
// Lock<T>.
unsafe impl<T> Send for Lock<T> where T: Send {}
unsafe impl<T> Sync for Lock<T> where T: Send {}
unsafe impl<T> Sync for LockGuard<T> where T: Send + Sync {}
#[derive(Debug)]
+2 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "tokio-tcp"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
@@ -29,4 +29,5 @@ futures = "0.1.19"
[dev-dependencies]
env_logger = { version = "0.5", default-features = false }
net2 = "0.2"
tokio = "0.1.13"
+7 -7
View File
@@ -61,7 +61,7 @@ impl TcpListener {
/// use tokio::net::TcpListener;
///
/// # fn main() -> Result<(), Box<std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse::<SocketAddr>()?;
/// let addr = "127.0.0.1:0".parse::<SocketAddr>()?;
/// let listener = TcpListener::bind(&addr)?;
/// # Ok(())
/// # }
@@ -109,7 +109,7 @@ impl TcpListener {
/// use futures::Async;
///
/// # fn main() -> Result<(), Box<std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse::<SocketAddr>()?;
/// let addr = "127.0.0.1:0".parse::<SocketAddr>()?;
/// let mut listener = TcpListener::bind(&addr)?;
/// match listener.poll_accept() {
/// Ok(Async::Ready((_socket, addr))) => println!("listener ready to accept: {:?}", addr),
@@ -167,7 +167,7 @@ impl TcpListener {
/// use futures::Async;
///
/// # fn main() -> Result<(), Box<std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse::<SocketAddr>()?;
/// let addr = "127.0.0.1:0".parse::<SocketAddr>()?;
/// let mut listener = TcpListener::bind(&addr)?;
/// match listener.poll_accept_std() {
/// Ok(Async::Ready((_socket, addr))) => println!("listener ready to accept: {:?}", addr),
@@ -230,7 +230,7 @@ impl TcpListener {
/// use tokio::reactor::Handle;
///
/// # fn main() -> Result<(), Box<std::error::Error>> {
/// let std_listener = StdTcpListener::bind("127.0.0.1:8080")?;
/// let std_listener = StdTcpListener::bind("127.0.0.1:0")?;
/// let listener = TcpListener::from_std(std_listener, &Handle::default())?;
/// # Ok(())
/// # }
@@ -296,7 +296,7 @@ impl TcpListener {
/// use std::net::SocketAddr;
///
/// # fn main() -> Result<(), Box<std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse::<SocketAddr>()?;
/// let addr = "127.0.0.1:0".parse::<SocketAddr>()?;
/// let listener = TcpListener::bind(&addr)?;
///
/// listener.incoming()
@@ -326,7 +326,7 @@ impl TcpListener {
/// use std::net::SocketAddr;
///
/// # fn main() -> Result<(), Box<std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse::<SocketAddr>()?;
/// let addr = "127.0.0.1:0".parse::<SocketAddr>()?;
/// let listener = TcpListener::bind(&addr)?;
/// listener.set_ttl(100).expect("could not set TTL");
/// assert_eq!(listener.ttl()?, 100);
@@ -350,7 +350,7 @@ impl TcpListener {
/// use std::net::SocketAddr;
///
/// # fn main() -> Result<(), Box<std::error::Error>> {
/// let addr = "127.0.0.1:8080".parse::<SocketAddr>()?;
/// let addr = "127.0.0.1:0".parse::<SocketAddr>()?;
/// let listener = TcpListener::bind(&addr)?;
/// listener.set_ttl(100).expect("could not set TTL");
/// # Ok(())
+5 -2
View File
@@ -1,6 +1,7 @@
extern crate env_logger;
extern crate futures;
extern crate mio;
extern crate net2;
extern crate tokio_io;
extern crate tokio_tcp;
@@ -84,13 +85,14 @@ fn accept2() {
t.join().unwrap();
}
#[cfg(unix)]
mod unix {
#[cfg(target_os = "linux")]
mod linux {
use tokio_tcp::TcpStream;
use env_logger;
use futures::{future, Future};
use mio::unix::UnixReady;
use net2::TcpStreamExt;
use tokio_io::AsyncRead;
use std::io::Write;
@@ -105,6 +107,7 @@ mod unix {
let addr = t!(srv.local_addr());
let t = thread::spawn(move || {
let mut client = t!(srv.accept()).0;
client.set_linger(Some(Duration::from_millis(0))).unwrap();
client.write(b"hello world").unwrap();
thread::sleep(Duration::from_millis(200));
});
+1
View File
@@ -0,0 +1 @@
@@ -1,23 +1,26 @@
[package]
name = "tokio-trace-core"
name = "tokio-test"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.2.x" git tag.
version = "0.2.0"
# - Create "v0.1.x" git tag.
version = "0.1.0"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-trace-core/0.2.0/tokio_trace_core"
documentation = "https://docs.rs/tokio-test/0.1.0/tokio_test"
description = """
Core primitives for tokio-trace.
Testing utilities for Tokio- and futures-based code
"""
categories = ["development-tools::debugging"]
keywords = ["logging", "tracing"]
categories = ["asynchronous", "testing"]
publish = false
[dependencies]
lazy_static = "1.0.0"
futures = "0.1"
tokio-timer = "0.2"
tokio-executor = "0.1"
+36
View File
@@ -0,0 +1,36 @@
# tokio-test
Tokio and Futures based testing utilities
[Documenation](https://docs.rs/tokio-test)
## Usage
First, add this to your `Cargo.toml`:
```toml
[dev-dependencies]
tokio-test = "0.1.0"
```
Next, add this to your crate:
```rust
#[macro_use]
extern crate tokio_test;
```
You can find extensive documentation and examples about how to use this crate
online at [https://tokio.rs](https://tokio.rs). The [API
documentation](https://docs.rs/tokio-test) is also a great place to get started
for the nitty-gritty.
## License
This project is licensed under the [MIT license](LICENSE).
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Tokio by you, shall be licensed as MIT, without any additional
terms or conditions.
+256
View File
@@ -0,0 +1,256 @@
//! A mocked clock for use with `tokio_timer` based futures.
//!
//! # Example
//!
//! ```
//! # #[macro_use] extern crate tokio_test;
//! # extern crate futures;
//! # extern crate tokio_timer;
//! # use tokio_test::clock;
//! # use tokio_timer::Delay;
//! # use std::time::Duration;
//! # use futures::Future;
//! clock::mock(|handle| {
//! let mut delay = Delay::new(handle.now() + Duration::from_secs(1));
//!
//! assert_not_ready!(delay.poll());
//!
//! handle.advance(Duration::from_secs(1));
//!
//! assert_ready!(delay.poll());
//! });
//! ```
use futures::{future::lazy, Future};
use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use tokio_executor::park::{Park, Unpark};
use tokio_timer::clock::{Clock, Now};
use tokio_timer::Timer;
/// Run the provided closure with a `MockClock` that starts at the current time.
pub fn mock<F, R>(f: F) -> R
where
F: FnOnce(&mut Handle) -> R,
{
let mut mock = MockClock::new();
mock.enter(f)
}
/// Run the provided closure with a `MockClock` that starts at the provided `Instant`.
pub fn mock_at<F, R>(instant: Instant, f: F) -> R
where
F: FnOnce(&mut Handle) -> R,
{
let mut mock = MockClock::with_instant(instant);
mock.enter(f)
}
/// Mock clock for use with `tokio-timer` futures.
///
/// A mock timer that is able to advance and wake after a
/// certain duration.
#[derive(Debug)]
pub struct MockClock {
time: MockTime,
clock: Clock,
}
/// A handle to the `MockClock`.
#[derive(Debug)]
pub struct Handle {
timer: Timer<MockPark>,
time: MockTime,
}
type Inner = Arc<Mutex<State>>;
#[derive(Debug, Clone)]
struct MockTime {
inner: Inner,
_pd: PhantomData<Rc<()>>,
}
#[derive(Debug)]
struct MockNow {
inner: Inner,
}
#[derive(Debug)]
struct MockPark {
inner: Inner,
_pd: PhantomData<Rc<()>>,
}
#[derive(Debug)]
struct MockUnpark {
inner: Inner,
}
#[derive(Debug)]
struct State {
base: Instant,
advance: Duration,
unparked: bool,
park_for: Option<Duration>,
}
impl MockClock {
/// Create a new `MockClock` with the current time.
pub fn new() -> Self {
MockClock::with_instant(Instant::now())
}
/// Create a `MockClock` with its current time at a duration from now
///
/// This will create a clock with `Instant::now() + duration` as the current time.
pub fn with_duration(duration: Duration) -> Self {
let instant = Instant::now() + duration;
MockClock::with_instant(instant)
}
/// Create a `MockClock` that sets its current time as the `Instant` provided.
pub fn with_instant(instant: Instant) -> Self {
let time = MockTime::new(instant);
let clock = Clock::new_with_now(time.mock_now());
MockClock { time, clock }
}
/// Enter the `MockClock` context.
pub fn enter<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut Handle) -> R,
{
let mut enter = ::tokio_executor::enter().unwrap();
::tokio_timer::clock::with_default(&self.clock, &mut enter, |enter| {
let park = self.time.mock_park();
let timer = Timer::new(park);
let handle = timer.handle();
let time = self.time.clone();
::tokio_timer::with_default(&handle, enter, |_| {
let mut handle = Handle::new(timer, time);
lazy(|| Ok::<_, ()>(f(&mut handle))).wait().unwrap()
})
})
}
}
impl Handle {
pub(self) fn new(timer: Timer<MockPark>, time: MockTime) -> Self {
Handle { timer, time }
}
/// Turn the internal timer and mock park for the provided duration.
pub fn turn(&mut self, duration: Option<Duration>) {
self.timer.turn(duration).unwrap();
}
/// Advance the `MockClock` by the provided duration.
pub fn advance(&mut self, duration: Duration) {
let inner = self.timer.get_park().inner.clone();
let deadline = inner.lock().unwrap().now() + duration;
while inner.lock().unwrap().now() < deadline {
let dur = deadline - inner.lock().unwrap().now();
self.turn(Some(dur));
}
}
/// Get the currently mocked time
pub fn now(&mut self) -> Instant {
self.time.now()
}
}
impl MockTime {
pub(crate) fn new(now: Instant) -> MockTime {
let state = State {
base: now,
advance: Duration::default(),
unparked: false,
park_for: None,
};
MockTime {
inner: Arc::new(Mutex::new(state)),
_pd: PhantomData,
}
}
pub(crate) fn mock_now(&self) -> MockNow {
let inner = self.inner.clone();
MockNow { inner }
}
pub(crate) fn mock_park(&self) -> MockPark {
let inner = self.inner.clone();
MockPark {
inner,
_pd: PhantomData,
}
}
pub(crate) fn now(&self) -> Instant {
self.inner.lock().unwrap().now()
}
}
impl State {
fn now(&self) -> Instant {
self.base + self.advance
}
fn advance(&mut self, duration: Duration) {
self.advance += duration;
}
}
impl Park for MockPark {
type Unpark = MockUnpark;
type Error = ();
fn unpark(&self) -> Self::Unpark {
let inner = self.inner.clone();
MockUnpark { inner }
}
fn park(&mut self) -> Result<(), Self::Error> {
let mut inner = self.inner.lock().map_err(|_| ())?;
let duration = inner.park_for.take().expect("call park_for first");
inner.advance(duration);
Ok(())
}
fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error> {
let mut inner = self.inner.lock().unwrap();
if let Some(duration) = inner.park_for.take() {
inner.advance(duration);
} else {
inner.advance(duration);
}
Ok(())
}
}
impl Unpark for MockUnpark {
fn unpark(&self) {
if let Ok(mut inner) = self.inner.lock() {
inner.unparked = true;
}
}
}
impl Now for MockNow {
fn now(&self) -> Instant {
self.inner.lock().unwrap().now()
}
}
+30
View File
@@ -0,0 +1,30 @@
#![doc(html_root_url = "https://docs.rs/tokio-test/0.1.0")]
#![deny(missing_docs, missing_debug_implementations, unreachable_pub)]
#![cfg_attr(test, deny(warnings))]
//! Tokio and Futures based testing utilites
//!
//! # Example
//!
//! ```
//! # extern crate futures;
//! # #[macro_use] extern crate tokio_test;
//! # use futures::{Future, future};
//! let mut fut = future::ok::<(), ()>(());
//! assert_ready!(fut.poll());
//! ```
extern crate futures;
extern crate tokio_executor;
extern crate tokio_timer;
pub mod clock;
mod macros;
pub mod task;
#[doc(hidden)]
pub mod codegen {
pub mod futures {
pub use futures::*;
}
}
+131
View File
@@ -0,0 +1,131 @@
//! A collection of useful macros for testing futures and tokio based code
/// Assert if a poll is ready
#[macro_export]
macro_rules! assert_ready {
($e:expr) => {{
use $crate::codegen::futures::Async::Ready;
match $e {
Ok(Ready(v)) => v,
Ok(_) => panic!("not ready"),
Err(e) => panic!("error = {:?}", e),
}
}};
($e:expr, $($msg:tt),+) => {{
use $crate::codegen::futures::Async::Ready;
match $e {
Ok(Ready(v)) => v,
Ok(_) => {
let msg = format_args!($($msg),+);
panic!("not ready; {}", msg)
}
Err(e) => {
let msg = format!($($msg),+);
panic!("error = {:?}; {}", e, msg)
}
}
}};
}
/// Asset if the poll is not ready
#[macro_export]
macro_rules! assert_not_ready {
($e:expr) => {{
use $crate::codegen::futures::Async::{Ready, NotReady};
match $e {
Ok(NotReady) => {}
Ok(Ready(v)) => panic!("ready; value = {:?}", v),
Err(e) => panic!("error = {:?}", e),
}
}};
($e:expr, $($msg:tt),+) => {{
use $crate::codegen::futures::Async::{Ready, NotReady};
match $e {
Ok(NotReady) => {}
Ok(Ready(v)) => {
let msg = format_args!($($msg),+);
panic!("ready; value = {:?}; {}", v, msg)
}
Err(e) => {
let msg = format_args!($($msg),+);
panic!("error = {:?}; {}", e, msg)
}
}
}};
}
/// Assert if a poll is ready and check for equality on the value
#[macro_export]
macro_rules! assert_ready_eq {
($e:expr, $expect:expr) => {
use $crate::codegen::futures::Async::Ready;
match $e {
Ok(e) => assert_eq!(e, Ready($expect)),
Err(e) => panic!("error = {:?}", e),
}
};
($e:expr, $expect:expr, $($msg:tt),+) => {
use $crate::codegen::futures::Async::Ready;
match $e {
Ok(e) => assert_eq!(e, Ready($expect), $($msg)+),
Err(e) => {
let msg = format_args!($($msg),+);
panic!("error = {:?}; {}", e, msg)
}
}
};
}
/// Assert if the deadline has passed
#[macro_export]
macro_rules! assert_elapsed {
($e:expr) => {
assert!($e.unwrap_err().is_elapsed());
};
($e:expr, $($msg:expr),+) => {
assert!($e.unwrap_err().is_elapsed(), $msg);
};
}
#[cfg(test)]
mod tests {
use futures::{future, Async, Future, Poll};
#[test]
fn assert_ready() {
let mut fut = future::ok::<(), ()>(());
assert_ready!(fut.poll());
let mut fut = future::ok::<(), ()>(());
assert_ready!(fut.poll(), "some message");
}
#[test]
#[should_panic]
fn assert_ready_err() {
let mut fut = future::err::<(), ()>(());
assert_ready!(fut.poll());
}
#[test]
fn assert_not_ready() {
let poll: Poll<(), ()> = Ok(Async::NotReady);
assert_not_ready!(poll);
assert_not_ready!(poll, "some message");
}
#[test]
#[should_panic]
fn assert_not_ready_err() {
let mut fut = future::err::<(), ()>(());
assert_not_ready!(fut.poll());
}
#[test]
fn assert_ready_eq() {
let mut fut = future::ok::<(), ()>(());
assert_ready_eq!(fut.poll(), ());
}
}
+133
View File
@@ -0,0 +1,133 @@
//! Futures task based helpers
//!
//! # Example
//!
//! This example will use the `MockTask` to set the current task on
//! poll.
//!
//! ```
//! # #[macro_use] extern crate tokio_test;
//! # extern crate futures;
//! # use tokio_test::task::MockTask;
//! # use futures::{sync::mpsc, Stream, Sink, Future, Async};
//! let mut task = MockTask::new();
//! let (tx, mut rx) = mpsc::channel(5);
//!
//! tx.send(()).wait();
//!
//! assert_ready_eq!(task.enter(|| rx.poll()), Some(()));
//! ```
use futures::executor::{spawn, Notify};
use futures::{future, Async};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Condvar, Mutex};
/// Mock task
///
/// A mock task is able to intercept and track notifications.
#[derive(Debug)]
pub struct MockTask {
notify: Arc<ThreadNotify>,
}
#[derive(Debug)]
struct ThreadNotify {
state: AtomicUsize,
mutex: Mutex<()>,
condvar: Condvar,
}
const IDLE: usize = 0;
const NOTIFY: usize = 1;
const SLEEP: usize = 2;
impl MockTask {
/// Create a new mock task
pub fn new() -> Self {
MockTask {
notify: Arc::new(ThreadNotify::new()),
}
}
/// Run a closure from the context of the task.
///
/// Any notifications resulting from the execution of the closure are
/// tracked.
pub fn enter<F, R>(&mut self, f: F) -> R
where
F: FnOnce() -> R,
{
self.notify.clear();
let res = spawn(future::lazy(|| Ok::<_, ()>(f()))).poll_future_notify(&self.notify, 0);
match res.unwrap() {
Async::Ready(v) => v,
_ => unreachable!(),
}
}
/// Returns `true` if the inner future has received a readiness notification
/// since the last call to `enter`.
pub fn is_notified(&self) -> bool {
self.notify.is_notified()
}
/// Returns the number of references to the task notifier
///
/// The task itself holds a reference. The return value will never be zero.
pub fn notifier_ref_count(&self) -> usize {
Arc::strong_count(&self.notify)
}
}
impl ThreadNotify {
fn new() -> Self {
ThreadNotify {
state: AtomicUsize::new(IDLE),
mutex: Mutex::new(()),
condvar: Condvar::new(),
}
}
/// Clears any previously received notify, avoiding potential spurrious
/// notifications. This should only be called immediately before running the
/// task.
fn clear(&self) {
self.state.store(IDLE, Ordering::SeqCst);
}
fn is_notified(&self) -> bool {
match self.state.load(Ordering::SeqCst) {
IDLE => false,
NOTIFY => true,
_ => unreachable!(),
}
}
}
impl Notify for ThreadNotify {
fn notify(&self, _unpark_id: usize) {
// First, try transitioning from IDLE -> NOTIFY, this does not require a
// lock.
match self.state.compare_and_swap(IDLE, NOTIFY, Ordering::SeqCst) {
IDLE | NOTIFY => return,
SLEEP => {}
_ => unreachable!(),
}
// The other half is sleeping, this requires a lock
let _m = self.mutex.lock().unwrap();
// Transition from SLEEP -> NOTIFY
match self.state.compare_and_swap(SLEEP, NOTIFY, Ordering::SeqCst) {
SLEEP => {}
_ => return,
}
// Wakeup the sleeper
self.condvar.notify_one();
}
}
+44
View File
@@ -0,0 +1,44 @@
#[macro_use]
extern crate tokio_test;
extern crate futures;
extern crate tokio_timer;
use futures::Future;
use std::time::{Duration, Instant};
use tokio_test::clock::MockClock;
use tokio_test::task::MockTask;
use tokio_timer::Delay;
#[test]
fn clock() {
let mut mock = MockClock::new();
mock.enter(|handle| {
let deadline = Instant::now() + Duration::from_secs(1);
let mut delay = Delay::new(deadline);
assert_not_ready!(delay.poll());
handle.advance(Duration::from_secs(2));
assert_ready!(delay.poll());
});
}
#[test]
fn notify() {
let deadline = Instant::now() + Duration::from_secs(1);
let mut mock = MockClock::new();
let mut task = MockTask::new();
mock.enter(|handle| {
let mut delay = Delay::new(deadline);
task.enter(|| assert_not_ready!(delay.poll()));
handle.advance(Duration::from_secs(1));
assert!(task.is_notified());
assert_ready!(delay.poll());
});
}
+5
View File
@@ -1,3 +1,8 @@
# 0.1.15 (June 2, 2019)
### Changed
- Allow other executors inside `threadpool::blocking` (#1155).
# 0.1.14 (April 22, 2019)
### Added
+3 -2
View File
@@ -1,13 +1,14 @@
[package]
name = "tokio-threadpool"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.14"
version = "0.1.15"
documentation = "https://docs.rs/tokio-threadpool/0.1.14/tokio_threadpool"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://github.com/tokio-rs/tokio"
@@ -20,7 +21,7 @@ keywords = ["futures", "tokio"]
categories = ["concurrency", "asynchronous"]
[dependencies]
tokio-executor = "0.1.7"
tokio-executor = "0.1.8"
futures = "0.1.19"
crossbeam-deque = "0.7.0"
crossbeam-queue = "0.1.0"
+1 -1
View File
@@ -3,7 +3,7 @@
A library for scheduling execution of futures concurrently across a pool of
threads.
[Documentation](https://docs.rs/tokio-threadpool/0.1.14/tokio_threadpool)
[Documentation](https://docs.rs/tokio-threadpool/0.1.15/tokio_threadpool)
### Why not Rayon?
+6 -2
View File
@@ -1,6 +1,7 @@
use worker::Worker;
use futures::Poll;
use tokio_executor;
use std::error::Error;
use std::fmt;
@@ -142,8 +143,11 @@ where
// If the transition cannot happen, exit early
try_ready!(res);
// Currently in blocking mode, so call the inner closure
let ret = f();
// Currently in blocking mode, so call the inner closure.
//
// "Exit" the current executor in case the blocking function wants
// to call a different executor.
let ret = tokio_executor::exit(move || f());
// Try to transition out of blocking mode. This is a fast path that takes
// back ownership of the worker if the worker handoff didn't complete yet.
+3 -1
View File
@@ -1,5 +1,7 @@
#![doc(html_root_url = "https://docs.rs/tokio-threadpool/0.1.14")]
#![doc(html_root_url = "https://docs.rs/tokio-threadpool/0.1.15")]
#![deny(warnings, missing_docs, missing_debug_implementations)]
// Our MSRV doesn't allow us to fix these warnings yet
#![allow(rust_2018_idioms)]
//! A work-stealing based thread pool for executing futures.
//!
+23
View File
@@ -1,3 +1,4 @@
extern crate tokio_executor;
extern crate tokio_threadpool;
extern crate env_logger;
@@ -44,6 +45,28 @@ fn basic() {
rx2.recv().unwrap();
}
#[test]
fn other_executors_can_run_inside_blocking() {
let _ = ::env_logger::try_init();
let pool = Builder::new().pool_size(1).max_blocking(1).build();
let (tx, rx) = mpsc::channel();
pool.spawn(lazy(move || {
let res = blocking(|| {
let _e = tokio_executor::enter().expect("nested blocking enter");
tx.send(()).unwrap();
})
.unwrap();
assert!(res.is_ready());
Ok(().into())
}));
rx.recv().unwrap();
}
#[test]
fn notify_task_on_capacity() {
const BLOCKING: usize = 10;
+5
View File
@@ -1,3 +1,8 @@
# 0.2.11 (May 14, 2019)
### Added
- `Handle::timeout` API, replacing the deprecated `Handle::deadline` (#1074).
# 0.2.10 (February 4, 2019)
### Fixed
+3 -2
View File
@@ -1,17 +1,18 @@
[package]
name = "tokio-timer"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.2.x" git tag.
version = "0.2.10"
version = "0.2.11"
authors = ["Carl Lerche <[email protected]>"]
license = "MIT"
readme = "README.md"
documentation = "https://docs.rs/tokio-timer/0.2.10/tokio_timer"
documentation = "https://docs.rs/tokio-timer/0.2.11/tokio_timer"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://github.com/tokio-rs/tokio"
description = """
+1 -1
View File
@@ -2,7 +2,7 @@
Timer facilities for Tokio
[Documentation](https://docs.rs/tokio-timer/0.2.10/tokio_timer/)
[Documentation](https://docs.rs/tokio-timer/0.2.11/tokio_timer/)
## Overview
+1 -1
View File
@@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/tokio-timer/0.2.10")]
#![doc(html_root_url = "https://docs.rs/tokio-timer/0.2.11")]
#![deny(missing_docs, warnings, missing_debug_implementations)]
//! Utilities for tracking time.
+3
View File
@@ -126,7 +126,10 @@ impl<T> Timeout<T> {
/// ```
pub fn new(value: T, timeout: Duration) -> Timeout<T> {
let delay = Delay::new_timeout(now() + timeout, timeout);
Timeout::new_with_delay(value, delay)
}
pub(crate) fn new_with_delay(value: T, delay: Delay) -> Timeout<T> {
Timeout { value, delay }
}
+8 -2
View File
@@ -1,5 +1,5 @@
use timer::Inner;
use {Deadline, Delay, Error, Interval};
use {Deadline, Delay, Error, Interval, Timeout};
use tokio_executor::Enter;
@@ -139,11 +139,17 @@ impl Handle {
}
}
/// Create a `Deadline` driven by this handle's associated `Timer`.
#[doc(hidden)]
#[deprecated(since = "0.2.11", note = "use timeout instead")]
pub fn deadline<T>(&self, future: T, deadline: Instant) -> Deadline<T> {
Deadline::new_with_delay(future, self.delay(deadline))
}
/// Create a `Timeout` driven by this handle's associated `Timer`.
pub fn timeout<T>(&self, value: T, deadline: Instant) -> Timeout<T> {
Timeout::new_with_delay(value, self.delay(deadline))
}
/// Create a new `Interval` that starts at `at` and yields every `duration`
/// interval after that.
pub fn interval(&self, at: Instant, duration: Duration) -> Interval {
+1 -1
View File
@@ -118,7 +118,7 @@ fn hammer_cancel() {
let deadline = cmp::min(deadline1, deadline2);
let delay = handle.delay(deadline1);
let join = handle.deadline(delay, deadline2);
let join = handle.timeout(delay, deadline2);
exec.push({
join.and_then(move |_| {
+5 -1
View File
@@ -1,9 +1,13 @@
[package]
name = "tokio-tls"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "tokio-tls-0.2.x" git tag.
# - Create "v0.2.x" git tag.
version = "0.2.1"
authors = ["Carl Lerche <[email protected]>"]
license = "MIT"
-3
View File
@@ -1,3 +0,0 @@
# 0.1.0 (April 22, 2019)
- Initial release
-52
View File
@@ -1,52 +0,0 @@
[package]
name = "tokio-trace"
# When releasing to crates.io:
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag
version = "0.1.0"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-trace/0.1.0/tokio_trace"
description = """
A scoped, structured logging and diagnostics system.
"""
categories = ["development-tools::debugging", "asynchronous"]
keywords = ["logging", "tracing"]
[dependencies]
tokio-trace-core = "0.2"
log = { version = "0.4", optional = true }
cfg-if = "0.1.7"
[dev-dependencies]
ansi_term = "0.11"
humantime = "1.1.1"
futures = "0.1"
log = "0.4"
# These are used for the "basic" example from the tokio-trace-prototype repo,
# which is currently not included as it used the `tokio-trace-log` crate, and
# that crate is currently unstable.
# env_logger = "0.5"
# tokio-trace-log = { path = "../tokio-trace-log" }
[features]
max_level_off = []
max_level_error = []
max_level_warn = []
max_level_info = []
max_level_debug = []
max_level_trace = []
release_max_level_off = []
release_max_level_error = []
release_max_level_warn = []
release_max_level_info = []
release_max_level_debug = []
release_max_level_trace = []
-171
View File
@@ -1,171 +0,0 @@
# tokio-trace
A scoped, structured logging and diagnostics system.
[Documentation](https://docs.rs/tokio-trace/0.1.0/tokio_trace/index.html)
## Overview
`tokio-trace` is a framework for instrumenting Rust programs to collect
structured, event-based diagnostic information.
In asynchronous systems like Tokio, interpreting traditional log messages can
often be quite challenging. Since individual tasks are multiplexed on the same
thread, associated events and log lines are intermixed making it difficult to
trace the logic flow. `tokio-trace` expands upon logging-style diagnostics by
allowing libraries and applications to record structured events with additional
information about *temporality* and *causality* — unlike a log message, a span
in `tokio-trace` has a beginning and end time, may be entered and exited by the
flow of execution, and may exist within a nested tree of similar spans. In
addition, `tokio-trace` spans are *structured*, with the ability to record typed
data as well as textual messages.
The `tokio-trace` crate provides the APIs necessary for instrumenting libraries
and applications to emit trace data.
## Usage
First, add this to your `Cargo.toml`:
```toml
[dependencies]
tokio-trace = "0.1"
```
Next, add this to your crate:
```rust
#[macro_use]
extern crate tokio_trace;
```
This crate provides macros for creating `Span`s and `Event`s, which represent
periods of time and momentary events within the execution of a program,
respectively.
As a rule of thumb, _spans_ should be used to represent discrete units of work
(e.g., a given request's lifetime in a server) or periods of time spent in a
given context (e.g., time spent interacting with an instance of an external
system, such as a database). In contrast, _events_ should be used to represent
points in time within a span — a request returned with a given status code,
_n_ new items were taken from a queue, and so on.
`Span`s are constructed using the `span!` macro, and then _entered_
to indicate that some code takes place within the context of that `Span`:
```rust
// Construct a new span named "my span".
let mut span = span!("my span");
span.enter(|| {
// Any trace events in this closure or code called by it will occur within
// the span.
});
// Dropping the span will close it, indicating that it has ended.
```
The `Event` type represent an event that occurs instantaneously, and is
essentially a `Span` that cannot be entered. They are created using the `event!`
macro:
```rust
use tokio_trace::Level;
event!(Level::INFO, "something has happened!");
```
Users of the [`log`] crate should note that `tokio-trace` exposes a set of macros for
creating `Event`s (`trace!`, `debug!`, `info!`, `warn!`, and `error!`) which may
be invoked with the same syntax as the similarly-named macros from the `log`
crate. Often, the process of converting a project to use `tokio-trace` can begin
with a simple drop-in replacement.
Let's consider the `log` crate's yak-shaving example:
```rust
#[macro_use]
extern crate tokio_trace;
use tokio_trace::field;
pub fn shave_the_yak(yak: &mut Yak) {
// Create a new span for this invocation of `shave_the_yak`, annotated
// with the yak being shaved as a *field* on the span.
span!("shave_the_yak", yak = field::debug(&yak)).enter(|| {
// Since the span is annotated with the yak, it is part of the context
// for everything happening inside the span. Therefore, we don't need
// to add it to the message for this event, as the `log` crate does.
info!(target: "yak_events", "Commencing yak shaving");
loop {
match find_a_razor() {
Ok(razor) => {
// We can add the razor as a field rather than formatting it
// as part of the message, allowing subscribers to consume it
// in a more structured manner:
info!({ razor = field::display(razor) }, "Razor located");
yak.shave(razor);
break;
}
Err(err) => {
// However, we can also create events with formatted messages,
// just as we would for log records.
warn!("Unable to locate a razor: {}, retrying", err);
}
}
}
})
}
```
You can find examples showing how to use this crate in the examples directory.
### In libraries
Libraries should link only to the `tokio-trace` crate, and use the provided
macros to record whatever information will be useful to downstream consumers.
### In executables
In order to record trace events, executables have to use a `Subscriber`
implementation compatible with `tokio-trace`. A `Subscriber` implements a way of
collecting trace data, such as by logging it to standard output.
Unlike the `log` crate, `tokio-trace` does *not* use a global `Subscriber` which
is initialized once. Instead, it follows the `tokio` pattern of executing code
in a context. For example:
```rust
#[macro_use]
extern crate tokio_trace;
let my_subscriber = FooSubscriber::new();
tokio_trace::subscriber::with_default(subscriber, || {
// Any trace events generated in this closure or by functions it calls
// will be collected by `my_subscriber`.
})
```
This approach allows trace data to be collected by multiple subscribers within
different contexts in the program. Alternatively, a single subscriber may be
constructed by the `main` function and all subsequent code executed with that
subscriber as the default. Any trace events generated outside the context of a
subscriber will not be collected.
The executable itself may use the `tokio-trace` crate to instrument itself as
well.
The [`tokio-trace-nursery`] repository contains less stable crates designed to
be used with the `tokio-trace` ecosystem. It includes a collection of
`Subscriber` implementations, as well as utility and adapter crates.
[`log`]: https://docs.rs/log/0.4.6/log/
[`tokio-trace-nursery`]: https://github.com/tokio-rs/tokio-trace-nursery
## License
This project is licensed under the [MIT license](LICENSE).
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Tokio by you, shall be licensed as MIT, without any additional
terms or conditions.
-46
View File
@@ -1,46 +0,0 @@
#![feature(test)]
#[macro_use]
extern crate tokio_trace;
#[macro_use]
extern crate log;
extern crate test;
use test::Bencher;
use tokio_trace::Level;
#[bench]
fn bench_span_no_subscriber(b: &mut Bencher) {
b.iter(|| {
span!(Level::TRACE, "span");
});
}
#[bench]
fn bench_log_no_logger(b: &mut Bencher) {
b.iter(|| {
log!(log::Level::Info, "log");
});
}
#[bench]
fn bench_costly_field_no_subscriber(b: &mut Bencher) {
b.iter(|| {
span!(
Level::TRACE,
"span",
foo = tokio_trace::field::display(format!("bar {:?}", 2))
);
});
}
#[bench]
fn bench_no_span_no_subscriber(b: &mut Bencher) {
b.iter(|| {});
}
#[bench]
fn bench_1_atomic_load(b: &mut Bencher) {
// This is just included as a baseline.
use std::sync::atomic::{AtomicUsize, Ordering};
let foo = AtomicUsize::new(1);
b.iter(|| foo.load(Ordering::Relaxed));
}
-158
View File
@@ -1,158 +0,0 @@
#![feature(test)]
#[macro_use]
extern crate tokio_trace;
extern crate test;
use test::Bencher;
use tokio_trace::Level;
use std::{
fmt,
sync::{Mutex, MutexGuard},
};
use tokio_trace::{field, span, Event, Id, Metadata};
/// A subscriber that is enabled but otherwise does nothing.
struct EnabledSubscriber;
impl tokio_trace::Subscriber for EnabledSubscriber {
fn new_span(&self, span: &span::Attributes) -> Id {
let _ = span;
Id::from_u64(0xDEADFACE)
}
fn event(&self, event: &Event) {
let _ = event;
}
fn record(&self, span: &Id, values: &span::Record) {
let _ = (span, values);
}
fn record_follows_from(&self, span: &Id, follows: &Id) {
let _ = (span, follows);
}
fn enabled(&self, metadata: &Metadata) -> bool {
let _ = metadata;
true
}
fn enter(&self, span: &Id) {
let _ = span;
}
fn exit(&self, span: &Id) {
let _ = span;
}
}
/// Simulates a subscriber that records span data.
struct VisitingSubscriber(Mutex<String>);
struct Visitor<'a>(MutexGuard<'a, String>);
impl<'a> field::Visit for Visitor<'a> {
fn record_debug(&mut self, _field: &field::Field, value: &fmt::Debug) {
use std::fmt::Write;
let _ = write!(&mut *self.0, "{:?}", value);
}
}
impl tokio_trace::Subscriber for VisitingSubscriber {
fn new_span(&self, span: &span::Attributes) -> Id {
let mut visitor = Visitor(self.0.lock().unwrap());
span.record(&mut visitor);
Id::from_u64(0xDEADFACE)
}
fn record(&self, _span: &Id, values: &span::Record) {
let mut visitor = Visitor(self.0.lock().unwrap());
values.record(&mut visitor);
}
fn event(&self, event: &Event) {
let mut visitor = Visitor(self.0.lock().unwrap());
event.record(&mut visitor);
}
fn record_follows_from(&self, span: &Id, follows: &Id) {
let _ = (span, follows);
}
fn enabled(&self, metadata: &Metadata) -> bool {
let _ = metadata;
true
}
fn enter(&self, span: &Id) {
let _ = span;
}
fn exit(&self, span: &Id) {
let _ = span;
}
}
const N_SPANS: usize = 100;
#[bench]
fn span_no_fields(b: &mut Bencher) {
tokio_trace::subscriber::with_default(EnabledSubscriber, || {
b.iter(|| span!(Level::TRACE, "span"))
});
}
#[bench]
fn enter_span(b: &mut Bencher) {
tokio_trace::subscriber::with_default(EnabledSubscriber, || {
let span = span!(Level::TRACE, "span");
b.iter(|| test::black_box(span.enter(|| {})))
});
}
#[bench]
fn span_repeatedly(b: &mut Bencher) {
#[inline]
fn mk_span(i: u64) -> tokio_trace::Span {
span!(Level::TRACE, "span", i = i)
}
let n = test::black_box(N_SPANS);
tokio_trace::subscriber::with_default(EnabledSubscriber, || {
b.iter(|| (0..n).fold(mk_span(0), |_, i| mk_span(i as u64)))
});
}
#[bench]
fn span_with_fields(b: &mut Bencher) {
tokio_trace::subscriber::with_default(EnabledSubscriber, || {
b.iter(|| {
span!(
Level::TRACE,
"span",
foo = "foo",
bar = "bar",
baz = 3,
quuux = tokio_trace::field::debug(0.99)
)
})
});
}
#[bench]
fn span_with_fields_record(b: &mut Bencher) {
let subscriber = VisitingSubscriber(Mutex::new(String::from("")));
tokio_trace::subscriber::with_default(subscriber, || {
b.iter(|| {
span!(
Level::TRACE,
"span",
foo = "foo",
bar = "bar",
baz = 3,
quuux = tokio_trace::field::debug(0.99)
)
})
});
}
-144
View File
@@ -1,144 +0,0 @@
#[macro_use]
extern crate tokio_trace;
use tokio_trace::{
field::{Field, Visit},
span,
subscriber::{self, Subscriber},
Event, Id, Level, Metadata,
};
use std::{
collections::HashMap,
fmt,
sync::{
atomic::{AtomicUsize, Ordering},
Arc, RwLock, RwLockReadGuard,
},
};
#[derive(Clone)]
struct Counters(Arc<RwLock<HashMap<String, AtomicUsize>>>);
struct CounterSubscriber {
ids: AtomicUsize,
counters: Counters,
}
struct Count<'a> {
counters: RwLockReadGuard<'a, HashMap<String, AtomicUsize>>,
}
impl<'a> Visit for Count<'a> {
fn record_i64(&mut self, field: &Field, value: i64) {
if let Some(counter) = self.counters.get(field.name()) {
if value > 0 {
counter.fetch_add(value as usize, Ordering::Release);
} else {
counter.fetch_sub((value * -1) as usize, Ordering::Release);
}
};
}
fn record_u64(&mut self, field: &Field, value: u64) {
if let Some(counter) = self.counters.get(field.name()) {
counter.fetch_add(value as usize, Ordering::Release);
};
}
fn record_bool(&mut self, _: &Field, _: bool) {}
fn record_str(&mut self, _: &Field, _: &str) {}
fn record_debug(&mut self, _: &Field, _: &fmt::Debug) {}
}
impl CounterSubscriber {
fn visitor(&self) -> Count {
Count {
counters: self.counters.0.read().unwrap(),
}
}
}
impl Subscriber for CounterSubscriber {
fn register_callsite(&self, meta: &Metadata) -> subscriber::Interest {
let mut interest = subscriber::Interest::never();
for key in meta.fields() {
let name = key.name();
if name.contains("count") {
self.counters
.0
.write()
.unwrap()
.entry(name.to_owned())
.or_insert_with(|| AtomicUsize::new(0));
interest = subscriber::Interest::always();
}
}
interest
}
fn new_span(&self, new_span: &span::Attributes) -> Id {
new_span.record(&mut self.visitor());
let id = self.ids.fetch_add(1, Ordering::SeqCst);
Id::from_u64(id as u64)
}
fn record_follows_from(&self, _span: &Id, _follows: &Id) {
// unimplemented
}
fn record(&self, _: &Id, values: &span::Record) {
values.record(&mut self.visitor())
}
fn event(&self, event: &Event) {
event.record(&mut self.visitor())
}
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.fields().iter().any(|f| f.name().contains("count"))
}
fn enter(&self, _span: &Id) {}
fn exit(&self, _span: &Id) {}
}
impl Counters {
fn print_counters(&self) {
for (k, v) in self.0.read().unwrap().iter() {
println!("{}: {}", k, v.load(Ordering::Acquire));
}
}
fn new() -> (Self, CounterSubscriber) {
let counters = Counters(Arc::new(RwLock::new(HashMap::new())));
let subscriber = CounterSubscriber {
ids: AtomicUsize::new(1),
counters: counters.clone(),
};
(counters, subscriber)
}
}
fn main() {
let (counters, subscriber) = Counters::new();
tokio_trace::subscriber::with_default(subscriber, || {
let mut foo: u64 = 2;
span!(Level::TRACE, "my_great_span", foo_count = &foo).enter(|| {
foo += 1;
info!({ yak_shaved = true, yak_count = 1 }, "hi from inside my span");
span!(
Level::TRACE,
"my other span",
foo_count = &foo,
baz_count = 5
)
.enter(|| {
warn!({ yak_shaved = false, yak_count = -1 }, "failed to shave yak");
});
});
});
counters.print_counters();
}
-53
View File
@@ -1,53 +0,0 @@
//! A simple example demonstrating how one might implement a custom
//! subscriber.
//!
//! This subscriber implements a tree-structured logger similar to
//! the "compact" formatter in [`slog-term`]. The demo mimicks the
//! example output in the screenshot in the [`slog` README].
//!
//! Note that this logger isn't ready for actual production use.
//! Several corners were cut to make the example simple.
//!
//! [`slog-term`]: https://docs.rs/slog-term/2.4.0/slog_term/
//! [`slog` README]: https://github.com/slog-rs/slog#terminal-output-example
#[macro_use]
extern crate tokio_trace;
use tokio_trace::{field, Level};
mod sloggish_subscriber;
use self::sloggish_subscriber::SloggishSubscriber;
fn main() {
let subscriber = SloggishSubscriber::new(2);
tokio_trace::subscriber::with_default(subscriber, || {
span!(Level::TRACE, "", version = &field::display(5.0)).enter(|| {
span!(Level::TRACE, "server", host = "localhost", port = 8080).enter(|| {
info!("starting");
info!("listening");
let peer1 = span!(Level::TRACE, "conn", peer_addr = "82.9.9.9", port = 42381);
peer1.enter(|| {
debug!("connected");
debug!({ length = 2 }, "message received");
});
let peer2 = span!(Level::TRACE, "conn", peer_addr = "8.8.8.8", port = 18230);
peer2.enter(|| {
debug!("connected");
});
peer1.enter(|| {
warn!({ algo = "xor" }, "weak encryption requested");
debug!({ length = 8 }, "response sent");
debug!("disconnected");
});
peer2.enter(|| {
debug!({ length = 5 }, "message received");
debug!({ length = 8 }, "response sent");
debug!("disconnected");
});
warn!("internal error");
info!("exit");
})
});
});
}
@@ -1,285 +0,0 @@
//! A simple example demonstrating how one might implement a custom
//! subscriber.
//!
//! This subscriber implements a tree-structured logger similar to
//! the "compact" formatter in [`slog-term`]. The demo mimicks the
//! example output in the screenshot in the [`slog` README].
//!
//! Note that this logger isn't ready for actual production use.
//! Several corners were cut to make the example simple.
//!
//! [`slog-term`]: https://docs.rs/slog-term/2.4.0/slog_term/
//! [`slog` README]: https://github.com/slog-rs/slog#terminal-output-example
extern crate ansi_term;
extern crate humantime;
use self::ansi_term::{Color, Style};
use super::tokio_trace::{
self,
field::{Field, Visit},
Id, Level, Subscriber,
};
use std::{
cell::RefCell,
collections::HashMap,
fmt,
io::{self, Write},
sync::{
atomic::{AtomicUsize, Ordering},
Mutex,
},
thread,
time::SystemTime,
};
/// Tracks the currently executing span on a per-thread basis.
#[derive(Clone)]
pub struct CurrentSpanPerThread {
current: &'static thread::LocalKey<RefCell<Vec<Id>>>,
}
impl CurrentSpanPerThread {
pub fn new() -> Self {
thread_local! {
static CURRENT: RefCell<Vec<Id>> = RefCell::new(vec![]);
};
Self { current: &CURRENT }
}
/// Returns the [`Id`](::Id) of the span in which the current thread is
/// executing, or `None` if it is not inside of a span.
pub fn id(&self) -> Option<Id> {
self.current
.with(|current| current.borrow().last().cloned())
}
pub fn enter(&self, span: Id) {
self.current.with(|current| {
current.borrow_mut().push(span);
})
}
pub fn exit(&self) {
self.current.with(|current| {
let _ = current.borrow_mut().pop();
})
}
}
pub struct SloggishSubscriber {
// TODO: this can probably be unified with the "stack" that's used for
// printing?
current: CurrentSpanPerThread,
indent_amount: usize,
stderr: io::Stderr,
stack: Mutex<Vec<Id>>,
spans: Mutex<HashMap<Id, Span>>,
ids: AtomicUsize,
}
struct Span {
parent: Option<Id>,
kvs: Vec<(&'static str, String)>,
}
struct Event<'a> {
stderr: io::StderrLock<'a>,
comma: bool,
}
struct ColorLevel<'a>(&'a Level);
impl<'a> fmt::Display for ColorLevel<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
&Level::TRACE => Color::Purple.paint("TRACE"),
&Level::DEBUG => Color::Blue.paint("DEBUG"),
&Level::INFO => Color::Green.paint("INFO "),
&Level::WARN => Color::Yellow.paint("WARN "),
&Level::ERROR => Color::Red.paint("ERROR"),
}
.fmt(f)
}
}
impl Span {
fn new(parent: Option<Id>, attrs: &tokio_trace::span::Attributes) -> Self {
let mut span = Self {
parent,
kvs: Vec::new(),
};
attrs.record(&mut span);
span
}
}
impl Visit for Span {
fn record_debug(&mut self, field: &Field, value: &fmt::Debug) {
self.kvs.push((field.name(), format!("{:?}", value)))
}
}
impl<'a> Visit for Event<'a> {
fn record_debug(&mut self, field: &Field, value: &fmt::Debug) {
write!(
&mut self.stderr,
"{comma} ",
comma = if self.comma { "," } else { "" },
)
.unwrap();
let name = field.name();
if name == "message" {
write!(
&mut self.stderr,
"{}",
// Have to alloc here due to `ansi_term`'s API...
Style::new().bold().paint(format!("{:?}", value))
)
.unwrap();
self.comma = true;
} else {
write!(
&mut self.stderr,
"{}: {:?}",
Style::new().bold().paint(name),
value
)
.unwrap();
self.comma = true;
}
}
}
impl SloggishSubscriber {
pub fn new(indent_amount: usize) -> Self {
Self {
current: CurrentSpanPerThread::new(),
indent_amount,
stderr: io::stderr(),
stack: Mutex::new(vec![]),
spans: Mutex::new(HashMap::new()),
ids: AtomicUsize::new(1),
}
}
fn print_kvs<'a, I, K, V>(
&self,
writer: &mut impl Write,
kvs: I,
leading: &str,
) -> io::Result<()>
where
I: IntoIterator<Item = (K, V)>,
K: AsRef<str> + 'a,
V: fmt::Display + 'a,
{
let mut kvs = kvs.into_iter();
if let Some((k, v)) = kvs.next() {
write!(
writer,
"{}{}: {}",
leading,
Style::new().bold().paint(k.as_ref()),
v
)?;
}
for (k, v) in kvs {
write!(writer, ", {}: {}", Style::new().bold().paint(k.as_ref()), v)?;
}
Ok(())
}
fn print_indent(&self, writer: &mut impl Write, indent: usize) -> io::Result<()> {
for _ in 0..(indent * self.indent_amount) {
write!(writer, " ")?;
}
Ok(())
}
}
impl Subscriber for SloggishSubscriber {
fn enabled(&self, _metadata: &tokio_trace::Metadata) -> bool {
true
}
fn new_span(&self, span: &tokio_trace::span::Attributes) -> tokio_trace::Id {
let next = self.ids.fetch_add(1, Ordering::SeqCst) as u64;
let id = tokio_trace::Id::from_u64(next);
let span = Span::new(self.current.id(), span);
self.spans.lock().unwrap().insert(id.clone(), span);
id
}
fn record(&self, span: &tokio_trace::Id, values: &tokio_trace::span::Record) {
let mut spans = self.spans.lock().expect("mutex poisoned!");
if let Some(span) = spans.get_mut(span) {
values.record(span);
}
}
fn record_follows_from(&self, _span: &tokio_trace::Id, _follows: &tokio_trace::Id) {
// unimplemented
}
fn enter(&self, span_id: &tokio_trace::Id) {
self.current.enter(span_id.clone());
let mut stderr = self.stderr.lock();
let mut stack = self.stack.lock().unwrap();
let spans = self.spans.lock().unwrap();
let data = spans.get(span_id);
let parent = data.and_then(|span| span.parent.as_ref());
if stack.iter().any(|id| id == span_id) {
// We are already in this span, do nothing.
return;
} else {
let indent = if let Some(idx) = stack
.iter()
.position(|id| parent.map(|p| id == p).unwrap_or(false))
{
let idx = idx + 1;
stack.truncate(idx);
idx
} else {
stack.clear();
0
};
self.print_indent(&mut stderr, indent).unwrap();
stack.push(span_id.clone());
if let Some(data) = data {
self.print_kvs(&mut stderr, data.kvs.iter().map(|(k, v)| (k, v)), "")
.unwrap();
}
write!(&mut stderr, "\n").unwrap();
}
}
fn event(&self, event: &tokio_trace::Event) {
let mut stderr = self.stderr.lock();
let indent = self.stack.lock().unwrap().len();
self.print_indent(&mut stderr, indent).unwrap();
write!(
&mut stderr,
"{timestamp} {level} {target}",
timestamp = humantime::format_rfc3339_seconds(SystemTime::now()),
level = ColorLevel(event.metadata().level()),
target = &event.metadata().target(),
)
.unwrap();
let mut visitor = Event {
stderr,
comma: false,
};
event.record(&mut visitor);
write!(&mut visitor.stderr, "\n").unwrap();
}
#[inline]
fn exit(&self, _span: &tokio_trace::Id) {
// TODO: unify stack with current span
self.current.exit();
}
fn drop_span(&self, _id: tokio_trace::Id) {
// TODO: GC unneeded spans.
}
}
-56
View File
@@ -1,56 +0,0 @@
//! Structured data associated with `Span`s and `Event`s.
pub use tokio_trace_core::field::*;
use Metadata;
/// Trait implemented to allow a type to be used as a field key.
///
/// **Note**: Although this is implemented for both the [`Field`] type *and* any
/// type that can be borrowed as an `&str`, only `Field` allows _O_(1) access.
/// Indexing a field with a string results in an iterative search that performs
/// string comparisons. Thus, if possible, once the key for a field is known, it
/// should be used whenever possible.
///
/// [`Field`]: ../struct.Field.html
pub trait AsField: ::sealed::Sealed {
/// Attempts to convert `&self` into a `Field` with the specified `metadata`.
///
/// If `metadata` defines this field, then the field is returned. Otherwise,
/// this returns `None`.
fn as_field(&self, metadata: &Metadata) -> Option<Field>;
}
// ===== impl AsField =====
impl AsField for Field {
#[inline]
fn as_field(&self, metadata: &Metadata) -> Option<Field> {
if self.callsite() == metadata.callsite() {
Some(self.clone())
} else {
None
}
}
}
impl<'a> AsField for &'a Field {
#[inline]
fn as_field(&self, metadata: &Metadata) -> Option<Field> {
if self.callsite() == metadata.callsite() {
Some((*self).clone())
} else {
None
}
}
}
impl AsField for str {
#[inline]
fn as_field(&self, metadata: &Metadata) -> Option<Field> {
metadata.fields().field(&self)
}
}
impl ::sealed::Sealed for Field {}
impl<'a> ::sealed::Sealed for &'a Field {}
impl ::sealed::Sealed for str {}
-137
View File
@@ -1,137 +0,0 @@
//! Trace verbosity level filtering.
//!
//! # Compile time filters
//!
//! Trace verbosity levels can be statically disabled at compile time via Cargo
//! features, similar to the [`log` crate]. Trace instrumentation at disabled
//! levels will be skipped and will not even be present in the resulting binary
//! unless the verbosity level is specified dynamically. This level is
//! configured separately for release and debug builds. The features are:
//!
//! * `max_level_off`
//! * `max_level_error`
//! * `max_level_warn`
//! * `max_level_info`
//! * `max_level_debug`
//! * `max_level_trace`
//! * `release_max_level_off`
//! * `release_max_level_error`
//! * `release_max_level_warn`
//! * `release_max_level_info`
//! * `release_max_level_debug`
//! * `release_max_level_trace`
//!
//! These features control the value of the `STATIC_MAX_LEVEL` constant. The
//! instrumentation macros macros check this value before recording an event or
//! constructing a span. By default, no levels are disabled.
//!
//! For example, a crate can disable trace level instrumentation in debug builds
//! and trace, debug, and info level instrumentation in release builds with the
//! following configuration:
//!
//! ```toml
//! [dependencies]
//! tokio-trace = { version = "0.1", features = ["max_level_debug", "release_max_level_warn"] }
//! ```
//!
//! [`log` crate]: https://docs.rs/log/0.4.6/log/#compile-time-filters
use std::cmp::Ordering;
use tokio_trace_core::Level;
/// A filter comparable to trace verbosity `Level`.
///
/// If a `Level` is considered less than a `LevelFilter`, it should be
/// considered disabled; if greater than or equal to the `LevelFilter`, that
/// level is enabled.
///
/// Note that this is essentially identical to the `Level` type, but with the
/// addition of an `OFF` level that completely disables all trace
/// instrumentation.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct LevelFilter(Option<Level>);
impl LevelFilter {
/// The "off" level.
///
/// Designates that trace instrumentation should be completely disabled.
pub const OFF: LevelFilter = LevelFilter(None);
/// The "error" level.
///
/// Designates very serious errors.
pub const ERROR: LevelFilter = LevelFilter(Some(Level::ERROR));
/// The "warn" level.
///
/// Designates hazardous situations.
pub const WARN: LevelFilter = LevelFilter(Some(Level::WARN));
/// The "info" level.
///
/// Designates useful information.
pub const INFO: LevelFilter = LevelFilter(Some(Level::INFO));
/// The "debug" level.
///
/// Designates lower priority information.
pub const DEBUG: LevelFilter = LevelFilter(Some(Level::DEBUG));
/// The "trace" level.
///
/// Designates very low priority, often extremely verbose, information.
pub const TRACE: LevelFilter = LevelFilter(Some(Level::TRACE));
}
impl PartialEq<LevelFilter> for Level {
fn eq(&self, other: &LevelFilter) -> bool {
match other.0 {
None => false,
Some(ref level) => self.eq(level),
}
}
}
impl PartialOrd<LevelFilter> for Level {
fn partial_cmp(&self, other: &LevelFilter) -> Option<Ordering> {
match other.0 {
None => Some(Ordering::Less),
Some(ref level) => self.partial_cmp(level),
}
}
}
/// The statically configured maximum trace level.
///
/// See the [module-level documentation] for information on how to configure
/// this.
///
/// This value is checked by the `event!` and `span!` macros. Code that
/// manually constructs events or spans via the `Event::record` function or
/// `Span` constructors should compare the level against this value to
/// determine if those spans or events are enabled.
///
/// [module-level documentation]: ../index.html#compile-time-filters
pub const STATIC_MAX_LEVEL: LevelFilter = MAX_LEVEL;
cfg_if! {
if #[cfg(all(not(debug_assertions), feature = "release_max_level_off"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::OFF;
} else if #[cfg(all(not(debug_assertions), feature = "release_max_level_error"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::ERROR;
} else if #[cfg(all(not(debug_assertions), feature = "release_max_level_warn"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::WARN;
} else if #[cfg(all(not(debug_assertions), feature = "release_max_level_info"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::INFO;
} else if #[cfg(all(not(debug_assertions), feature = "release_max_level_debug"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::DEBUG;
} else if #[cfg(all(not(debug_assertions), feature = "release_max_level_trace"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::TRACE;
} else if #[cfg(feature = "max_level_off")] {
const MAX_LEVEL: LevelFilter = LevelFilter::OFF;
} else if #[cfg(feature = "max_level_error")] {
const MAX_LEVEL: LevelFilter = LevelFilter::ERROR;
} else if #[cfg(feature = "max_level_warn")] {
const MAX_LEVEL: LevelFilter = LevelFilter::WARN;
} else if #[cfg(feature = "max_level_info")] {
const MAX_LEVEL: LevelFilter = LevelFilter::INFO;
} else if #[cfg(feature = "max_level_debug")] {
const MAX_LEVEL: LevelFilter = LevelFilter::DEBUG;
} else {
const MAX_LEVEL: LevelFilter = LevelFilter::TRACE;
}
}
-437
View File
@@ -1,437 +0,0 @@
#![doc(html_root_url = "https://docs.rs/tokio-trace/0.1.0")]
#![deny(missing_debug_implementations, missing_docs, unreachable_pub)]
#![cfg_attr(test, deny(warnings))]
//! A scoped, structured logging and diagnostics system.
//!
//! # Overview
//!
//! `tokio-trace` is a framework for instrumenting Rust programs to collect
//! structured, event-based diagnostic information.
//!
//! In asynchronous systems like Tokio, interpreting traditional log messages can
//! often be quite challenging. Since individual tasks are multiplexed on the same
//! thread, associated events and log lines are intermixed making it difficult to
//! trace the logic flow. `tokio-trace` expands upon logging-style diagnostics by
//! allowing libraries and applications to record structured events with additional
//! information about *temporality* and *causality* — unlike a log message, a span
//! in `tokio-trace` has a beginning and end time, may be entered and exited by the
//! flow of execution, and may exist within a nested tree of similar spans. In
//! addition, `tokio-trace` spans are *structured*, with the ability to record typed
//! data as well as textual messages.
//!
//! The `tokio-trace` crate provides the APIs necessary for instrumenting libraries
//! and applications to emit trace data.
//!
//! # Core Concepts
//!
//! The core of `tokio-trace`'s API is composed of `Event`s, `Span`s, and
//! `Subscriber`s. We'll cover these in turn.
//!
//! ## `Span`s
//!
//! A [`Span`] represents a _period of time_ during which a program was executing
//! in some context. A thread of execution is said to _enter_ a span when it
//! begins executing in that context, and to _exit_ the span when switching to
//! another context. The span in which a thread is currently executing is
//! referred to as the _current_ span.
//!
//! For example:
//! ```
//! #[macro_use]
//! extern crate tokio_trace;
//!
//! use tokio_trace::Level;
//!
//! # fn main() {
//! span!(Level::TRACE, "my_span").enter(|| {
//! // perform some work in the context of `my_span`...
//! });
//! # }
//!```
//!
//! Spans form a tree structure — unless it is a root span, all spans have a
//! _parent_, and may have one or more _children_. When a new span is created,
//! the current span becomes the new span's parent. The total execution time of
//! a span consists of the time spent in that span and in the entire subtree
//! represented by its children. Thus, a parent span always lasts for at least
//! as long as the longest-executing span in its subtree.
//!
//! ```
//! # #[macro_use] extern crate tokio_trace;
//! # use tokio_trace::Level;
//! # fn main() {
//! // this span is considered the "root" of a new trace tree:
//! span!(Level::INFO, "root").enter(|| {
//! // since we are now inside "root", this span is considered a child
//! // of "root":
//! span!(Level::DEBUG, "outer_child").enter(|| {
//! // this span is a child of "outer_child", which is in turn a
//! // child of "root":
//! span!(Level::TRACE, "inner_child").enter(|| {
//! // and so on...
//! });
//! });
//! });
//! # }
//!```
//!
//! In addition, data may be associated with spans. A span may have _fields_ —
//! a set of key-value pairs describing the state of the program during that
//! span; an optional name, and metadata describing the source code location
//! where the span was originally entered.
//! ```
//! # #[macro_use] extern crate tokio_trace;
//! # use tokio_trace::Level;
//! # fn main() {
//! // construct a new span with three fields:
//! // - "foo", with a value of 42,
//! // - "bar", with the value "false"
//! // - "baz", with no initial value
//! let my_span = span!(Level::INFO, "my_span", foo = 42, bar = false, baz);
//!
//! // record a value for the field "baz" declared above:
//! my_span.record("baz", &"hello world");
//! # }
//!```
//!
//! ### When to use spans
//!
//! As a rule of thumb, spans should be used to represent discrete units of work
//! (e.g., a given request's lifetime in a server) or periods of time spent in a
//! given context (e.g., time spent interacting with an instance of an external
//! system, such as a database).
//!
//! Which scopes in a program correspond to new spans depend somewhat on user
//! intent. For example, consider the case of a loop in a program. Should we
//! construct one span and perform the entire loop inside of that span, like:
//! ```rust
//! # #[macro_use] extern crate tokio_trace;
//! # use tokio_trace::Level;
//! # fn main() {
//! # let n = 1;
//! span!(Level::TRACE, "my loop").enter(|| {
//! for i in 0..n {
//! # let _ = i;
//! // ...
//! }
//! })
//! # }
//! ```
//! Or, should we create a new span for each iteration of the loop, as in:
//! ```rust
//! # #[macro_use] extern crate tokio_trace;
//! # use tokio_trace::Level;
//! # fn main() {
//! # let n = 1u64;
//! for i in 0..n {
//! # let _ = i;
//! span!(Level::TRACE, "my loop", iteration = i).enter(|| {
//! // ...
//! })
//! }
//! # }
//! ```
//!
//! Depending on the circumstances, we might want to do either, or both. For
//! example, if we want to know how long was spent in the loop overall, we would
//! create a single span around the entire loop; whereas if we wanted to know how
//! much time was spent in each individual iteration, we would enter a new span
//! on every iteration.
//!
//! ## Events
//!
//! An [`Event`] represents a _point_ in time. It signifies something that
//! happened while the trace was executing. `Event`s are comparable to the log
//! records emitted by unstructured logging code, but unlike a typical log line,
//! an `Event` may occur within the context of a `Span`. Like a `Span`, it
//! may have fields, and implicitly inherits any of the fields present on its
//! parent span.
//!
//! For example:
//! ```
//! # #[macro_use] extern crate tokio_trace;
//! # use tokio_trace::Level;
//! # fn main() {
//! // records an event outside of any span context:
//! event!(Level::INFO, "something happened");
//!
//! span!(Level::INFO, "my_span").enter(|| {
//! // records an event within "my_span".
//! event!(Level::DEBUG, "something happened inside my_span");
//! });
//! # }
//!```
//!
//! Essentially, `Event`s exist to bridge the gap between traditional
//! unstructured logging and span-based tracing. Similar to log records, they
//! may be recorded at a number of levels, and can have unstructured,
//! human-readable messages; however, they also carry key-value data and exist
//! within the context of the tree of spans that comprise a trace. Thus,
//! individual log record-like events can be pinpointed not only in time, but
//! in the logical execution flow of the system.
//!
//! Events are represented as a special case of spans — they are created, they
//! may have fields added, and then they close immediately, without being
//! entered.
//!
//! In general, events should be used to represent points in time _within_ a
//! span — a request returned with a given status code, _n_ new items were
//! taken from a queue, and so on.
//!
//! ## `Subscriber`s
//!
//! As `Span`s and `Event`s occur, they are recorded or aggregated by
//! implementations of the [`Subscriber`] trait. `Subscriber`s are notified
//! when an `Event` takes place and when a `Span` is entered or exited. These
//! notifications are represented by the following `Subscriber` trait methods:
//! + [`observe_event`], called when an `Event` takes place,
//! + [`enter`], called when execution enters a `Span`,
//! + [`exit`], called when execution exits a `Span`
//!
//! In addition, subscribers may implement the [`enabled`] function to _filter_
//! the notifications they receive based on [metadata] describing each `Span`
//! or `Event`. If a call to `Subscriber::enabled` returns `false` for a given
//! set of metadata, that `Subscriber` will *not* be notified about the
//! corresponding `Span` or `Event`. For performance reasons, if no currently
//! active subscribers express interest in a given set of metadata by returning
//! `true`, then the corresponding `Span` or `Event` will never be constructed.
//!
//! # Usage
//!
//! First, add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! tokio-trace = "0.1"
//! ```
//!
//! Next, add this to your crate:
//!
//! ```rust
//! #[macro_use]
//! extern crate tokio_trace;
//! # fn main() {}
//! ```
//!
//! `Span`s are constructed using the `span!` macro, and then _entered_
//! to indicate that some code takes place within the context of that `Span`:
//!
//! ```rust
//! # #[macro_use]
//! # extern crate tokio_trace;
//! # use tokio_trace::Level;
//! # fn main() {
//! // Construct a new span named "my span" with trace log level.
//! let span = span!(Level::TRACE, "my span");
//! span.enter(|| {
//! // Any trace events in this closure or code called by it will occur within
//! // the span.
//! });
//! // Dropping the span will close it, indicating that it has ended.
//! # }
//! ```
//!
//! `Event`s are created using the `event!` macro, and are recorded when the
//! event is dropped:
//!
//! ```rust
//! # #[macro_use]
//! # extern crate tokio_trace;
//! # fn main() {
//! use tokio_trace::Level;
//! event!(Level::INFO, "something has happened!");
//! # }
//! ```
//!
//! Users of the [`log`] crate should note that `tokio-trace` exposes a set of
//! macros for creating `Event`s (`trace!`, `debug!`, `info!`, `warn!`, and
//! `error!`) which may be invoked with the same syntax as the similarly-named
//! macros from the `log` crate. Often, the process of converting a project to
//! use `tokio-trace` can begin with a simple drop-in replacement.
//!
//! Let's consider the `log` crate's yak-shaving example:
//!
//! ```rust
//! #[macro_use]
//! extern crate tokio_trace;
//! use tokio_trace::{field, Level};
//! # #[derive(Debug)] pub struct Yak(String);
//! # impl Yak { fn shave(&mut self, _: u32) {} }
//! # fn find_a_razor() -> Result<u32, u32> { Ok(1) }
//! # fn main() {
//! pub fn shave_the_yak(yak: &mut Yak) {
//! // Create a new span for this invocation of `shave_the_yak`, annotated
//! // with the yak being shaved as a *field* on the span.
//! span!(Level::TRACE, "shave_the_yak", yak = field::debug(&yak)).enter(|| {
//! // Since the span is annotated with the yak, it is part of the context
//! // for everything happening inside the span. Therefore, we don't need
//! // to add it to the message for this event, as the `log` crate does.
//! info!(target: "yak_events", "Commencing yak shaving");
//!
//! loop {
//! match find_a_razor() {
//! Ok(razor) => {
//! // We can add the razor as a field rather than formatting it
//! // as part of the message, allowing subscribers to consume it
//! // in a more structured manner:
//! info!({ razor = field::display(razor) }, "Razor located");
//! yak.shave(razor);
//! break;
//! }
//! Err(err) => {
//! // However, we can also create events with formatted messages,
//! // just as we would for log records.
//! warn!("Unable to locate a razor: {}, retrying", err);
//! }
//! }
//! }
//! })
//! }
//! # }
//! ```
//!
//! You can find examples showing how to use this crate in the examples
//! directory.
//!
//! ## In libraries
//!
//! Libraries should link only to the `tokio-trace` crate, and use the provided
//! macros to record whatever information will be useful to downstream
//! consumers.
//!
//! ## In executables
//!
//! In order to record trace events, executables have to use a `Subscriber`
//! implementation compatible with `tokio-trace`. A `Subscriber` implements a
//! way of collecting trace data, such as by logging it to standard output.
//!
//! Unlike the `log` crate, `tokio-trace` does *not* use a global `Subscriber`
//! which is initialized once. Instead, it follows the `tokio` pattern of
//! executing code in a context. For example:
//!
//! ```rust
//! #[macro_use]
//! extern crate tokio_trace;
//! # pub struct FooSubscriber;
//! # use tokio_trace::{span::{Id, Attributes, Record}, Metadata};
//! # impl tokio_trace::Subscriber for FooSubscriber {
//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
//! # fn record(&self, _: &Id, _: &Record) {}
//! # fn event(&self, _: &tokio_trace::Event) {}
//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
//! # fn enabled(&self, _: &Metadata) -> bool { false }
//! # fn enter(&self, _: &Id) {}
//! # fn exit(&self, _: &Id) {}
//! # }
//! # impl FooSubscriber {
//! # fn new() -> Self { FooSubscriber }
//! # }
//! # fn main() {
//!
//! let my_subscriber = FooSubscriber::new();
//!
//! tokio_trace::subscriber::with_default(my_subscriber, || {
//! // Any trace events generated in this closure or by functions it calls
//! // will be collected by `my_subscriber`.
//! })
//! # }
//! ```
//!
//! This approach allows trace data to be collected by multiple subscribers
//! within different contexts in the program. Alternatively, a single subscriber
//! may be constructed by the `main` function and all subsequent code executed
//! with that subscriber as the default. Any trace events generated outside the
//! context of a subscriber will not be collected.
//!
//! The executable itself may use the `tokio-trace` crate to instrument itself
//! as well.
//!
//! The [`tokio-trace-nursery`] repository contains less stable crates designed
//! to be used with the `tokio-trace` ecosystem. It includes a collection of
//! `Subscriber` implementations, as well as utility and adapter crates.
//!
//! In particular, the following `tokio-trace-nursery` crates are likely to be
//! of interest:
//!
//! - [`tokio-trace-futures`] provides a compatibility layer with the `futures`
//! crate, allowing spans to be attached to `Future`s, `Stream`s, and `Executor`s.
//! - [`tokio-trace-fmt`] provides a `Subscriber` implementation for
//! logging formatted trace data to stdout, with similar filtering and
//! formatting to the `env-logger` crate.
//! - [`tokio-trace-log`] provides a compatibility layer with the `log` crate,
//! allowing log `Record`s to be recorded as `tokio-trace` `Event`s within the
//! trace tree. This is useful when a project using `tokio-trace` have
//! dependencies which use `log`.
//!
//!
//! ## Crate Feature Flags
//!
//! The following crate feature flags are available:
//!
//! * A set of features controlling the [static verbosity level].
//! * `log` causes trace instrumentation points to emit [`log`] records as well
//! as trace events. This is inteded for use in libraries whose users may be
//! using either `tokio-trace` or `log`.
//!
//! ```toml
//! [dependencies]
//! tokio-trace = { version = "0.1", features = ["log"] }
//! ```
//!
//! [`log`]: https://docs.rs/log/0.4.6/log/
//! [`Span`]: span/struct.Span
//! [`Event`]: struct.Event.html
//! [`Subscriber`]: subscriber/trait.Subscriber.html
//! [`observe_event`]: subscriber/trait.Subscriber.html#tymethod.observe_event
//! [`enter`]: subscriber/trait.Subscriber.html#tymethod.enter
//! [`exit`]: subscriber/trait.Subscriber.html#tymethod.exit
//! [`enabled`]: subscriber/trait.Subscriber.html#tymethod.enabled
//! [metadata]: struct.Metadata.html
//! [`tokio-trace-nursery`]: https://github.com/tokio-rs/tokio-trace-nursery
//! [`tokio-trace-futures`]: https://github.com/tokio-rs/tokio-trace-nursery/tree/master/tokio-trace-futures
//! [`tokio-trace-fmt`]: https://github.com/tokio-rs/tokio-trace-nursery/tree/master/tokio-trace-fmt
//! [`tokio-trace-log`]: https://github.com/tokio-rs/tokio-trace-nursery/tree/master/tokio-trace-log
//! [static verbosity level]: level_filters/index.html#compile-time-filters
#[macro_use]
extern crate cfg_if;
extern crate tokio_trace_core;
#[cfg(feature = "log")]
#[doc(hidden)]
pub extern crate log;
// Somehow this `use` statement is necessary for us to re-export the `core`
// macros on Rust 1.26.0. I'm not sure how this makes it work, but it does.
#[allow(unused_imports)]
#[doc(hidden)]
use tokio_trace_core::*;
pub use self::{
dispatcher::Dispatch,
event::Event,
field::Value,
span::Span,
subscriber::Subscriber,
tokio_trace_core::{dispatcher, event, Level, Metadata},
};
#[doc(hidden)]
pub use self::{
span::Id,
tokio_trace_core::{
callsite::{self, Callsite},
metadata,
},
};
#[macro_use]
mod macros;
pub mod field;
pub mod level_filters;
pub mod span;
pub mod subscriber;
mod sealed {
pub trait Sealed {}
}

Some files were not shown because too many files have changed in this diff Show More