Compare commits

...
Author SHA1 Message Date
Carl Lerche da186a7859 prepare tokio-sync v0.1.7 release. (#1650) 2019-10-10 13:16:36 -07:00
Carl Lerche 2117ce7bac sync: fix mem leak in oneshot on task migration (#1649)
When polling the task, the current waker is saved to the oneshot state.
When the handle is migrated to a new task and polled again, the waker
must be swaped from the old waker to the new waker. In some cases, there
is a potential for the old waker to leak.

This bug was caught by loom with the recently added memory leak
detection.

Backport of #1648.
2019-10-10 12:47:53 -07:00
David Kellum 39f369f686 v0.1.x: Don't deny warnings (#1368)
This is just too aggressive for a stable maintenance branch of tokio,
in that new rust release warnings are prooving too hard to fix.
2019-09-30 18:28:26 -04:00
Lucio Franco 83e8fff090 reactor: Remove extra semi colon (#1616)
* reactor: Remove extra semi colon

* fmt
2019-09-30 15:06:17 -04:00
David Kellum f545d1276b v0.1.x: stage -threadpool 0.1.16 -reactor 0.1.10 releases (#1604)
* upgrade to rand 0.7.0 (MSRV 1.32)

* upgrade to parking_lot 0.9.0

* Remove last non-dev dependency on rand crate (#1324)

Use std RandomState for XorShift seeding. This allows dropping _rand_
crate dep here, accept as a dev dependency for tests or benchmarks.

* increase CI MSRV to 1.31.0

* increase nightly for CI TSAN tests

* add TSAN suppressions for recent rand related updates

* make latest TSAN suppression patterns more general

* upgrade tempfile dev dep for common rand version

But avoid tempfile 3.2 for now, since history demonstrates it bumps
rand versions and MSRV in MINOR updates.

* update (dev dep) env_logger to latest 0.6

* reactor, threadpool: bump PATCH versions, doc links, change logs [ci-release]
2019-09-30 14:21:56 -04:00
Roman Proskuryakov 59fb5b9a7d Add more unit tests for UdpFramed (#1522) 2019-08-30 22:29:02 -04:00
Lucio Franco 57ba3a7fbc udp: Prep release v0.1.5 (#1519)
Signed-off-by: Lucio Franco <[email protected]>
2019-08-30 17:51:48 -04:00
Lucio Franco c3c3481d74 udp: Fix UdpFramed decode (#1517) 2019-08-30 11:13:54 -07:00
Lucio Franco 7b39388415 Prep tokio-udp 0.1.4 release (#1503)
* Fix warnings in udp tests

* Prep tokio-udp 0.1.4 release
2019-08-28 12:16:40 -04:00
John Doneth 11a1ce2721 v0.1.x: Fix UdpFramed with regards to Decode (#1444)
* add test for using LinesCodec with UdpFramed

* fix UdpFramed decode

* rustfmt
2019-08-20 15:57:04 -04:00
David Kellum c9532e49d7 v0.1.x lint fix, MSRV 1.28.0 updates (#1451)
* use dyn Trait syntax where appropriate

recent rust nightly started warning that not using `dyn` was
deprecated. This requires MSRV 1.27.0+.

* rustfmt fallout from dyn additions

* stop explicit allow of rust_2018_idioms

* more dyn Trait syntax

* drop tokio-macros from 0.1.x workspace

Since tokio-macros specifies an edition=2018, we would otherwise
require MSRV 1.31.0 to build/test it. And tokio-macros isn't used with
tokio 0.1.x.

* reactor: narrow tokio-io-pool dev dep to 0.1.4

Since 0.1.5-6 is now a edition=2018 crate, which has effective MSRV
1.31.0.

* narrow tempfile dev-dep to avoid MSRV bump

tempfile 3.1.0 pulls in rand 0.7.0 and is MSRV 1.32.0

* narrow flate2 dev-dep to avoid MSRV bump

flate2 1.0.10-11 have MSRV 1.34.0.

github refs: alexcrichton/flate2-rs#207

* fs: drop deprecated tempdir crate use in tests

In particular because it pulls in old rand duplicates. Replace use
with tempfile::tempdir() which has been available since tempfile
3.0.0.

backport-of: #1312

* increase CI MSRV to 1.28.0
2019-08-15 18:28:56 -04:00
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
162 changed files with 651 additions and 9365 deletions
-2
View File
@@ -32,8 +32,6 @@ task:
test_script:
- . $HOME/.cargo/env
- cargo test --all
- (cd tokio-trace/test-log-support && cargo test)
- (cd tokio-trace/test_static_max_level_features && cargo test)
- cargo doc --all
i686_test_script:
- . $HOME/.cargo/env
-3
View File
@@ -9,7 +9,6 @@ members = [
"tokio-fs",
"tokio-futures",
"tokio-io",
"tokio-macros",
"tokio-reactor",
"tokio-signal",
"tokio-sync",
@@ -18,8 +17,6 @@ members = [
"tokio-timer",
"tokio-tcp",
"tokio-tls",
"tokio-trace",
"tokio-trace/tokio-trace-core",
"tokio-udp",
"tokio-uds",
]
+17
View File
@@ -170,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 -5
View File
@@ -46,10 +46,6 @@ jobs:
- tokio-threadpool
- tokio-timer
- tokio-test
- tokio-trace
- tokio-trace/tokio-trace-core
- tokio-trace/test-log-support
- tokio-trace/test_static_max_level_features
- template: ci/azure-cargo-check.yml
parameters:
@@ -68,6 +64,7 @@ jobs:
- udp
- uds
- sync
- experimental-tracing
tokio-buf:
- util
@@ -94,7 +91,7 @@ jobs:
- template: ci/azure-check-minrust.yml
parameters:
name: minrust
rust_version: 1.26.0
rust_version: 1.31.0
- template: ci/azure-tsan.yml
parameters:
-1
View File
@@ -1,5 +1,4 @@
#![feature(test)]
#![deny(warnings)]
extern crate test;
#[macro_use]
-1
View File
@@ -1,7 +1,6 @@
// Measure cost of different operations
// to get a sense of performance tradeoffs
#![feature(test)]
#![deny(warnings)]
extern crate mio;
extern crate test;
-1
View File
@@ -1,5 +1,4 @@
#![feature(test)]
#![deny(warnings)]
extern crate futures;
extern crate tokio;
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
steps:
- template: azure-install-rust.yml
parameters:
rust_version: nightly-2018-11-18
rust_version: nightly-2019-07-17
- template: azure-patch-crates.yml
- script: |
-2
View File
@@ -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" }
+7
View File
@@ -35,3 +35,10 @@ race:WorkerEntry::set_next_sleeper
# This ignores a false positive caused by `thread::park()`/`thread::unpark()`.
# See: https://github.com/rust-lang/rust/pull/54806#issuecomment-436193353
race:pthread_cond_destroy
# Recent rand dependency updates and seeding changes have introduced
# lazy_static's and other racy code. See:
# https://github.com/tokio-rs/tokio/pull/1358#issuecomment-516172383
race:RandomState*::build_hasher
race:lazy_static::
race:c2_chacha::guts
-1
View File
@@ -1,6 +1,5 @@
#![doc(html_root_url = "https://docs.rs/tokio-buf/0.1.1")]
#![deny(missing_docs, missing_debug_implementations, unreachable_pub)]
#![cfg_attr(test, deny(warnings))]
//! Asynchronous stream of bytes.
//!
+1 -1
View File
@@ -4,4 +4,4 @@ use tokio_buf::BufStream;
// Ensures that `BufStream` can be a trait object
#[allow(dead_code)]
fn obj(_: &mut BufStream<Item = u32, Error = ()>) {}
fn obj(_: &mut dyn BufStream<Item = u32, Error = ()>) {}
+1 -1
View File
@@ -1,4 +1,4 @@
#![deny(missing_docs, missing_debug_implementations, warnings)]
#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-codec/0.1.1")]
//! Utilities for encoding and decoding frames.
+20 -12
View File
@@ -1,5 +1,5 @@
#![doc(html_root_url = "https://docs.rs/tokio-current-thread/0.1.6")]
#![deny(warnings, missing_docs, missing_debug_implementations)]
#![deny(missing_docs, missing_debug_implementations)]
//! A single-threaded executor which executes tasks on the same thread from which
//! they are spawned.
@@ -64,7 +64,7 @@ pub struct CurrentThread<P: Park = ParkThread> {
spawn_handle: Handle,
/// Receiver for futures spawned from other threads
spawn_receiver: mpsc::Receiver<Box<Future<Item = (), Error = ()> + Send + 'static>>,
spawn_receiver: mpsc::Receiver<Box<dyn Future<Item = (), Error = ()> + Send + 'static>>,
/// The thread-local ID assigned to this executor.
id: u64,
@@ -186,11 +186,15 @@ struct Borrow<'a, U: 'a> {
}
trait SpawnLocal {
fn spawn_local(&mut self, future: Box<Future<Item = (), Error = ()>>, already_counted: bool);
fn spawn_local(
&mut self,
future: Box<dyn Future<Item = (), Error = ()>>,
already_counted: bool,
);
}
struct CurrentRunner {
spawn: Cell<Option<*mut SpawnLocal>>,
spawn: Cell<Option<*mut dyn SpawnLocal>>,
id: Cell<Option<u64>>,
}
@@ -424,7 +428,7 @@ impl<P: Park> Drop for CurrentThread<P> {
impl tokio_executor::Executor for CurrentThread {
fn spawn(
&mut self,
future: Box<Future<Item = (), Error = ()> + Send>,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError> {
self.borrow().spawn_local(future, false);
Ok(())
@@ -629,7 +633,7 @@ impl<'a, P: Park> fmt::Debug for Entered<'a, P> {
/// Handle to spawn a future on the corresponding `CurrentThread` instance
#[derive(Clone)]
pub struct Handle {
sender: mpsc::Sender<Box<Future<Item = (), Error = ()> + Send + 'static>>,
sender: mpsc::Sender<Box<dyn Future<Item = (), Error = ()> + Send + 'static>>,
num_futures: Arc<atomic::AtomicUsize>,
shut_down: Cell<bool>,
notify: executor::NotifyHandle,
@@ -731,7 +735,7 @@ impl TaskExecutor {
/// Spawn a future onto the current `CurrentThread` instance.
pub fn spawn_local(
&mut self,
future: Box<Future<Item = (), Error = ()>>,
future: Box<dyn Future<Item = (), Error = ()>>,
) -> Result<(), SpawnError> {
CURRENT.with(|current| match current.spawn.get() {
Some(spawn) => {
@@ -746,7 +750,7 @@ impl TaskExecutor {
impl tokio_executor::Executor for TaskExecutor {
fn spawn(
&mut self,
future: Box<Future<Item = (), Error = ()> + Send>,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError> {
self.spawn_local(future)
}
@@ -791,7 +795,11 @@ impl<'a, U: Unpark> Borrow<'a, U> {
}
impl<'a, U: Unpark> SpawnLocal for Borrow<'a, U> {
fn spawn_local(&mut self, future: Box<Future<Item = (), Error = ()>>, already_counted: bool) {
fn spawn_local(
&mut self,
future: Box<dyn Future<Item = (), Error = ()>>,
already_counted: bool,
) {
if !already_counted {
// NOTE: we have a borrow of the Runtime, so we know that it isn't shut down.
// NOTE: += 2 since LSB is the shutdown bit
@@ -804,7 +812,7 @@ impl<'a, U: Unpark> SpawnLocal for Borrow<'a, U> {
// ===== impl CurrentRunner =====
impl CurrentRunner {
fn set_spawn<F, R>(&self, spawn: &mut SpawnLocal, f: F) -> R
fn set_spawn<F, R>(&self, spawn: &mut dyn SpawnLocal, f: F) -> R
where
F: FnOnce() -> R,
{
@@ -819,14 +827,14 @@ impl CurrentRunner {
let _reset = Reset(self);
let spawn = unsafe { hide_lt(spawn as *mut SpawnLocal) };
let spawn = unsafe { hide_lt(spawn as *mut dyn SpawnLocal) };
self.spawn.set(Some(spawn));
f()
}
}
unsafe fn hide_lt<'a>(p: *mut (SpawnLocal + 'a)) -> *mut (SpawnLocal + 'static) {
unsafe fn hide_lt<'a>(p: *mut (dyn SpawnLocal + 'a)) -> *mut (dyn SpawnLocal + 'static) {
use std::mem;
mem::transmute(p)
}
+5 -5
View File
@@ -125,7 +125,7 @@ enum Dequeue<U> {
}
/// Wraps a spawned boxed future
struct Task(Spawn<Box<Future<Item = (), Error = ()>>>);
struct Task(Spawn<Box<dyn Future<Item = (), Error = ()>>>);
/// A task that is scheduled. `turn` must be called
pub struct Scheduled<'a, U: 'a> {
@@ -171,7 +171,7 @@ where
self.inner.clone().into()
}
pub fn schedule(&mut self, item: Box<Future<Item = (), Error = ()>>) {
pub fn schedule(&mut self, item: Box<dyn Future<Item = (), Error = ()>>) {
// Get the current scheduler tick
let tick_num = self.inner.tick_num.load(SeqCst);
@@ -359,7 +359,7 @@ impl<'a, U: Unpark> Scheduled<'a, U> {
}
impl Task {
pub fn new(future: Box<Future<Item = (), Error = ()> + 'static>) -> Self {
pub fn new(future: Box<dyn Future<Item = (), Error = ()> + 'static>) -> Self {
Task(executor::spawn(future))
}
}
@@ -687,8 +687,8 @@ unsafe impl<U: Unpark> UnsafeNotify for ArcNode<U> {
}
}
unsafe fn hide_lt<U: Unpark>(p: *mut ArcNode<U>) -> *mut UnsafeNotify {
mem::transmute(p as *mut UnsafeNotify)
unsafe fn hide_lt<U: Unpark>(p: *mut ArcNode<U>) -> *mut dyn UnsafeNotify {
mem::transmute(p as *mut dyn UnsafeNotify)
}
impl<U: Unpark> Node<U> {
+10 -12
View File
@@ -22,7 +22,7 @@ use futures::sync::oneshot;
mod from_block_on_all {
use super::*;
fn test<F: Fn(Box<Future<Item = (), Error = ()>>) + 'static>(spawn: F) {
fn test<F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static>(spawn: F) {
let cnt = Rc::new(Cell::new(0));
let c = cnt.clone();
@@ -102,7 +102,7 @@ fn spawn_many() {
mod does_not_set_global_executor_by_default {
use super::*;
fn test<F: Fn(Box<Future<Item = (), Error = ()> + Send>) -> Result<(), E> + 'static, E>(
fn test<F: Fn(Box<dyn Future<Item = (), Error = ()> + Send>) -> Result<(), E> + 'static, E>(
spawn: F,
) {
block_on_all(lazy(|| {
@@ -127,7 +127,7 @@ mod does_not_set_global_executor_by_default {
mod from_block_on_future {
use super::*;
fn test<F: Fn(Box<Future<Item = (), Error = ()>>)>(spawn: F) {
fn test<F: Fn(Box<dyn Future<Item = (), Error = ()>>)>(spawn: F) {
let cnt = Rc::new(Cell::new(0));
let mut tokio_current_thread = CurrentThread::new();
@@ -181,8 +181,8 @@ mod outstanding_tasks_are_dropped_when_executor_is_dropped {
fn test<F, G>(spawn: F, dotspawn: G)
where
F: Fn(Box<Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<Future<Item = (), Error = ()>>),
F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<dyn Future<Item = (), Error = ()>>),
{
let mut rc = Rc::new(());
@@ -383,8 +383,8 @@ mod and_turn {
fn test<F, G>(spawn: F, dotspawn: G)
where
F: Fn(Box<Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<Future<Item = (), Error = ()>>),
F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<dyn Future<Item = (), Error = ()>>),
{
let cnt = Rc::new(Cell::new(0));
let c = cnt.clone();
@@ -445,7 +445,6 @@ mod and_turn {
},
);
}
}
mod in_drop {
@@ -459,7 +458,7 @@ mod in_drop {
}
struct MyFuture {
_data: Box<Any>,
_data: Box<dyn Any>,
}
impl Future for MyFuture {
@@ -473,8 +472,8 @@ mod in_drop {
fn test<F, G>(spawn: F, dotspawn: G)
where
F: Fn(Box<Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<Future<Item = (), Error = ()>>),
F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<dyn Future<Item = (), Error = ()>>),
{
let mut tokio_current_thread = CurrentThread::new();
@@ -520,7 +519,6 @@ mod in_drop {
},
);
}
}
#[test]
+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
+1 -1
View File
@@ -8,7 +8,7 @@ name = "tokio-executor"
# - 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
+37 -1
View File
@@ -11,7 +11,7 @@ thread_local!(static ENTERED: Cell<bool> = Cell::new(false));
///
/// For more details, see [`enter` documentation](fn.enter.html)
pub struct Enter {
on_exit: Vec<Box<Callback>>,
on_exit: Vec<Box<dyn Callback>>,
permanent: bool,
}
@@ -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.
+2 -2
View File
@@ -94,7 +94,7 @@ pub trait Executor {
/// ```
fn spawn(
&mut self,
future: Box<Future<Item = (), Error = ()> + Send>,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError>;
/// Provides a best effort **hint** to whether or not `spawn` will succeed.
@@ -140,7 +140,7 @@ pub trait Executor {
impl<E: Executor + ?Sized> Executor for Box<E> {
fn spawn(
&mut self,
future: Box<Future<Item = (), Error = ()> + Send>,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError> {
(**self).spawn(future)
}
+4 -4
View File
@@ -37,7 +37,7 @@ impl DefaultExecutor {
}
#[inline]
fn with_current<F: FnOnce(&mut Executor) -> R, R>(f: F) -> Option<R> {
fn with_current<F: FnOnce(&mut dyn Executor) -> R, R>(f: F) -> Option<R> {
EXECUTOR.with(
|current_executor| match current_executor.replace(State::Active) {
State::Ready(executor_ptr) => {
@@ -57,7 +57,7 @@ enum State {
// default executor not defined
Empty,
// default executor is defined and ready to be used
Ready(*mut Executor),
Ready(*mut dyn Executor),
// default executor is currently active (used to detect recursive calls)
Active,
}
@@ -72,7 +72,7 @@ thread_local! {
impl super::Executor for DefaultExecutor {
fn spawn(
&mut self,
future: Box<Future<Item = (), Error = ()> + Send>,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError> {
DefaultExecutor::with_current(|executor| executor.spawn(future))
.unwrap_or_else(|| Err(SpawnError::shutdown()))
@@ -210,7 +210,7 @@ where
})
}
unsafe fn hide_lt<'a>(p: *mut (Executor + 'a)) -> *mut (Executor + 'static) {
unsafe fn hide_lt<'a>(p: *mut (dyn Executor + 'a)) -> *mut (dyn Executor + 'static) {
use std::mem;
mem::transmute(p)
}
+3 -3
View File
@@ -1,5 +1,5 @@
#![deny(missing_docs, missing_debug_implementations, warnings)]
#![doc(html_root_url = "https://docs.rs/tokio-executor/0.1.7")]
#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-executor/0.1.8")]
//! Task execution related traits and utilities.
//!
@@ -61,7 +61,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};
+2 -2
View File
@@ -128,13 +128,13 @@ pub trait Unpark: Sync + Send + 'static {
fn unpark(&self);
}
impl Unpark for Box<Unpark> {
impl Unpark for Box<dyn Unpark> {
fn unpark(&self) {
(**self).unpark()
}
}
impl Unpark for Arc<Unpark> {
impl Unpark for Arc<dyn Unpark> {
fn unpark(&self) {
(**self).unpark()
}
+1 -1
View File
@@ -10,7 +10,7 @@ mod out_of_executor_context {
fn test<F, E>(spawn: F)
where
F: Fn(Box<Future<Item = (), Error = ()> + Send>) -> Result<(), E>,
F: Fn(Box<dyn Future<Item = (), Error = ()> + Send>) -> Result<(), E>,
{
let res = spawn(Box::new(lazy(|| Ok(()))));
assert!(res.is_err());
+2 -3
View File
@@ -27,9 +27,8 @@ tokio-threadpool = "0.1.3"
tokio-io = "0.1.6"
[dev-dependencies]
rand = "0.6"
tempfile = "3"
tempdir = "0.3"
rand = "0.7"
tempfile = "~3.1.0"
tokio-io = "0.1.6"
tokio-codec = "0.1.0"
tokio = "0.1.7"
+2 -2
View File
@@ -1,5 +1,5 @@
//! Echo everything received on STDIN to STDOUT.
#![deny(deprecated, warnings)]
#![deny(deprecated)]
extern crate futures;
extern crate tokio_codec;
@@ -14,7 +14,7 @@ use futures::{Future, Sink, Stream};
use std::io;
pub fn main() -> Result<(), Box<std::error::Error>> {
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let pool = Builder::new().pool_size(1).build();
pool.spawn({
+1 -1
View File
@@ -1,4 +1,4 @@
#![deny(missing_docs, missing_debug_implementations, warnings)]
#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-fs/0.1.6")]
//! Asynchronous file and standard stream adaptation.
+6 -6
View File
@@ -1,18 +1,18 @@
extern crate futures;
extern crate tempdir;
extern crate tempfile;
extern crate tokio_fs;
use futures::{Future, Stream};
use std::fs;
use std::sync::{Arc, Mutex};
use tempdir::TempDir;
use tempfile::tempdir;
use tokio_fs::*;
mod pool;
#[test]
fn create() {
let base_dir = TempDir::new("base").unwrap();
let base_dir = tempdir().unwrap();
let new_dir = base_dir.path().join("foo");
pool::run({ create_dir(new_dir.clone()) });
@@ -22,7 +22,7 @@ fn create() {
#[test]
fn create_all() {
let base_dir = TempDir::new("base").unwrap();
let base_dir = tempdir().unwrap();
let new_dir = base_dir.path().join("foo").join("bar");
pool::run({ create_dir_all(new_dir.clone()) });
@@ -32,7 +32,7 @@ fn create_all() {
#[test]
fn remove() {
let base_dir = TempDir::new("base").unwrap();
let base_dir = tempdir().unwrap();
let new_dir = base_dir.path().join("foo");
fs::create_dir(new_dir.clone()).unwrap();
@@ -44,7 +44,7 @@ fn remove() {
#[test]
fn read() {
let base_dir = TempDir::new("base").unwrap();
let base_dir = tempdir().unwrap();
let p = base_dir.path();
fs::create_dir(p.join("aa")).unwrap();
+4 -4
View File
@@ -1,19 +1,19 @@
extern crate futures;
extern crate tempdir;
extern crate tempfile;
extern crate tokio_fs;
use futures::Future;
use std::fs;
use std::io::prelude::*;
use std::io::BufReader;
use tempdir::TempDir;
use tempfile::tempdir;
use tokio_fs::*;
mod pool;
#[test]
fn test_hard_link() {
let dir = TempDir::new("base").unwrap();
let dir = tempdir().unwrap();
let src = dir.path().join("src.txt");
let dst = dir.path().join("dst.txt");
@@ -38,7 +38,7 @@ fn test_hard_link() {
#[cfg(unix)]
#[test]
fn test_symlink() {
let dir = TempDir::new("base").unwrap();
let dir = tempdir().unwrap();
let src = dir.path().join("src.txt");
let dst = dir.path().join("dst.txt");
-1
View File
@@ -2,7 +2,6 @@
#![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))]
//! A preview of Tokio w/ `async` / `await` support.
+1 -1
View File
@@ -10,7 +10,7 @@
//! [`Stream`]: #
//! [transports]: #
#![deny(missing_docs, missing_debug_implementations, warnings)]
#![deny(missing_docs, missing_debug_implementations)]
#![doc(hidden, html_root_url = "https://docs.rs/tokio-codec/0.1.0")]
// _tokio_codec are the items that belong in the `tokio_codec` crate. However, because we need to
+5 -5
View File
@@ -1,4 +1,4 @@
#![deny(missing_docs, missing_debug_implementations, warnings)]
#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-io/0.1.12")]
//! Core I/O traits and combinators when working with Tokio.
@@ -21,10 +21,10 @@ use std::io as std_io;
use futures::{Future, Stream};
/// A convenience typedef around a `Future` whose error component is `io::Error`
pub type IoFuture<T> = Box<Future<Item = T, Error = std_io::Error> + Send>;
pub type IoFuture<T> = Box<dyn Future<Item = T, Error = std_io::Error> + Send>;
/// A convenience typedef around a `Stream` whose error component is `io::Error`
pub type IoStream<T> = Box<Stream<Item = T, Error = std_io::Error> + Send>;
pub type IoStream<T> = Box<dyn Stream<Item = T, Error = std_io::Error> + Send>;
/// A convenience macro for working with `io::Result<T>` from the `Read` and
/// `Write` traits.
@@ -65,6 +65,6 @@ pub use self::async_write::AsyncWrite;
fn _assert_objects() {
fn _assert<T>() {}
_assert::<Box<AsyncRead>>();
_assert::<Box<AsyncWrite>>();
_assert::<Box<dyn AsyncRead>>();
_assert::<Box<dyn AsyncWrite>>();
}
+6
View File
@@ -1,3 +1,9 @@
# 0.1.10 (September 25, 2019)
### Changed
- Upgrade to parking_lot 0.9.0 (#1298 backport)
- The minimum supported rust version (MSRV) is now 1.31.0. (#1358)
# 0.1.9 (March 1, 2019)
### Added
+4 -4
View File
@@ -8,13 +8,13 @@ name = "tokio-reactor"
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.9"
version = "0.1.10"
authors = ["Carl Lerche <[email protected]>"]
license = "MIT"
readme = "README.md"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-reactor/0.1.9/tokio_reactor"
documentation = "https://docs.rs/tokio-reactor/0.1.10/tokio_reactor"
description = """
Event loop that drives Tokio I/O resources.
"""
@@ -27,7 +27,7 @@ lazy_static = "1.0.2"
log = "0.4.1"
mio = "0.6.14"
num_cpus = "1.8.0"
parking_lot = "0.7.0"
parking_lot = "0.9.0"
slab = "0.4.0"
tokio-executor = "0.1.1"
tokio-io = "0.1.6"
@@ -36,4 +36,4 @@ tokio-sync = "0.1.1"
[dev-dependencies]
num_cpus = "1.8.0"
tokio = "0.1.7"
tokio-io-pool = "0.1.4"
tokio-io-pool = "=0.1.4"
+5 -5
View File
@@ -2,7 +2,7 @@
Event loop that drives Tokio I/O resources.
[Documentation](https://docs.rs/tokio-reactor/0.1.9/tokio_reactor)
[Documentation](https://docs.rs/tokio-reactor/0.1.10/tokio_reactor)
## Overview
@@ -25,10 +25,10 @@ are building a custom I/O resource.
[`mio`]: http://github.com/carllerche/mio
[`futures`]: http://github.com/rust-lang-nursery/futures-rs
[`Reactor`]: https://docs.rs/tokio-reactor/0.1.9/tokio_reactor/struct.Reactor.html
[`Handle`]: https://docs.rs/tokio-reactor/0.1.9/tokio_reactor/struct.Handle.html
[`Registration`]: https://docs.rs/tokio-reactor/0.1.9/tokio_reactor/struct.Registration.html
[`PollEvented`]: https://docs.rs/tokio-reactor/0.1.9/tokio_reactor/struct.PollEvented.html
[`Reactor`]: https://docs.rs/tokio-reactor/0.1.10/tokio_reactor/struct.Reactor.html
[`Handle`]: https://docs.rs/tokio-reactor/0.1.10/tokio_reactor/struct.Handle.html
[`Registration`]: https://docs.rs/tokio-reactor/0.1.10/tokio_reactor/struct.Registration.html
[`PollEvented`]: https://docs.rs/tokio-reactor/0.1.10/tokio_reactor/struct.PollEvented.html
[`tokio`]: ../
## License
-1
View File
@@ -1,5 +1,4 @@
#![feature(test)]
#![deny(warnings)]
extern crate futures;
extern crate mio;
+5 -5
View File
@@ -1,5 +1,5 @@
#![doc(html_root_url = "https://docs.rs/tokio-reactor/0.1.9")]
#![deny(missing_docs, warnings, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-reactor/0.1.10")]
#![deny(missing_docs, missing_debug_implementations)]
//! Event loop that drives Tokio I/O resources.
//!
@@ -631,7 +631,7 @@ impl HandlePriv {
}
unsafe fn from_usize(val: usize) -> HandlePriv {
let inner = mem::transmute::<usize, Weak<Inner>>(val);;
let inner = mem::transmute::<usize, Weak<Inner>>(val);
HandlePriv { inner }
}
@@ -652,7 +652,7 @@ impl Inner {
/// Register an I/O resource with the reactor.
///
/// The registration token is returned.
fn add_source(&self, source: &Evented) -> io::Result<usize> {
fn add_source(&self, source: &dyn Evented) -> io::Result<usize> {
// Get an ABA guard value
let aba_guard = self.next_aba_guard.fetch_add(1 << TOKEN_SHIFT, Relaxed);
@@ -690,7 +690,7 @@ impl Inner {
}
/// Deregisters an I/O resource from the reactor.
fn deregister_source(&self, source: &Evented) -> io::Result<()> {
fn deregister_source(&self, source: &dyn Evented) -> io::Result<()> {
self.io.deregister(source)
}
+1 -1
View File
@@ -7,7 +7,7 @@ use futures::{Future, Stream};
/// how many signals to handle before exiting
const STOP_AFTER: u64 = 10;
fn main() -> Result<(), Box<std::error::Error>> {
fn main() -> Result<(), Box<dyn std::error::Error>> {
// tokio_signal provides a convenience builder for Ctrl+C
// this even works cross-platform: linux and windows!
//
+2 -3
View File
@@ -11,7 +11,7 @@ mod platform {
use futures::{Future, Stream};
use tokio_signal::unix::{Signal, SIGINT, SIGTERM};
pub fn main() -> Result<(), Box<::std::error::Error>> {
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a stream for each of the signals we'd like to handle.
let sigint = Signal::new(SIGINT).flatten_stream();
let sigterm = Signal::new(SIGTERM).flatten_stream();
@@ -39,7 +39,6 @@ mod platform {
}
Ok(())
}
}
#[cfg(not(unix))]
@@ -49,6 +48,6 @@ mod platform {
}
}
fn main() -> Result<(), Box<std::error::Error>> {
fn main() -> Result<(), Box<dyn std::error::Error>> {
platform::main()
}
+2 -3
View File
@@ -9,7 +9,7 @@ mod platform {
use futures::{Future, Stream};
use tokio_signal::unix::{Signal, SIGHUP};
pub fn main() -> Result<(), Box<::std::error::Error>> {
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
// on Unix, we can listen to whatever signal we want, in this case: SIGHUP
let stream = Signal::new(SIGHUP).flatten_stream();
@@ -38,7 +38,6 @@ mod platform {
::tokio::runtime::current_thread::block_on_all(future)?;
Ok(())
}
}
#[cfg(not(unix))]
@@ -48,6 +47,6 @@ mod platform {
}
}
fn main() -> Result<(), Box<std::error::Error>> {
fn main() -> Result<(), Box<dyn std::error::Error>> {
platform::main()
}
+3 -3
View File
@@ -86,9 +86,9 @@ pub mod unix;
pub mod windows;
/// A future whose error is `io::Error`
pub type IoFuture<T> = Box<Future<Item = T, Error = io::Error> + Send>;
pub type IoFuture<T> = Box<dyn Future<Item = T, Error = io::Error> + Send>;
/// A stream whose error is `io::Error`
pub type IoStream<T> = Box<Stream<Item = T, Error = io::Error> + Send>;
pub type IoStream<T> = Box<dyn Stream<Item = T, Error = io::Error> + Send>;
/// Creates a stream which receives "ctrl-c" notifications sent to a process.
///
@@ -125,7 +125,7 @@ pub fn ctrl_c_handle(handle: &Handle) -> IoFuture<IoStream<()>> {
let handle = handle.clone();
Box::new(future::lazy(move || {
unix::Signal::with_handle(unix::libc::SIGINT, &handle)
.map(|x| Box::new(x.map(|_| ())) as Box<Stream<Item = _, Error = _> + Send>)
.map(|x| Box::new(x.map(|_| ())) as Box<dyn Stream<Item = _, Error = _> + Send>)
}))
}
+5
View File
@@ -1,3 +1,8 @@
# 0.1.7 (October 10, 2019)
### Fixed
- memory leak when polling oneshot handle from more than one task (#1649).
# 0.1.6 (June 4, 2019)
### Added
+3 -3
View File
@@ -8,12 +8,12 @@ name = "tokio-sync"
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.6"
version = "0.1.7"
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.6/tokio_sync"
documentation = "https://docs.rs/tokio-sync/0.1.7/tokio_sync"
description = """
Synchronization utilities.
"""
@@ -24,7 +24,7 @@ fnv = "1.0.6"
futures = "0.1.19"
[dev-dependencies]
env_logger = { version = "0.5", default-features = false }
env_logger = { version = "0.6", default-features = false }
tokio = { version = "0.1.15", path = "../tokio" }
tokio-mock-task = "0.1.1"
loom = { version = "0.1.1", features = ["futures"] }
-1
View File
@@ -1,5 +1,4 @@
#![feature(test)]
#![cfg_attr(test, deny(warnings))]
extern crate futures;
extern crate test;
-1
View File
@@ -1,5 +1,4 @@
#![feature(test)]
#![cfg_attr(test, deny(warnings))]
extern crate futures;
extern crate test;
+1 -2
View File
@@ -1,6 +1,5 @@
#![doc(html_root_url = "https://docs.rs/tokio-sync/0.1.6")]
#![doc(html_root_url = "https://docs.rs/tokio-sync/0.1.7")]
#![deny(missing_debug_implementations, missing_docs, unreachable_pub)]
#![cfg_attr(test, deny(warnings))]
//! Asynchronous synchronization primitives.
//!
+5
View File
@@ -198,6 +198,8 @@ impl<T> Sender<T> {
state = State::unset_tx_task(&inner.state);
if state.is_closed() {
// Set the flag again so that the waker is released in drop
State::set_tx_task(&inner.state);
return Ok(Async::Ready(()));
} else {
unsafe { inner.drop_tx_task() };
@@ -363,6 +365,9 @@ impl<T> Inner<T> {
// Unset the task
state = State::unset_rx_task(&self.state);
if state.is_complete() {
// Set the flag again so that the waker is released in drop
State::set_rx_task(&self.state);
return match unsafe { self.consume_value() } {
Some(value) => Ok(Ready(value)),
None => Err(RecvError(())),
-2
View File
@@ -1,5 +1,3 @@
#![deny(warnings)]
extern crate futures;
extern crate tokio_mock_task;
extern crate tokio_sync;
-2
View File
@@ -1,5 +1,3 @@
#![deny(warnings)]
extern crate tokio_sync;
fn is_error<T: ::std::error::Error + Send + Sync>() {}
-2
View File
@@ -1,5 +1,3 @@
#![deny(warnings)]
extern crate futures;
#[macro_use]
extern crate loom;
-2
View File
@@ -1,5 +1,3 @@
#![deny(warnings)]
extern crate futures;
extern crate loom;
-2
View File
@@ -1,5 +1,3 @@
#![deny(warnings)]
#[macro_use]
extern crate futures;
#[macro_use]
-2
View File
@@ -1,5 +1,3 @@
#![deny(warnings)]
extern crate futures;
extern crate tokio_mock_task;
extern crate tokio_sync;
-2
View File
@@ -1,5 +1,3 @@
#![deny(warnings)]
extern crate futures;
extern crate tokio_mock_task;
extern crate tokio_sync;
-2
View File
@@ -1,5 +1,3 @@
#![deny(warnings)]
extern crate futures;
extern crate tokio_mock_task;
extern crate tokio_sync;
-2
View File
@@ -1,5 +1,3 @@
#![deny(warnings)]
extern crate futures;
extern crate tokio_mock_task;
extern crate tokio_sync;
+1 -1
View File
@@ -28,6 +28,6 @@ iovec = "0.1"
futures = "0.1.19"
[dev-dependencies]
env_logger = { version = "0.5", default-features = false }
env_logger = { version = "0.6", default-features = false }
net2 = "0.2"
tokio = "0.1.13"
+1 -1
View File
@@ -1,5 +1,5 @@
#![doc(html_root_url = "https://docs.rs/tokio-tcp/0.1.3")]
#![deny(missing_docs, warnings, missing_debug_implementations)]
#![deny(missing_docs, missing_debug_implementations)]
//! TCP bindings for `tokio`.
//!
-1
View File
@@ -1,6 +1,5 @@
#![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
//!
-1
View File
@@ -127,5 +127,4 @@ mod tests {
let mut fut = future::ok::<(), ()>(());
assert_ready_eq!(fut.poll(), ());
}
}
+13
View File
@@ -1,3 +1,16 @@
# 0.1.16 (September 25, 2019)
### Changed
- Remove last non-dev dependency on rand crate by seeding PRNG via libstd
`RandomState` (#1324 backport)
- Upgrade (dev-only dependency) rand to 0.7.0 (#1302 backport)
- The minimum supported rust version (MSRV) is now 1.31.0 (#1358)
# 0.1.15 (June 2, 2019)
### Changed
- Allow other executors inside `threadpool::blocking` (#1155).
# 0.1.14 (April 22, 2019)
### Added
+6 -5
View File
@@ -8,8 +8,8 @@ name = "tokio-threadpool"
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.14"
documentation = "https://docs.rs/tokio-threadpool/0.1.14/tokio_threadpool"
version = "0.1.16"
documentation = "https://docs.rs/tokio-threadpool/0.1.16/tokio_threadpool"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://github.com/tokio-rs/tokio"
license = "MIT"
@@ -21,18 +21,19 @@ 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"
crossbeam-utils = "0.6.4"
num_cpus = "1.2"
rand = "0.6"
slab = "0.4.1"
log = "0.4"
lazy_static = "1"
[dev-dependencies]
env_logger = "0.5"
rand = "0.7"
env_logger = { version = "0.6", default-features = false }
# For comparison benchmarks
futures-cpupool = "0.1.7"
+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.16/tokio_threadpool)
### Why not Rayon?
-1
View File
@@ -1,5 +1,4 @@
#![feature(test)]
#![deny(warnings)]
extern crate futures;
extern crate futures_cpupool;
-1
View File
@@ -1,5 +1,4 @@
#![feature(test)]
#![deny(warnings)]
extern crate futures;
extern crate rand;
-1
View File
@@ -1,5 +1,4 @@
#![feature(test)]
#![deny(warnings)]
extern crate futures;
extern crate futures_cpupool;
+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.
+2 -2
View File
@@ -67,7 +67,7 @@ pub struct Builder {
max_blocking: usize,
/// Generates the `Park` instances
new_park: Box<Fn(&WorkerId) -> BoxPark>,
new_park: Box<dyn Fn(&WorkerId) -> BoxPark>,
}
impl Builder {
@@ -223,7 +223,7 @@ impl Builder {
/// ```
pub fn panic_handler<F>(&mut self, f: F) -> &mut Self
where
F: Fn(Box<Any + Send>) + Send + Sync + 'static,
F: Fn(Box<dyn Any + Send>) + Send + Sync + 'static,
{
self.config.panic_handler = Some(Arc::new(f));
self
+1 -1
View File
@@ -7,7 +7,7 @@ use tokio_executor::Enter;
#[derive(Clone)]
pub(crate) struct Callback {
f: Arc<Fn(&Worker, &mut Enter) + Send + Sync>,
f: Arc<dyn Fn(&Worker, &mut Enter) + Send + Sync>,
}
impl Callback {
+3 -3
View File
@@ -13,9 +13,9 @@ pub(crate) struct Config {
pub name_prefix: Option<String>,
pub stack_size: Option<usize>,
pub around_worker: Option<Callback>,
pub after_start: Option<Arc<Fn() + Send + Sync>>,
pub before_stop: Option<Arc<Fn() + Send + Sync>>,
pub panic_handler: Option<Arc<Fn(Box<Any + Send>) + Send + Sync>>,
pub after_start: Option<Arc<dyn Fn() + Send + Sync>>,
pub before_stop: Option<Arc<dyn Fn() + Send + Sync>>,
pub panic_handler: Option<Arc<dyn Fn(Box<dyn Any + Send>) + Send + Sync>>,
}
/// Max number of workers that can be part of a pool. This is the most that can
+4 -3
View File
@@ -1,5 +1,5 @@
#![doc(html_root_url = "https://docs.rs/tokio-threadpool/0.1.14")]
#![deny(warnings, missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-threadpool/0.1.16")]
#![deny(missing_docs, missing_debug_implementations)]
//! A work-stealing based thread pool for executing futures.
//!
@@ -84,8 +84,9 @@ extern crate crossbeam_queue;
extern crate crossbeam_utils;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate lazy_static;
extern crate num_cpus;
extern crate rand;
extern crate slab;
#[macro_use]
+2 -2
View File
@@ -3,8 +3,8 @@ use tokio_executor::park::{Park, Unpark};
use std::error::Error;
use std::time::Duration;
pub(crate) type BoxPark = Box<Park<Unpark = BoxUnpark, Error = ()> + Send>;
pub(crate) type BoxUnpark = Box<Unpark>;
pub(crate) type BoxPark = Box<dyn Park<Unpark = BoxUnpark, Error = ()> + Send>;
pub(crate) type BoxUnpark = Box<dyn Unpark>;
pub(crate) struct BoxedPark<T>(T);
+31 -6
View File
@@ -17,6 +17,8 @@ use worker::{self, Worker, WorkerId};
use futures::Poll;
use std::cell::Cell;
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hash, Hasher};
use std::num::Wrapping;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::{AcqRel, Acquire};
@@ -25,7 +27,6 @@ use std::thread;
use crossbeam_deque::Injector;
use crossbeam_utils::CachePadded;
use rand;
#[derive(Debug)]
pub(crate) struct Pool {
@@ -420,11 +421,7 @@ impl Pool {
/// Uses a thread-local random number generator based on XorShift.
pub fn rand_usize(&self) -> usize {
thread_local! {
static RNG: Cell<Wrapping<u32>> = {
// The initial seed must be non-zero.
let init = rand::random::<u32>() | 1;
Cell::new(Wrapping(init))
}
static RNG: Cell<Wrapping<u32>> = Cell::new(Wrapping(prng_seed()));
}
RNG.with(|rng| {
@@ -448,3 +445,31 @@ impl PartialEq for Pool {
unsafe impl Send for Pool {}
unsafe impl Sync for Pool {}
// Return a thread-specific, 32-bit, non-zero seed value suitable for a 32-bit
// PRNG. This uses one libstd RandomState for a default hasher and hashes on
// the current thread ID to obtain an unpredictable, collision resistant seed.
fn prng_seed() -> u32 {
// This obtains a small number of random bytes from the host system (for
// example, on unix via getrandom(2)) in order to seed an unpredictable and
// HashDoS resistant 64-bit hash function (currently: `SipHasher13` with
// 128-bit state). We only need one of these, to make the seeds for all
// process threads different via hashed IDs, collision resistant, and
// unpredictable.
lazy_static! {
static ref RND_STATE: RandomState = RandomState::new();
}
// Hash the current thread ID to produce a u32 value
let mut hasher = RND_STATE.build_hasher();
thread::current().id().hash(&mut hasher);
let hash: u64 = hasher.finish();
let seed = (hash as u32) ^ ((hash >> 32) as u32);
// Ensure non-zero seed (Xorshift yields only zero's for that seed)
if seed == 0 {
0x9b4e_6d25 // misc bits, could be any non-zero
} else {
seed
}
}
+2 -2
View File
@@ -131,7 +131,7 @@ impl tokio_executor::Executor for Sender {
fn spawn(
&mut self,
future: Box<Future<Item = (), Error = ()> + Send>,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError> {
let mut s = &*self;
tokio_executor::Executor::spawn(&mut s, future)
@@ -157,7 +157,7 @@ impl<'a> tokio_executor::Executor for &'a Sender {
fn spawn(
&mut self,
future: Box<Future<Item = (), Error = ()> + Send>,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError> {
self.prepare_for_spawn()?;
+1 -1
View File
@@ -60,7 +60,7 @@ pub(crate) enum Run {
Complete,
}
type BoxFuture = Box<Future<Item = (), Error = ()> + Send + 'static>;
type BoxFuture = Box<dyn Future<Item = (), Error = ()> + Send + 'static>;
// ===== impl Task =====
+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;
+3 -1
View File
@@ -18,7 +18,9 @@ use std::time::Duration;
thread_local!(static FOO: Cell<u32> = Cell::new(0));
fn ignore_results<F: Future + Send + 'static>(f: F) -> Box<Future<Item = (), Error = ()> + Send> {
fn ignore_results<F: Future + Send + 'static>(
f: F,
) -> Box<dyn Future<Item = (), Error = ()> + Send> {
Box::new(f.map(|_| ()).map_err(|_| ()))
}
+1 -1
View File
@@ -28,6 +28,6 @@ crossbeam-utils = "0.6.0"
slab = "0.4.1"
[dev-dependencies]
rand = "0.6"
rand = "0.7"
tokio-mock-task = "0.1.0"
tokio = "0.1.7"
+1 -1
View File
@@ -17,7 +17,7 @@ use std::time::Instant;
/// [`Instant::now`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.now
#[derive(Default, Clone)]
pub struct Clock {
now: Option<Arc<Now>>,
now: Option<Arc<dyn Now>>,
}
thread_local! {
+1 -1
View File
@@ -1,5 +1,5 @@
#![doc(html_root_url = "https://docs.rs/tokio-timer/0.2.11")]
#![deny(missing_docs, warnings, missing_debug_implementations)]
#![deny(missing_docs, missing_debug_implementations)]
//! Utilities for tracking time.
//!
+1 -1
View File
@@ -158,7 +158,7 @@ impl<T: StdError + 'static> StdError for ThrottleError<T> {
// FIXME(taiki-e): When the minimum support version of tokio reaches Rust 1.30,
// replace this with Error::source.
#[allow(deprecated)]
fn cause(&self) -> Option<&StdError> {
fn cause(&self) -> Option<&dyn StdError> {
match self.0 {
Either::A(ref err) => Some(err),
Either::B(ref err) => Some(err),
+2 -2
View File
@@ -162,7 +162,7 @@ pub(crate) struct Inner {
process: AtomicStack,
/// Unparks the timer thread.
unpark: Box<Unpark>,
unpark: Box<dyn Unpark>,
}
/// Maximum number of timeouts the system can handle concurrently.
@@ -426,7 +426,7 @@ impl<T, N> Drop for Timer<T, N> {
// ===== impl Inner =====
impl Inner {
fn new(start: Instant, unpark: Box<Unpark>) -> Inner {
fn new(start: Instant, unpark: Box<dyn Unpark>) -> Inner {
Inner {
num: AtomicUsize::new(0),
elapsed: AtomicU64::new(0),
+1 -1
View File
@@ -31,7 +31,7 @@ tokio-io = "0.1.7"
[dev-dependencies]
tokio = "0.1"
cfg-if = "0.1"
env_logger = { version = "0.5", default-features = false }
env_logger = { version = "0.6", default-features = false }
[target.'cfg(all(not(target_os = "macos"), not(windows), not(target_os = "ios")))'.dev-dependencies]
openssl = "0.10"
+1 -1
View File
@@ -12,7 +12,7 @@ use native_tls::TlsConnector;
use tokio::net::TcpStream;
use tokio::runtime::Runtime;
fn main() -> Result<(), Box<std::error::Error>> {
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut runtime = Runtime::new()?;
let addr = "www.rust-lang.org:443"
.to_socket_addrs()?
+1 -1
View File
@@ -8,7 +8,7 @@ use tokio::io;
use tokio::net::TcpListener;
use tokio::prelude::*;
fn main() -> Result<(), Box<std::error::Error>> {
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Bind the server's socket
let addr = "127.0.0.1:12345".parse()?;
let tcp = TcpListener::bind(&addr)?;
-3
View File
@@ -1,3 +0,0 @@
# 0.1.0 (April 22, 2019)
- Initial release
-53
View File
@@ -1,53 +0,0 @@
[package]
name = "tokio-trace"
# 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]>"]
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 = []
-25
View File
@@ -1,25 +0,0 @@
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.
-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 {}
}
File diff suppressed because it is too large Load Diff
-609
View File
@@ -1,609 +0,0 @@
//! Spans represent periods of time in the execution of a program.
//!
//! # Entering a Span
//!
//! A thread of execution is said to _enter_ a span when it begins executing,
//! and _exit_ the span when it switches to another context. Spans may be
//! entered through the [`enter`] method, which enters the target span,
//! performs a given function (either a closure or a function pointer), exits
//! the span, and then returns the result.
//!
//! Calling `enter` on a span handle enters the span that handle corresponds to,
//! if the span exists:
//! ```
//! # #[macro_use] extern crate tokio_trace;
//! # use tokio_trace::Level;
//! # fn main() {
//! let my_var: u64 = 5;
//! let my_span = span!(Level::TRACE, "my_span", my_var = &my_var);
//!
//! my_span.enter(|| {
//! // perform some work in the context of `my_span`...
//! });
//!
//! // Perform some work outside of the context of `my_span`...
//!
//! my_span.enter(|| {
//! // Perform some more work in the context of `my_span`.
//! });
//! # }
//! ```
//!
//! # The Span Lifecycle
//!
//! Execution may enter and exit a span multiple times before that
//! span is _closed_. Consider, for example, a future which has an associated
//! span and enters that span every time it is polled:
//! ```rust
//! # extern crate tokio_trace;
//! # extern crate futures;
//! # use futures::{Future, Poll, Async};
//! struct MyFuture {
//! // data
//! span: tokio_trace::Span,
//! }
//!
//! impl Future for MyFuture {
//! type Item = ();
//! type Error = ();
//!
//! fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
//! self.span.enter(|| {
//! // Do actual future work
//! # Ok(Async::Ready(()))
//! })
//! }
//! }
//! ```
//!
//! If this future was spawned on an executor, it might yield one or more times
//! before `poll` returns `Ok(Async::Ready)`. If the future were to yield, then
//! the executor would move on to poll the next future, which may _also_ enter
//! an associated span or series of spans. Therefore, it is valid for a span to
//! be entered repeatedly before it completes. Only the time when that span or
//! one of its children was the current span is considered to be time spent in
//! that span. A span which is not executing and has not yet been closed is said
//! to be _idle_.
//!
//! Because spans may be entered and exited multiple times before they close,
//! [`Subscriber`]s have separate trait methods which are called to notify them
//! of span exits and when span handles are dropped. When execution exits a
//! span, [`exit`] will always be called with that span's ID to notify the
//! subscriber that the span has been exited. When span handles are dropped, the
//! [`drop_span`] method is called with that span's ID. The subscriber may use
//! this to determine whether or not the span will be entered again.
//!
//! If there is only a single handle with the capacity to exit a span, dropping
//! that handle "close" the span, since the capacity to enter it no longer
//! exists. 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`...
//! }); // --> Subscriber::exit(my_span)
//!
//! // The handle to `my_span` only lives inside of this block; when it is
//! // dropped, the subscriber will be informed via `drop_span`.
//!
//! } // --> Subscriber::drop_span(my_span)
//! # }
//! ```
//!
//! However, if multiple handles exist, the span can still be re-entered even if
//! one or more is dropped. For determining when _all_ handles to a span have
//! been dropped, `Subscriber`s have a [`clone_span`] method, which is called
//! every time a span handle is cloned. Combined with `drop_span`, this may be
//! used to track the number of handles to a given span — if `drop_span` has
//! been called one more time than the number of calls to `clone_span` for a
//! given ID, then no more handles to the span with that ID exist. The
//! subscriber may then treat it as closed.
//!
//! # Accessing a Span's Attributes
//!
//! The [`Attributes`] type represents a *non-entering* reference to a `Span`'s data
//! — a set of key-value pairs (known as _fields_), a creation timestamp,
//! a reference to the span's parent in the trace tree, and metadata describing
//! the source code location where the span was created. This data is provided
//! to the [`Subscriber`] when the span is created; it may then choose to cache
//! the data for future use, record it in some manner, or discard it completely.
//!
//! [`clone_span`]: ../subscriber/trait.Subscriber.html#method.clone_span
//! [`drop_span`]: ../subscriber/trait.Subscriber.html#method.drop_span
//! [`exit`]: ../subscriber/trait.Subscriber.html#tymethod.exit
//! [`Subscriber`]: ../subscriber/trait.Subscriber.html
//! [`Attributes`]: struct.Attributes.html
//! [`enter`]: struct.Span.html#method.enter
pub use tokio_trace_core::span::{Attributes, Id, Record};
use std::{
cmp, fmt,
hash::{Hash, Hasher},
};
use {dispatcher::Dispatch, field, Metadata};
/// Trait implemented by types which have a span `Id`.
pub trait AsId: ::sealed::Sealed {
/// Returns the `Id` of the span that `self` corresponds to, or `None` if
/// this corresponds to a disabled span.
fn as_id(&self) -> Option<&Id>;
}
/// A handle representing a span, with the capability to enter the span if it
/// exists.
///
/// If the span was rejected by the current `Subscriber`'s filter, entering the
/// span will silently do nothing. Thus, the handle can be used in the same
/// manner regardless of whether or not the trace is currently being collected.
#[derive(Clone)]
pub struct Span {
/// A handle used to enter the span when it is not executing.
///
/// If this is `None`, then the span has either closed or was never enabled.
inner: Option<Inner>,
meta: &'static Metadata<'static>,
}
/// A handle representing the capacity to enter a span which is known to exist.
///
/// Unlike `Span`, this type is only constructed for spans which _have_ been
/// enabled by the current filter. This type is primarily used for implementing
/// span handles; users should typically not need to interact with it directly.
#[derive(Debug)]
pub(crate) struct Inner {
/// The span's ID, as provided by `subscriber`.
id: Id,
/// The subscriber that will receive events relating to this span.
///
/// This should be the same subscriber that provided this span with its
/// `id`.
subscriber: Dispatch,
}
/// A guard representing a span which has been entered and is currently
/// executing.
///
/// This guard may be used to exit the span, returning an `Enter` to
/// re-enter it.
///
/// This type is primarily used for implementing span handles; users should
/// typically not need to interact with it directly.
#[derive(Debug)]
#[must_use = "once a span has been entered, it should be exited"]
struct Entered<'a> {
inner: &'a Inner,
}
// ===== impl Span =====
impl Span {
/// Constructs a new `Span` with the given [metadata] and set of
/// [field values].
///
/// The new span will be constructed by the currently-active [`Subscriber`],
/// with the current span as its parent (if one exists).
///
/// After the span is constructed, [field values] and/or [`follows_from`]
/// annotations may be added to it.
///
/// [metadata]: ../metadata
/// [`Subscriber`]: ../subscriber/trait.Subscriber.html
/// [field values]: ../field/struct.ValueSet.html
/// [`follows_from`]: ../struct.Span.html#method.follows_from
#[inline]
pub fn new(meta: &'static Metadata<'static>, values: &field::ValueSet) -> Span {
let new_span = Attributes::new(meta, values);
Self::make(meta, new_span)
}
/// Constructs a new `Span` as the root of its own trace tree, with the
/// given [metadata] and set of [field values].
///
/// After the span is constructed, [field values] and/or [`follows_from`]
/// annotations may be added to it.
///
/// [metadata]: ../metadata
/// [field values]: ../field/struct.ValueSet.html
/// [`follows_from`]: ../struct.Span.html#method.follows_from
#[inline]
pub fn new_root(meta: &'static Metadata<'static>, values: &field::ValueSet) -> Span {
Self::make(meta, Attributes::new_root(meta, values))
}
/// Constructs a new `Span` as child of the given parent span, with the
/// given [metadata] and set of [field values].
///
/// After the span is constructed, [field values] and/or [`follows_from`]
/// annotations may be added to it.
///
/// [metadata]: ../metadata
/// [field values]: ../field/struct.ValueSet.html
/// [`follows_from`]: ../struct.Span.html#method.follows_from
pub fn child_of<I>(
parent: I,
meta: &'static Metadata<'static>,
values: &field::ValueSet,
) -> Span
where
I: AsId,
{
let new_span = match parent.as_id() {
Some(parent) => Attributes::child_of(parent.clone(), meta, values),
None => Attributes::new_root(meta, values),
};
Self::make(meta, new_span)
}
/// Constructs a new disabled span.
#[inline(always)]
pub fn new_disabled(meta: &'static Metadata<'static>) -> Span {
Span { inner: None, meta }
}
fn make(meta: &'static Metadata<'static>, new_span: Attributes) -> Span {
let attrs = &new_span;
let inner = ::dispatcher::get_default(move |dispatch| {
let id = dispatch.new_span(attrs);
Some(Inner::new(id, dispatch))
});
let span = Self { inner, meta };
span.log(format_args!("{}; {}", meta.name(), FmtAttrs(&new_span)));
span
}
/// Executes the given function in the context of this span.
///
/// If this span is enabled, then this function enters the span, invokes
/// and then exits the span. If the span is disabled, `f` will still be
/// invoked, but in the context of the currently-executing span (if there is
/// one).
///
/// Returns the result of evaluating `f`.
pub fn enter<F: FnOnce() -> T, T>(&self, f: F) -> T {
self.log(format_args!("-> {}", self.meta.name));
let _enter = self.inner.as_ref().map(Inner::enter);
let result = f();
self.log(format_args!("<- {}", self.meta.name));
result
}
/// Returns a [`Field`](../field/struct.Field.html) for the field with the
/// given `name`, if one exists,
pub fn field<Q: ?Sized>(&self, field: &Q) -> Option<field::Field>
where
Q: field::AsField,
{
self.metadata().and_then(|meta| field.as_field(meta))
}
/// Returns true if this `Span` has a field for the given
/// [`Field`](../field/struct.Field.html) or field name.
#[inline]
pub fn has_field<Q: ?Sized>(&self, field: &Q) -> bool
where
Q: field::AsField,
{
self.field(field).is_some()
}
/// Visits that the field described by `field` has the value `value`.
pub fn record<Q: ?Sized, V>(&self, field: &Q, value: &V) -> &Self
where
Q: field::AsField,
V: field::Value,
{
if let Some(field) = field.as_field(self.meta) {
self.record_all(
&self
.meta
.fields()
.value_set(&[(&field, Some(value as &field::Value))]),
);
}
self
}
/// Visit all the fields in the span
pub fn record_all(&self, values: &field::ValueSet) -> &Self {
let record = Record::new(values);
if let Some(ref inner) = self.inner {
inner.record(&record);
}
self.log(format_args!("{}; {}", self.meta.name(), FmtValues(&record)));
self
}
/// Returns `true` if this span was disabled by the subscriber and does not
/// exist.
#[inline]
pub fn is_disabled(&self) -> bool {
self.inner.is_none()
}
/// Indicates that the span with the given ID has an indirect causal
/// relationship with this span.
///
/// This relationship differs somewhat from the parent-child relationship: a
/// span may have any number of prior spans, rather than a single one; and
/// spans are not considered to be executing _inside_ of the spans they
/// follow from. This means that a span may close even if subsequent spans
/// that follow from it are still open, and time spent inside of a
/// subsequent span should not be included in the time its precedents were
/// executing. This is used to model causal relationships such as when a
/// single future spawns several related background tasks, et cetera.
///
/// If this span is disabled, or the resulting follows-from relationship
/// would be invalid, this function will do nothing.
pub fn follows_from<I>(&self, from: I) -> &Self
where
I: AsId,
{
if let Some(ref inner) = self.inner {
if let Some(from) = from.as_id() {
inner.follows_from(from);
}
}
self
}
/// Returns this span's `Id`, if it is enabled.
pub fn id(&self) -> Option<Id> {
self.inner.as_ref().map(Inner::id)
}
/// Returns this span's `Metadata`, if it is enabled.
pub fn metadata(&self) -> Option<&'static Metadata<'static>> {
if self.inner.is_some() {
Some(self.meta)
} else {
None
}
}
#[cfg(feature = "log")]
#[inline]
fn log(&self, message: fmt::Arguments) {
use log;
let logger = log::logger();
let log_meta = log::Metadata::builder()
.level(level_to_log!(self.meta.level))
.target(self.meta.target)
.build();
if logger.enabled(&log_meta) {
logger.log(
&log::Record::builder()
.metadata(log_meta)
.module_path(self.meta.module_path)
.file(self.meta.file)
.line(self.meta.line)
.args(message)
.build(),
);
}
}
#[cfg(not(feature = "log"))]
#[inline]
fn log(&self, _: fmt::Arguments) {}
}
impl cmp::PartialEq for Span {
fn eq(&self, other: &Self) -> bool {
self.meta.callsite() == other.meta.callsite() && self.inner == other.inner
}
}
impl Hash for Span {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.inner.hash(hasher);
}
}
impl fmt::Debug for Span {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut span = f.debug_struct("Span");
span.field("name", &self.meta.name())
.field("level", &self.meta.level())
.field("target", &self.meta.target());
if let Some(ref inner) = self.inner {
span.field("id", &inner.id());
} else {
span.field("disabled", &true);
}
if let Some(ref path) = self.meta.module_path() {
span.field("module_path", &path);
}
if let Some(ref line) = self.meta.line() {
span.field("line", &line);
}
if let Some(ref file) = self.meta.file() {
span.field("file", &file);
}
span.finish()
}
}
// ===== impl Inner =====
impl Inner {
/// Enters the span, returning a guard that may be used to exit the span and
/// re-enter the prior span.
///
/// This is used internally to implement `Span::enter`. It may be used for
/// writing custom span handles, but should generally not be called directly
/// when entering a span.
#[inline]
fn enter(&self) -> Entered {
self.subscriber.enter(&self.id);
Entered { inner: self }
}
/// Indicates that the span with the given ID has an indirect causal
/// relationship with this span.
///
/// This relationship differs somewhat from the parent-child relationship: a
/// span may have any number of prior spans, rather than a single one; and
/// spans are not considered to be executing _inside_ of the spans they
/// follow from. This means that a span may close even if subsequent spans
/// that follow from it are still open, and time spent inside of a
/// subsequent span should not be included in the time its precedents were
/// executing. This is used to model causal relationships such as when a
/// single future spawns several related background tasks, et cetera.
///
/// If this span is disabled, this function will do nothing. Otherwise, it
/// returns `Ok(())` if the other span was added as a precedent of this
/// span, or an error if this was not possible.
fn follows_from(&self, from: &Id) {
self.subscriber.record_follows_from(&self.id, &from)
}
/// Returns the span's ID.
fn id(&self) -> Id {
self.id.clone()
}
fn record(&self, values: &Record) {
self.subscriber.record(&self.id, values)
}
fn new(id: Id, subscriber: &Dispatch) -> Self {
Inner {
id,
subscriber: subscriber.clone(),
}
}
}
impl cmp::PartialEq for Inner {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Hash for Inner {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl Drop for Inner {
fn drop(&mut self) {
self.subscriber.drop_span(self.id.clone());
}
}
impl Clone for Inner {
fn clone(&self) -> Self {
Inner {
id: self.subscriber.clone_span(&self.id),
subscriber: self.subscriber.clone(),
}
}
}
// ===== impl Entered =====
impl<'a> Drop for Entered<'a> {
#[inline]
fn drop(&mut self) {
// Dropping the guard exits the span.
//
// Running this behaviour on drop rather than with an explicit function
// call means that spans may still be exited when unwinding.
self.inner.subscriber.exit(&self.inner.id);
}
}
struct FmtValues<'a>(&'a Record<'a>);
impl<'a> fmt::Display for FmtValues<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut res = Ok(());
self.0.record(&mut |k: &field::Field, v: &fmt::Debug| {
res = write!(f, "{}={:?} ", k, v);
});
res
}
}
struct FmtAttrs<'a>(&'a Attributes<'a>);
impl<'a> fmt::Display for FmtAttrs<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut res = Ok(());
self.0.record(&mut |k: &field::Field, v: &fmt::Debug| {
res = write!(f, "{}={:?} ", k, v);
});
res
}
}
// ===== impl AsId =====
impl ::sealed::Sealed for Span {}
impl AsId for Span {
fn as_id(&self) -> Option<&Id> {
self.inner.as_ref().map(|inner| &inner.id)
}
}
impl<'a> ::sealed::Sealed for &'a Span {}
impl<'a> AsId for &'a Span {
fn as_id(&self) -> Option<&Id> {
self.inner.as_ref().map(|inner| &inner.id)
}
}
impl ::sealed::Sealed for Id {}
impl AsId for Id {
fn as_id(&self) -> Option<&Id> {
Some(self)
}
}
impl<'a> ::sealed::Sealed for &'a Id {}
impl<'a> AsId for &'a Id {
fn as_id(&self) -> Option<&Id> {
Some(self)
}
}
impl ::sealed::Sealed for Option<Id> {}
impl AsId for Option<Id> {
fn as_id(&self) -> Option<&Id> {
self.as_ref()
}
}
impl<'a> ::sealed::Sealed for &'a Option<Id> {}
impl<'a> AsId for &'a Option<Id> {
fn as_id(&self) -> Option<&Id> {
self.as_ref()
}
}
#[cfg(test)]
mod test {
use super::*;
trait AssertSend: Send {}
impl AssertSend for Span {}
trait AssertSync: Sync {}
impl AssertSync for Span {}
}

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