eclipse启用代码规范_启用锈代码诊断

eclipse启用代码规范

Debugging in Rust is difficult. It may be possible, but the instruments allowing to do so are nowhere near the equivalents of Java or C#, partly because the latter languages have virtual machines underneath.

在Rust中进行调试非常困难。 可能是有可能的,但是允许这样做的工具远不及Java或C#的等效物,部分原因是后者的语言在下面具有虚拟机。

Tracing is an issue closely related to debugging, although not the same. Tracing allows the programmer to see how the program reacts on external stimuli (such as network messages) and examine the program life-cycle. Clearly, tracing allows to flag situations where a proper debugging must take place.

跟踪是与调试紧密相关的问题,尽管并不相同。 跟踪使程序员可以查看程序对外部刺激(例如网络消息)的React,并检查程序的生命周期。 显然,跟踪允许标记必须进行适当调试的情况。

It is often the case that developers resort to old plain println! statements to trace own code. In any reasonably large program this method will result in a hardly manageable set of println! statements creating more confusion than clarification. Let’s agree this isn’t a viable option and investigate what else the Rust ecosystem has to offer.

开发人员通常会使用旧的普通println! 语句来跟踪自己的代码。 在任何相当大的程序中,此方法都将导致难以管理的println!集合println! 陈述比澄清更令人困惑。 让我们同意这不是一个可行的选择,并研究Rust生态系统还可以提供什么。

log方法 (The log method)

Next level of sophistication is the usage of log crate. This crate is an abstract layer for logging, it distinguishes 5 levels of importance (in descending order of importance): error!, warn!, info!, debug! and trace! . This crate requires a concrete logger implementation, often env_logger to be paired with log . env_logger is simple, clean, and nice to use. It requires 1 line to initialize it:

复杂性的下一个层次是log箱的用法。 此板条箱是用于记录的抽象层,它区分了5个重要级别(按重要性降序): error!warn!info!debug!trace! 。 此板条箱需要具体的记录器实现,通常env_loggerlog配对。 env_logger简单,干净并且易于使用。 它需要1行来初始化它:

env_logger::init();

and allows to quickly configure the level of log messages using an environment variable

并允许使用环境变量快速配置日志消息的级别

RUST_LOG=trace cargo run

This configuration is extremely flexible and allows to configure separate levels per module. For example:

此配置非常灵活,可以为每个模块配置单独的级别。 例如:

RUST_LOG=module1=trace,module2=info cargo run

will ensure the logger only outputs messages of higher or equal importance than that specified from the appropriate modules.

将确保记录器仅输出比相应模块指定的消息重要的消息。

This method is sufficient in many case, for example, large projects such as Hyperledger Indy use it to the fullest: entry into and exit from a function is accompanied with log statements printing out input parameters and the function result.

这种方法在很多情况下就足够了,例如,大型项目(例如Hyperledger Indy)可以最大程度地使用它:函数的进入和退出都带有输出输出参数和函数结果的日志语句。

异步代码 (Asynchronous code)

Before going further, let us take a short detour. Many (if not all) network applications allow for accepting external messages/requests before an earlier accepted message/request is processed. In such cases, asynchronous code is a real painkiller. Writing async code in Rust has become a breeze after Rust has matured to 1.39, and, most notably, multi-purpose futures driving platform tokio and HTTP library hyper aligned themselves with the newly introduced functionality. This totality of work had a tremendous impact how async Rust code is written. Importantly, tokio introduces a concept of a task, a piece of work which is executed in parallel in a multi-threaded context, task can be paused and passed around between the threads. Tasks are paused at the await calls until the call has been completed, e.g., an event has occurred or the required data have arrived.

在继续之前,让我们先走一下弯路。 许多(如果不是全部)网络应用程序允许在处理较早接受的消息/请求之前接受外部消息/请求。 在这种情况下,异步代码是真正的止痛药。 在Rust成熟到1.39之后,在Rust中编写异步代码变得轻而易举,最显着的是,多功能期货驱动平台tokio和HTTP库将它们与新引入的功能hyper结合。 如此大量的工作对异步Rust代码的编写方式产生了巨大影响。 重要的是, tokio引入了任务的概念,即在多线程上下文中并行执行的一项工作,任务可以暂停并在线程之间传递。 任务在await呼叫处暂停,直到呼叫完成(例如,事件已发生或所需数据已到达)。

tracing方法 (The tracing method)

I gave one example of how a large project uses the log crate to generate execution traces. It works, why would one look for another option? There are two reasons to look further:

我举了一个有关大型项目如何使用log箱生成执行跟踪的示例。 它有效,为什么一个人会寻找另一种选择? 需要进一步研究的原因有两个:

  1. Size. Although the trace log demonstrates only linearly growth with respect to the size of the code base, it may become unwieldy for manual inspection.

    尺寸。 尽管跟踪日志仅显示出相对于代码库大小的线性增长,但是对于手动检查而言可能变得笨拙。
  2. Code pollution. Logging statements, although useful, often decrease overall readability, especially if used to print out function arguments and evaluation results.

    代码污染。 日志记录语句虽然有用,但通常会降低总体可读性,尤其是如果用于打印函数自变量和评估结果时。
  3. Asynchronous code. Parallel execution messes tracing up. Often, log traces from different tasks interleave each other rendering them intractable.

    异步代码。 并行执行陷入困境。 通常,来自不同任务的log跟踪相互交错,使它们难以处理。

The sum of these points begs the question: what’s the alternative. Enter the tracing crate. This crate provides instrumenting functionality to collect structured diagnostic from your application. Its core functionality is based on the premise that all logging happens within spans. A span is a continuous stretch of time with a defined start and end. Spans are entered and left, and other and spans can be entered and left within a span. This property defines an inclusion relation on a set of all spans. The inclusion relation allows to structure log messages in a time domain, but, prominently, defines causal relationship on spans. The latter is very much important in async code, when tasks can be paused and picked up.

这些要点的总和就是一个问题:替代方案是什么。 输入tracing箱。 此板条箱提供检测功能,可从您的应用程序收集结构化诊断。 它的核心功能基于所有记录均在跨度内进行的前提 跨度是具有定义的开始和结束的连续时间段。 输入和保留跨度,可以输入和保留其他和跨度。 此属性在所有范围的集合上定义一个包含关系。 包含关系允许在时域中构造日志消息,但是,突出地定义跨度上的因果关系。 当任务可以暂停和接收时,后者在异步代码中非常重要。

In the above diagram, Task A is associated with Span A, Task B with Span B, etc. Denote the respective task starting times with t(·). In the time domain, the starting times are completely ordered, t(A) < t(B) < t(C) < t(D). In the causal domain the order relation is partial, this can represented, using the set inclusion sign liberally, as A ⊆ B, B ⊆ C, B ⊆ D, B is caused by A, C by B, etc.

在上图中,任务A与跨度A相关联,任务B与跨度B相关联,等等。以t(·)表示各个任务的开始时间。 在时域中,开始时间是完全有序的,t(A)<t(B)<t(C)<t(D)。 在因果域中,顺序关系是局部的,可以使用集合包含符号自由地表示,因为A⊆B,B⊆C,B⊆D,B由A引起,C由B引起,等等。

The tracing crate has an open-ended interface allowing to plug in different collectors or subscribers for the tracing messages. The simplest subscriber logs directly to the standard output. This is barely an improvement, luckily, it’s not the only option. To really stand out, these traces:

tracing箱具有一个开放式接口,允许为跟踪消息插入不同的收集器或订户。 最简单的订户直接登录到标准输出。 幸运的是,这几乎不是一个改进,并不是唯一的选择。 要真正脱颖而出,这些痕迹是:

  1. Must be persistent, thus be available also when the respective application is not running.

    必须是持久性的,因此在相应应用程序未运行时也可用。
  2. Must be conveniently accessible from different hosts, not necessarily from the host executing the application.

    必须可以方便地从其他主机访问,而不必从执行应用程序的主机访问。

One subscriber fulfilling these requirements is tracing-opentelemetry.

满足这些要求的一个用户是tracing-opentelemetry

Let’s dive in!

让我们潜入吧!

Create an async function doing some heavy work:

创建一个异步函数来完成一些繁重的工作:

struct Dummy;#[tracing::instrument(skip(_dummy))]
async fn heavy_work(id: String, units: u64, _dummy: Dummy) -> String {
for i in 1..=units {
tokio::time::delay_for(Duration::from_secs(1)).await;
tracing::info!("{} has been working for {} units", id, i);
}

id
}

Let’s unpack.

让我们打开包装。

  1. Instrumentation. Macro #[tracing::instrument], roughly speaking, creates a span for this function and enters it. Macro uses the function name and its parameters for its metadata. This creates the requirement for the parameters to implement the Debug trait; to exclude a parameter from metadata, use skip in the instrumentation instruction. More attributes can be found here.

    仪器仪表。 粗略地说,宏#[tracing::instrument]会为此函数创建一个跨度并输入它。 宏将函数名称及其参数用于元数据。 这为实现Debug trait的参数提出了要求; 要从元数据中排除参数,请在检测指令中使用skip 。 在这里可以找到更多属性。

  2. tracing::info! does the actual tracing.

    tracing::info! 进行实际跟踪。

Let’s reuse a tracer initialization functioninit_tracer, it’s good enough to start developing and likely to be adjusted when more customization is required.

让我们重用一个跟踪器初始化函数init_tracer ,它足以开始开发,并且在需要更多定制时可能会进行调整。

Finally, the main function:

最后, main功能:

#[tokio::main]
async fn main() {
init_tracer().expect("Tracer setup failed");
let root = tracing::span!(tracing::Level::TRACE, "lifecycle");
let _enter = root.enter();

let rng = rand::thread_rng();
let normal = rand_distr::Normal::new(5.0, 1.0).unwrap();

let mut finished_work = normal
.sample_iter(rng)
.take(10)
.map(|t| heavy_work(t.to_string(), t.to_u64().expect("Must convert"), Dummy))
.collect::<FuturesUnordered<_>>();

while let Some(id) = finished_work.next().await {
tracing::info!("{} has completed", id);
}
}

Related to the topic, this function accomplishes two things: initializes a tracer and enters the root span. The rest is just a wrapper making calls to the function doing the heavy work and receiving the results.

与该主题相关,此函数完成两件事:初始化跟踪器并输入根范围。 剩下的只是一个包装器,它调用该函数来完成繁重的工作并接收结果。

The Rust compiler de-sugars async functions into a state machine, which is polled at the execution time. What seems to be a single functional call for the programmer is, in fact, an act of repeated function invocation. For tracing it means, that the respective span will be entered and left many times before the underlying state machine completes. This behavior also presents a challenge to tracing, because it complicates the treatment of span inclusions. Instead of one cohesive span corresponding to an async piece of code, there will be a plurality of smaller spans.

Rust编译器将异步功能添加到状态机中,并在执行时对其进行轮询。 实际上,对程序员来说,似乎是单个功能调用,实际上是重复调用功能。 对于跟踪,这意味着在基础状态机完成之前,将分别输入和保留多次跨度。 这种行为也对跟踪提出了挑战,因为它使跨度夹杂物的处理变得复杂。 代替与一个异步代码段相对应的一个内聚范围,将有多个较小的范围。

One option to parse the tracing logs (adhering to the opentelemetry specifications) is to use Jaeger. This is a tool specifically designed to increase observability of how applications are executed.

解析跟踪日志(遵循opentelemetry规范)的一种选择是使用Jaeger 。 这是专门设计用来提高应用程序执行方式的可观察性的工具。

To collect and analyze traces, Docker must be installed. Run Jaeger

要收集和分析跟踪,必须安装Docker。 运行积家

docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 jaegertracing/all-in-one:latest

Run your application.

运行您的应用程序。

Open your favorite browser and go to http://localhost:16686/. What you see is quite impressive. It is a tool chest full of neat visualizations and analytical instruments.

打开您喜欢的浏览器,然后转到http://localhost:16686/ 。 您所看到的令人印象深刻。 它是一个充满整洁的可视化和分析工具的工具箱。

Image for post

I created a small script running the application continuously to simulate a load making the execution time graph at the top somewhat populated.

我创建了一个小脚本,该脚本连续运行应用程序以模拟负载,从而使顶部的执行时间图有所填充。

Every trace can be examined structurally and temporally.

每条迹线都可以在结构上和时间上进行检查。

Image for post
Trace composition
微量成分

Every span corresponds to a function call. Notice how neatly messages from multiple async sub-calls are grouped together to create an impression of uninterrupted execution.

每个范围对应一个函数调用。 请注意,如何将来自多个异步子调用的消息整齐地组合在一起,以产生不间断执行的印象。

Image for post
Messages produced during execution of the respective function
执行相应功能时产生的消息

Span’s meta information allows for easy inspection of the function arguments, for example, units = 5 .

Span的元信息可轻松检查函数参数,例如, units = 5

Image for post

Next level of (experimental) sophistication is a graph representing the causal relationship discussed above. This representation can be found under a drop-down list “Trace Timeline”.

(实验)复杂度的下一个层次是代表上述因果关系的图表。 可以在下拉列表“跟踪时间线”下找到此表示形式。

结论 (Conclusion)

Crates tracing and tracing-opentelemetry enable simple and clean tracing of Rust applications. Jaeger presents such traces in a comprehensible way and provides analytics over them. This piece barely touches the possibilities provided by these tools, but, in essence, provides a good starting point to explore further!

板条箱tracingtracing-opentelemetry可实现Rust应用程序的简单干净的跟踪。 Jaeger以一种易于理解的方式展示了这些痕迹,并对其进行了分析。 这篇文章几乎没有涉及这些工具提供的可能性,但是,从本质上讲,它为进一步探索提供了一个很好的起点!

Source code can be found on Github.

源代码可以在Github上找到。

翻译自: https://medium.com/@victorermolaev/enabling-diagnostics-for-rust-code-c359ceee1296

eclipse启用代码规范

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值