分类 技术 下的文章

Delve 是能让调试变成轻而易举的事的万能工具包。

你上次尝试去学习一种新的编程语言时什么时候?你有没有持之以恒,你是那些在新事物发布的第一时间就勇敢地去尝试的一员吗?不管怎样,学习一种新的语言也许非常有用,也会有很多乐趣。

你尝试着写简单的 “Hello, world!”,然后写一些示例代码并执行,继续做一些小的修改,之后继续前进。我敢保证我们都有过这个经历,不论我们使用哪种技术。假如你尝试用一段时间一种语言,并且你希望能够精通它,那么有一些事物能在你的进取之路上帮助你。

其中之一就是调试器。有些人喜欢在代码中用简单的 “print” 语句进行调试,这种方式很适合代码量少的简单程序;然而,如果你处理的是有多个开发者和几千行代码的大型项目,你应该使用调试器。

最近我开始学习 Go 编程语言了,在本文中,我们将探讨一种名为 Delve 的调试器。Delve 是专门用来调试 Go 程序的工具,我们会借助一些 Go 示例代码来了解下它的一些功能。不要担心这里展示的 Go 示例代码;即使你之前没有写过 Go 代码也能看懂。Go 的目标之一是简单,因此代码是始终如一的,理解和解释起来都很容易。

Delve 介绍

Delve 是托管在 GitHub 上的一个开源项目。

它自己的文档中写道:

Delve 是 Go 编程语言的调试器。该项目的目标是为 Go 提供一个简单、全功能的调试工具。Delve 应该是易于调用和易于使用的。当你使用调试器时,事情可能不会按你的思路运行。如果你这样想,那么你不适合用 Delve。

让我们来近距离看一下。

我的测试系统是运行着 Fedora Linux 的笔记本电脑,Go 编译器版本如下:

$ cat /etc/fedora-release
Fedora release 30 (Thirty)
$
$ go version
go version go1.12.17 linux/amd64
$

Golang 安装

如果你没有安装 Go,你可以运行下面的命令,很轻松地就可以从配置的仓库中获取。

$ dnf install golang.x86_64

或者,你可以在安装页面找到适合你的操作系统的其他安装版本。

在开始之前,请先确认已经设置好了 Go 工具依赖的下列各个路径。如果这些路径没有设置,有些示例可能不能正常运行。你可以在 SHELL 的 RC 文件中轻松设置这些环境变量,我的机器上是在 $HOME/bashrc 文件中设置的。

$ go env | grep GOPATH
GOPATH="/home/user/go"
$
$ go env | grep GOBIN
GOBIN="/home/user/go/gobin"
$

Delve 安装

你可以像下面那样,通过运行一个简单的 go get 命令来安装 Delve。go get 是 Golang 从外部源下载和安装需要的包的方式。如果你安装过程中遇到了问题,可以查看 Delve 安装教程

$ go get -u github.com/go-delve/delve/cmd/dlv
$

运行上面的命令,就会把 Delve 下载到你的 $GOPATH 的位置,如果你没有把 $GOPATH 设置成其他值,那么默认情况下 $GOPATH$HOME/go 是同一个路径。

你可以进入 go/ 目录,你可以在 bin/ 目录下看到 dlv

$ ls -l $HOME/go
total 8
drwxrwxr-x. 2 user user 4096 May 25 19:11 bin
drwxrwxr-x. 4 user user 4096 May 25 19:21 src
$
$ ls -l ~/go/bin/
total 19596
-rwxrwxr-x. 1 user user 20062654 May 25 19:17 dlv
$

因为你把 Delve 安装到了 $GOPATH,所以你可以像运行普通的 shell 命令一样运行它,即每次运行时你不必先进入它所在的目录。你可以通过 version 选项来验证 dlv 是否正确安装。示例中安装的版本是 1.4.1。

$ which dlv
~/go/bin/dlv
$
$ dlv version
Delve Debugger
Version: 1.4.1
Build: $Id: bda606147ff48b58bde39e20b9e11378eaa4db46 $
$

现在,我们一起在 Go 程序中使用 Delve 来理解下它的功能以及如何使用它们。我们先来写一个 hello.go,简单地打印一条 Hello, world! 信息。

记着,我把这些示例程序放到了 $GOBIN 目录下。

$ pwd
/home/user/go/gobin
$
$ cat hello.go
package main

import "fmt"

func main() {
        fmt.Println("Hello, world!")
}
$

运行 build 命令来编译一个 Go 程序,它的输入是 .go 后缀的文件。如果程序没有语法错误,Go 编译器把它编译成一个二进制可执行文件。这个文件可以被直接运行,运行后我们会在屏幕上看到 Hello, world! 信息。

$ go build hello.go
$
$ ls -l hello
-rwxrwxr-x. 1 user user 1997284 May 26 12:13 hello
$
$ ./hello
Hello, world!
$

在 Delve 中加载程序

把一个程序加载进 Delve 调试器有两种方式。

在源码编译成二进制文件之前使用 debug 参数

第一种方式是在需要时对源码使用 debug 命令。Delve 会为你编译出一个名为 __debug_bin 的二进制文件,并把它加载进调试器。

在这个例子中,你可以进入 hello.go 所在的目录,然后运行 dlv debug 命令。如果目录中有多个源文件且每个文件都有自己的主函数,Delve 则可能抛出错误,它期望的是单个程序或从单个项目构建成单个二进制文件。如果出现了这种错误,那么你就应该用下面展示的第二种方式。

$ ls -l
total 4
-rw-rw-r--. 1 user user 74 Jun  4 11:48 hello.go
$
$ dlv debug
Type 'help' for list of commands.
(dlv)

现在打开另一个终端,列出目录下的文件。你可以看到一个多出来的 __debug_bin 二进制文件,这个文件是由源码编译生成的,并会加载进调试器。你现在可以回到 dlv 提示框继续使用 Delve。

$ ls -l
total 2036
-rwxrwxr-x. 1 user user 2077085 Jun  4 11:48 __debug_bin
-rw-rw-r--. 1 user user      74 Jun  4 11:48 hello.go
$

使用 exec 参数

如果你已经有提前编译好的 Go 程序或者已经用 go build 命令编译完成了,不想再用 Delve 编译出 __debug_bin 二进制文件,那么第二种把程序加载进 Delve 的方法在这些情况下会很有用。在上述情况下,你可以使用 exec 命令来把整个目录加载进 Delve 调试器。

$ ls -l
total 4
-rw-rw-r--. 1 user user 74 Jun  4 11:48 hello.go
$
$ go build hello.go
$
$ ls -l
total 1956
-rwxrwxr-x. 1 user user 1997284 Jun  4 11:54 hello
-rw-rw-r--. 1 user user      74 Jun  4 11:48 hello.go
$
$ dlv exec ./hello
Type 'help' for list of commands.
(dlv)

查看 delve 帮助信息

dlv 提示符中,你可以运行 help 来查看 Delve 提供的多种帮助选项。命令列表相当长,这里我们只列举一些重要的功能。下面是 Delve 的功能概览。

(dlv) help
The following commands are available:

Running the program:

Manipulating breakpoints:

Viewing program variables and memory:

Listing and switching between threads and goroutines:

Viewing the call stack and selecting frames:

Other commands:

Type help followed by a command for full documentation.
(dlv)

设置断点

现在我们已经把 hello.go 程序加载进了 Delve 调试器,我们在主函数处设置断点,稍后来确认它。在 Go 中,主程序从 main.main 处开始执行,因此你需要给这个名字提供个 break 命令。之后,我们可以用 breakpoints 命令来检查断点是否正确设置了。

不要忘了你还可以用命令简写,因此你可以用 b main.main 来代替 break main.main,两者效果相同,bpbreakpoints 同理。你可以通过运行 help 命令查看帮助信息来找到你想要的命令简写。

(dlv) break main.main
Breakpoint 1 set at 0x4a228f for main.main() ./hello.go:5
(dlv) breakpoints
Breakpoint runtime-fatal-throw at 0x42c410 for runtime.fatalthrow() /usr/lib/golang/src/runtime/panic.go:663 (0)
Breakpoint unrecovered-panic at 0x42c480 for runtime.fatalpanic() /usr/lib/golang/src/runtime/panic.go:690 (0)
        print runtime.curg._panic.arg
Breakpoint 1 at 0x4a228f for main.main() ./hello.go:5 (0)
(dlv)

程序继续执行

现在,我们用 continue 来继续运行程序。它会运行到断点处中止,在我们的例子中,会运行到主函数的 main.main 处中止。从这里开始,我们可以用 next 命令来逐行执行程序。请注意,当我们运行到 fmt.Println("Hello, world!") 处时,即使我们还在调试器里,我们也能看到打印到屏幕的 Hello, world!

(dlv) continue
> main.main() ./hello.go:5 (hits goroutine(1):1 total:1) (PC: 0x4a228f)
     1: package main
     2:
     3: import "fmt"
     4:
=>   5:      func main() {
     6:         fmt.Println("Hello, world!")
     7: }
(dlv) next
> main.main() ./hello.go:6 (PC: 0x4a229d)
     1: package main
     2:
     3: import "fmt"
     4:
     5: func main() {
=>   6:              fmt.Println("Hello, world!")
     7: }
(dlv) next
Hello, world!
> main.main() ./hello.go:7 (PC: 0x4a22ff)
     2:
     3: import "fmt"
     4:
     5: func main() {
     6:         fmt.Println("Hello, world!")
=>   7:      }
(dlv)

退出 Delve

你随时可以运行 quit 命令来退出调试器,退出之后你会回到 shell 提示符。相当简单,对吗?

(dlv) quit
$

Delve 的其他功能

我们用其他的 Go 程序来探索下 Delve 的其他功能。这次,我们从 golang 教程 中找了一个程序。如果你要学习 Go 语言,那么 Golang 教程应该是你的第一站。

下面的程序,functions.go 中简单展示了 Go 程序中是怎样定义和调用函数的。这里,我们有一个简单的把两数相加并返回和值的 add() 函数。你可以像下面那样构建程序并运行它。

$ cat functions.go
package main

import "fmt"

func add(x int, y int) int {
        return x + y
}

func main() {
        fmt.Println(add(42, 13))
}
$

你可以像下面那样构建和运行程序。

$ go build functions.go  && ./functions
55
$

进入函数

跟前面展示的一样,我们用前面提到的一个选项来把二进制文件加载进 Delve 调试器,再一次在 main.main 处设置断点,继续运行程序直到断点处。然后执行 next 直到 fmt.Println(add(42, 13)) 处;这里我们调用了 add() 函数。我们可以像下面展示的那样,用 Delve 的 step 命令从 main 函数进入 add() 函数。

$ dlv debug
Type 'help' for list of commands.
(dlv) break main.main
Breakpoint 1 set at 0x4a22b3 for main.main() ./functions.go:9
(dlv) c
> main.main() ./functions.go:9 (hits goroutine(1):1 total:1) (PC: 0x4a22b3)
     4:
     5: func add(x int, y int) int {
     6:         return x + y
     7: }
     8:
=>   9:      func main() {
    10:         fmt.Println(add(42, 13))
    11: }
(dlv) next
> main.main() ./functions.go:10 (PC: 0x4a22c1)
     5: func add(x int, y int) int {
     6:         return x + y
     7: }
     8:
     9: func main() {
=>  10:              fmt.Println(add(42, 13))
    11: }
(dlv) step
> main.add() ./functions.go:5 (PC: 0x4a2280)
     1: package main
     2:
     3: import "fmt"
     4:
=>   5:      func add(x int, y int) int {
     6:         return x + y
     7: }
     8:
     9: func main() {
    10:         fmt.Println(add(42, 13))
(dlv)

使用文件名:行号来设置断点

上面的例子中,我们经过 main 函数进入了 add() 函数,但是你也可以在你想加断点的地方直接使用“文件名:行号”的组合。下面是在 add() 函数开始处加断点的另一种方式。

(dlv) break functions.go:5
Breakpoint 1 set at 0x4a2280 for main.add() ./functions.go:5
(dlv) continue
> main.add() ./functions.go:5 (hits goroutine(1):1 total:1) (PC: 0x4a2280)
     1: package main
     2:
     3: import "fmt"
     4:
=>   5:      func add(x int, y int) int {
     6:         return x + y
     7: }
     8:
     9: func main() {
    10:         fmt.Println(add(42, 13))
(dlv)

查看当前的栈信息

现在我们运行到了 add() 函数,我们可以在 Delve 中用 stack 命令查看当前栈的内容。这里在 0 位置展示了栈顶的函数 add() ,紧接着在 1 位置展示了调用 add() 函数的 main.main。在 main.main 下面的函数属于 Go 运行时,是用来处理加载和执行该程序的。

(dlv) stack
0  0x00000000004a2280 in main.add
   at ./functions.go:5
1  0x00000000004a22d7 in main.main
   at ./functions.go:10
2  0x000000000042dd1f in runtime.main
   at /usr/lib/golang/src/runtime/proc.go:200
3  0x0000000000458171 in runtime.goexit
   at /usr/lib/golang/src/runtime/asm_amd64.s:1337
(dlv)

在帧之间跳转

在 Delve 中我们可以用 frame 命令实现帧之间的跳转。在下面的例子中,我们用 frame 实现了从 add() 帧跳到 main.main 帧,以此类推。

(dlv) frame 0
> main.add() ./functions.go:5 (hits goroutine(1):1 total:1) (PC: 0x4a2280)
Frame 0: ./functions.go:5 (PC: 4a2280)
     1: package main
     2:
     3: import "fmt"
     4:
=>   5:      func add(x int, y int) int {
     6:         return x + y
     7: }
     8:
     9: func main() {
    10:         fmt.Println(add(42, 13))
(dlv) frame 1
> main.add() ./functions.go:5 (hits goroutine(1):1 total:1) (PC: 0x4a2280)
Frame 1: ./functions.go:10 (PC: 4a22d7)
     5: func add(x int, y int) int {
     6:         return x + y
     7: }
     8:
     9: func main() {
=>  10:              fmt.Println(add(42, 13))
    11: }
(dlv)

打印函数参数

一个函数通常会接收多个参数。在 add() 函数中,它的入参是两个整型。Delve 有个便捷的 args 命令,它能打印出命令行传给函数的参数。

(dlv) args
x = 42
y = 13
~r2 = 824633786832
(dlv)

查看反汇编码

由于我们是调试编译出的二进制文件,因此如果我们能查看编译器生成的汇编语言指令将会非常有用。Delve 提供了一个 disassemble 命令来查看这些指令。在下面的例子中,我们用它来查看 add() 函数的汇编指令。

(dlv) step
> main.add() ./functions.go:5 (PC: 0x4a2280)
     1: package main
     2:
     3: import "fmt"
     4:
=>   5:      func add(x int, y int) int {
     6:         return x + y
     7: }
     8:
     9: func main() {
    10:         fmt.Println(add(42, 13))
(dlv) disassemble
TEXT main.add(SB) /home/user/go/gobin/functions.go
=>   functions.go:5  0x4a2280   48c744241800000000   mov qword ptr [rsp+0x18], 0x0
        functions.go:6  0x4a2289   488b442408           mov rax, qword ptr [rsp+0x8]
        functions.go:6  0x4a228e   4803442410           add rax, qword ptr [rsp+0x10]
        functions.go:6  0x4a2293   4889442418           mov qword ptr [rsp+0x18], rax
        functions.go:6  0x4a2298   c3                   ret
(dlv)

单步退出函数

另一个功能是 stepout,这个功能可以让我们跳回到函数被调用的地方。在我们的例子中,如果我们想回到 main.main 函数,我们只需要简单地运行 stepout 命令,它就会把我们带回去。在我们调试大型代码库时,这个功能会是一个非常便捷的工具。

(dlv) stepout
> main.main() ./functions.go:10 (PC: 0x4a22d7)
Values returned:
        ~r2: 55

     5: func add(x int, y int) int {
     6:         return x + y
     7: }
     8:
     9: func main() {
=>  10:              fmt.Println(add(42, 13))
    11: }
(dlv)

打印变量信息

我们一起通过 Go 教程 的另一个示例程序来看下 Delve 是怎么处理 Go 中的变量的。下面的示例程序定义和初始化了一些不同类型的变量。你可以构建和运行程序。

$ cat variables.go
package main

import "fmt"

var i, j int = 1, 2

func main() {
        var c, python, java = true, false, "no!"
        fmt.Println(i, j, c, python, java)
}
$

$ go build variables.go &&; ./variables
1 2 true false no!
$

像前面说过的那样,用 delve debug 在调试器中加载程序。你可以在 Delve 中用 print 命令通过变量名来展示他们当前的值。

(dlv) print c
true
(dlv) print java
"no!"
(dlv)

或者,你还可以用 locals 命令来打印函数内所有的局部变量。

(dlv) locals
python = false
c = true
java = "no!"
(dlv)

如果你不知道变量的类型,你可以用 whatis 命令来通过变量名来打印它的类型。

(dlv) whatis python
bool
(dlv) whatis c
bool
(dlv) whatis java
string
(dlv)

总结

现在我们只是了解了 Delve 所有功能的皮毛。你可以自己去查看帮助内容,尝试下其它的命令。你还可以把 Delve 绑定到运行中的 Go 程序上(守护进程!),如果你安装了 Go 源码库,你甚至可以用 Delve 导出 Golang 库内部的信息。勇敢去探索吧!


via: https://opensource.com/article/20/6/debug-go-delve

作者:Gaurav Kamathe 选题:lujun9972 译者:lxbwolf 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

当你在 GIMP 中制作一个徽章、海报或其它任何作品时,你需要扭曲或弯曲一些文本。多功能的 GIMP 工具提供了一些创建弯曲文本的方法。取决于你将如何使用它和你想给予文本的弧度,有一些适合不同情况的方法。

在本篇教程中,我将向你展示我最喜欢的创建曲线文本的方法。

如何在 GIMP 中创建曲线文本

请确保你已经在你的系统上安装了 GIMP。

步骤 1: 创建一个你想要的匹配曲线的路径

创建一个新的图像或打开一个现有的图像。选择 “工具 -> 路径”,然后大致考虑曲线文本的位置,通过分别单击路径点的开始点和结束点来创建路径。

**然后给你的路径一个曲率。**首先向上或向下拖动中间的直线,然后通过移动调整点进行微调。这将给予它一个拱形结构。

步骤 2: 创建你想弯曲的文本

当你对自己的曲线路径满意时,你可以移动到接下来的步骤,并 创建你的文本

你可能想更改字体及其大小。我的选择只是为了演示用途。

步骤 3: 创建一个新的图层

我强烈建议分割 GIMP 图像中的每个不同的元素到不同的图层中,以便很容易地控制它们,像移动,打开/关闭一个元素等等。

遵循这一规则,我们要弯曲的文本将被放置到一个新的图层中。建议使用像 “Curved Text” 一样的名字来命名你的新的图层,或者一些类似的东西来很容易地识别它。

步骤 4: 弯曲文本

现在你需要在你的文本图层上单击,接下来在其上右击,并单击“文字对齐路径”来折弯你的文本。弯曲的文本将被放置到新创建的图层。

你把文本弯曲了!让我们使用颜色填充文本来使其更令人满意。

步骤 5: 最后的修饰和导出

单击弯曲的文本图层,然后转到路径选项卡来选择文本边界。

最后,选择油漆桶工具,选择一种颜色,并如下应用你的选择区。

随着最后一步的到来,打开不需要的层的可见性,只保留曲线文本。接下来,需要导出你的文件为你喜欢的图像格式。

额外提示:创建阴影效果

我还有一个作为一次挑战的额外的步骤,如果你想更进一步的话。让我们在 GIMP 中勾勒文本以创建一个弯曲文本的阴影效果。

我将给予你一些提示:

  • 重新启用所有图层
  • 单击弯曲文本图层,并使用移动工具来到处移动文本
  • 创建另一个图层,并使用黑色来重复油漆桶填充程序
  • 以一种模拟一种阴影位置的方式覆盖图层(你可能需要更改图层顺序)
  • 关闭辅助图层

最终结果:

让我在评论区知道你们对这篇 GIMP 教程的想法,以及有多少人尝试了这一额外的步骤。


via: https://itsfoss.com/curve-text-gimp/

作者:Dimitrios Savvopoulos 选题:lujun9972 译者:robsean 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

macOS 用户可以运行 Java 的开源版本,以及用于 云原生 cloud native 开发的新框架。

五月底,Java 庆祝了它的 25 周年纪念日,为了纪念这一时刻,世界各地的开发人员使用 #MovedByJava 这一标签分享他们使用这一编程语言的成就、记忆以及愿景。

我的时间线:

感谢你 @java#MovedByJava

— Graeme Rocher (@graemerocher) 2020年5月21日

多年来,许多技术和趋势都促进了 Java 堆栈的开发、部署和在标准应用程序服务器上运行多个应用的能力。为 Kubernetes 构建容器镜像使得 Java 开发者可以在多个云环境中打包和部署 微服务 microservices ,而不是在虚拟机上运行几个应用程序服务器。

 title=

有了这些技术,Java 应用程序栈被优化为运行更大的堆和可以在运行时做出决策的高动态框架。然而不幸的是,这些努力还不足以使 Java 成为开发人员为 无服务器 serverless 和事件驱动平台开发 云原生 cloud native Java 应用程序的首选编程语言。其他语言填补了这部分空缺,特别是 JavaScript、Python 和 Go,而 Rust 和 WebAssembly 也成了新的选择。

尽管存在这种竞争, 云原生 Java cloud native Java 正在对以云为中心的软件开发产生影响。好在,新的 Java 框架(比如,QuarkusMicronautHelidon)最近已经战胜了这些挑战,它们提供了编译速度更快而且更小的应用,同时它们在设计之初就将分布式系统考虑了进去。

如何在 macOS 上安装 Java

Java 开发的未来将从更多人安装和使用 Java 开始。因此,我将介绍如何在 macOS 上安装并开始使用 Java 开发环境。(如果你运行的是 Linux,请查看 Seth Kenlon 的文章《如何在 Linux 上安装 Java》)

通过 Brew 仓库安装 OpenJDK

Homebrew 是 macOS 事实上的标准软件包管理器。如果你还没有安装的话,Matthew Broberg 的文章《Homebrew 简介》将带你完成这些步骤。

当你在 Mac 上安装好 Homebrew 后,使用 brew 命令安装 OpenJDK,这是编写 Java 应用程序的开源方式:

$ brew cask install java

不到一分钟就能看到:

? java was successfully installed!

通过 java -version 命令确认 OpenJDK 已经正确安装:

$ java -version
openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment (build 14.0.1+7)
OpenJDK 64-Bit Server VM (build 14.0.1+7, mixed mode, sharing

从输出中可以确认 OpenJDK 14 (本文撰写时的最新版本)已经安装。

从二进制文件安装 OpenJDK

如果你并不热衷于包管理器,并且更愿意自己来管理 Java 的话,那么你总是可以选择下载并且手动安装。

我在 OpenJDK 主页上找到了最新版本的下载链接。下载 OpenJDK 14 的二进制文件:

$ wget https://download.java.net/java/GA/jdk14.0.1/664493ef4a6946b186ff29eb326336a2/7/GPL/openjdk-14.0.1_osx-x64_bin.tar.gz

移动到你保存二进制文件的目录,然后解压:

$ tar -xf openjdk-14.0.1_osx-x64_bin.tar.gz

接下来,将 Java 加入到你的 PATH:

$ export PATH=$PWD/jdk-14.0.1.jdk/Contents/Home/bin:$PATH

同时,将这条命令加到你的点文件中,.bash_profile 还是 .zshrc 取决于你运行的 shell。你可以在《如何在 Linux 中设置你的 PATH 变量》一文中了解更多关于配置 PATH变量][23]》一文中了解更多关于配置‘](https://opensource.com/article/17/6/set-path-linux)》一文中了解更多关于配置 $PATH` 变量的内容。

最后,验证你安装的 OpenJDK 14:

$ java -version
openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment (build 14.0.1+7)
OpenJDK 64-Bit Server VM (build 14.0.1+7, mixed mode, sharing)

在 Mac 上编写你的第一个 微服务 microservices

现在,你已经准备好在 maxOS 上使用 OpenJDK 堆栈开发 云原生 cloud native Java 应用程序了。在本教程中,你将在 Quarkus 上创建一个新的 Java 项目,这个项目使用 依赖注入 dependency injection 来公布 REST API。

你需要 Maven 启动,它是一个非常流行的 Java 依赖管理器。从 Maven 的网站安装它,或者通过 Homebrew 使用 brew install maven 命令。

执行以下 Maven 命令来配置 Quarkus 项目,并且创建一个简单的 web 应用:

$ mvn io.quarkus:quarkus-maven-plugin:1.5.1.Final:create \
    -DprojectGroupId=com.example \
    -DprojectArtifactId=getting-started \
    -DclassName="com.example.GreetingResource" \
    -Dpath="/hello"
cd getting-started

运行这个应用:

$ ./mvnw quarkus:dev

当应用程序运行的时候,你可以看到这个输出:

__  ____  __  _____   ___  __ ____  ______
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \  
\--\\___\\_\\____/_/ |_/_/|_/_/|_|\\____/___/  
2020-06-13 00:03:06,413 INFO  [io.quarkus] (Quarkus Main Thread) getting-started 1.0-SNAPSHOT on JVM (powered by Quarkus 1.5.1.Final) started in 1.125s. Listening on: <http://0.0.0.0:8080>
2020-06-13 00:03:06,416 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2020-06-13 00:03:06,416 INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy]

使用 curl 命令访问 REST 端点:

$ curl -w "\n" http://localhost:8080/hello
hello

恭喜!通过使用 Mavan 和 Quarkus,你很快从没有安装 Java 的环境里创建了第一个 web 应用。

接下来用 Java 做什么

Java 是一个成熟的编程语言,通过专门为 云原生 cloud native 应用程序开发设计的新框架,Java 的热度会一直持续下去。

如果你正走在这样构建未来应用的路上,你可能会对更多实用的 Quarkus 开发课程或其他现代化框架感兴趣。无论你在构建什么,下一步是配置你的文本编辑器。阅读我关于《在 VS Code 用 Quarkus 编写 Java》的教程,然后再看看你能做什么。


via: https://opensource.com/article/20/7/install-java-mac

作者:Daniel Oh 选题:lujun9972 译者:Yufei-Yan 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

如果你想了解 Linux 服务器在重压之下的运行情况,那么给 Linux 服务器施加压力是个不错的主意。在这篇文章中,我们将看一些工具,可以帮助你增加服务器压力并衡量结果。

为什么你会想给你的 Linux 系统施加压力呢?因为有时你可能想知道当一个系统由于大量运行的进程、繁重的网络流量、过多的内存使用等原因而承受很大的压力时,它的表现如何。这种压力测试可以帮助确保系统已经做好了 “上市” 的准备。

如果你需要预测应用程序可能需要多长时间才能做出反应,以及哪些(如果有的话)进程可能会在重负载下失败或运行缓慢,那么在前期进行压力测试是一个非常好的主意。

幸运的是,对于那些需要能够预测 Linux 系统在压力下的反应的人来说,你可以采用一些有用的技术和工具来使这个过程更容易。在这篇文章中,我们将研究其中的一些。

自己动手做个循环

第一种技术是在命令行上运行一些循环,观察它们对系统的影响。这种方式可以大大增加 CPU 的负荷。使用 uptime 或类似的命令可以很容易地看到结果。

在下面的命令中,我们启动了四个无尽循环。你可以通过添加数字或使用 bash 表达式,如 {1...6} 来代替 1 2 3 4 以增加循环次数:

for i in 1 2 3 4; do while : ; do : ; done & done

在命令行上输入后,将在后台启动四个无尽循环:

$ for i in 1 2 3 4; do while : ; do : ; done & done
[1] 205012
[2] 205013
[3] 205014
[4] 205015

在这种情况下,发起了作业 1-4,作业号和进程号会相应显示出来。

要观察对平均负载的影响,请使用如下所示的命令。在本例中,uptime 命令每 30 秒运行一次:

$ while true; do uptime; sleep 30; done

如果你打算定期运行这样的测试,你可以将循环命令放入脚本 watch-it 中。

#!/bin/bash

while true
do
  uptime
  sleep 30
done

在输出中,你可以看到平均负载是如何增加的,然后在循环结束后又开始下降。

 11:25:34 up 5 days, 17:27,  2 users,  load average: 0.15, 0.14, 0.08
 11:26:04 up 5 days, 17:27,  2 users,  load average: 0.09, 0.12, 0.08
 11:26:34 up 5 days, 17:28,  2 users,  load average: 1.42, 0.43, 0.18
 11:27:04 up 5 days, 17:28,  2 users,  load average: 2.50, 0.79, 0.31
 11:27:34 up 5 days, 17:29,  2 users,  load average: 3.09, 1.10, 0.43
 11:28:04 up 5 days, 17:29,  2 users,  load average: 3.45, 1.38, 0.54
 11:28:34 up 5 days, 17:30,  2 users,  load average: 3.67, 1.63, 0.66
 11:29:04 up 5 days, 17:30,  2 users,  load average: 3.80, 1.86, 0.76
 11:29:34 up 5 days, 17:31,  2 users,  load average: 3.88, 2.06, 0.87
 11:30:04 up 5 days, 17:31,  2 users,  load average: 3.93, 2.25, 0.97
 11:30:34 up 5 days, 17:32,  2 users,  load average: 3.64, 2.35, 1.04 <== 循环停止
 11:31:04 up 5 days, 17:32,  2 users,  load average: 2.20, 2.13, 1.01      11:31:34 up 5 days, 17:33,  2 users,  load average: 1.40, 1.94, 0.98

因为所显示的负载分别代表了 1、5 和 15 分钟的平均值,所以这些值需要一段时间才能恢复到系统接近正常的状态。

要停止循环,请发出像下面这样的 kill 命令 —— 假设作业号是 1-4,就像本篇文章前面显示的那样。如果你不确定,可以使用 jobs 命令来确认作业号。

$ kill %1 %2 %3 %4

增加压力的专用工具

另一种方法是使用专门为你制造系统压力的工具。其中一种叫做 stress(压力),可以以多种方式对系统进行压力测试。stress 工具是一个工作负载生成器,提供 CPU、内存和磁盘 I/O 压力测试。

在使用 --cpu 选项时,stress 命令使用平方根函数强制 CPU 努力工作。指定的 CPU 数量越多,负载上升的速度就越快。

下面第二个脚本(watch-it-2)可以用来衡量对系统内存使用的影响。请注意,它使用 free 命令来查看加压的效果。

$ cat watch-it-2
#!/bin/bash

while true
do
  free
  sleep 30
done

发起任务并观察压力:

$ stress --cpu 2

$ ./watch-it
 13:09:14 up 5 days, 19:10,  2 users,  load average: 0.00, 0.00, 0.00
 13:09:44 up 5 days, 19:11,  2 users,  load average: 0.68, 0.16, 0.05
 13:10:14 up 5 days, 19:11,  2 users,  load average: 1.20, 0.34, 0.12
 13:10:44 up 5 days, 19:12,  2 users,  load average: 1.52, 0.50, 0.18
 13:11:14 up 5 days, 19:12,  2 users,  load average: 1.71, 0.64, 0.24
 13:11:44 up 5 days, 19:13,  2 users,  load average: 1.83, 0.77, 0.30

在命令行中指定的 CPU 越多,负载就增加的越快。

$ stress --cpu 4
$ ./watch-it
 13:47:49 up 5 days, 19:49,  2 users,  load average: 0.00, 0.00, 0.00
 13:48:19 up 5 days, 19:49,  2 users,  load average: 1.58, 0.38, 0.13
 13:48:49 up 5 days, 19:50,  2 users,  load average: 2.61, 0.75, 0.26
 13:49:19 up 5 days, 19:50,  2 users,  load average: 3.16, 1.06, 0.38
 13:49:49 up 5 days, 19:51,  2 users,  load average: 3.49, 1.34, 0.50
 13:50:19 up 5 days, 19:51,  2 users,  load average: 3.69, 1.60, 0.61

stress 命令也可以通过 --io(输入/输出)和 --vm(内存)选项增加 I/O 和内存的负载来给系统施加压力。

在接下来的这个例子中,运行这个增加内存压力的命令,然后启动 watch-it-2 脚本。

$ stress --vm 2

$ watch-it-2
              total        used        free      shared  buff/cache   available
Mem:        6087064      662160     2519164        8868     2905740     5117548
Swap:       2097148           0     2097148
              total        used        free      shared  buff/cache   available
Mem:        6087064      803464     2377832        8864     2905768     4976248
Swap:       2097148           0     2097148
              total        used        free      shared  buff/cache   available
Mem:        6087064      968512     2212772        8864     2905780     4811200
Swap:       2097148           0     2097148

stress 的另一个选项是使用 --io 选项为系统添加输入/输出活动。在这种情况下,你可以使用这样的命令:

$ stress --io 4

然后你可以使用 iotop 观察受压的 I/O。注意,运行 iotop 需要 root 权限。

之前:

$ sudo iotop -o
Total DISK READ:         0.00 B/s | Total DISK WRITE:        19.36 K/s
Current DISK READ:       0.00 B/s | Current DISK WRITE:      27.10 K/s
    TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
 269308 be/4 root        0.00 B/s    0.00 B/s  0.00 %  1.24 % [kworker~fficient]
    283 be/3 root        0.00 B/s   19.36 K/s  0.00 %  0.26 % [jbd2/sda1-8]

之后:

Total DISK READ:         0.00 B/s | Total DISK WRITE:         0.00 B/s
Current DISK READ:       0.00 B/s | Current DISK WRITE:       0.00 B/s
    TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
 270983 be/4 shs         0.00 B/s    0.00 B/s  0.00 % 51.45 % stress --io 4
 270984 be/4 shs         0.00 B/s    0.00 B/s  0.00 % 51.36 % stress --io 4
 270985 be/4 shs         0.00 B/s    0.00 B/s  0.00 % 50.95 % stress --io 4
 270982 be/4 shs         0.00 B/s    0.00 B/s  0.00 % 50.80 % stress --io 4
 269308 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.09 % [kworker~fficient]

stress 只是给系统增加压力的若干工具之一。另一个较新的工具,stress-ng,将在以后的文章中介绍。

总结

用于系统压力测试的各种工具可以帮助你预测系统在真实世界的情况下如何响应,在这些情况下,它们受到增加的流量和计算需求。

虽然我们在文章中展示的是创建和测量各种类型的压力的方法,但最终的好处是压力如何帮助确定你的系统或应用程序对它的反应。


via: https://www.networkworld.com/article/3563334/how-to-stress-test-your-linux-system.html

作者:Sandra Henry-Stocker 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

重定向是一种十分高效的数据流动方式,它能帮你减少很多鼠标和键盘上的操作。

对于任何编程或脚本语言,输入与输出重定向都是很自然的功能。严格来说,当你使用电脑时,数据自然而然地在发生着重定向。从 stdin(标准输入,通常是你的键盘或者鼠标)读取输入,输入则发往 stdout(标准输出,一段文本或者数据流),最后错误信息送至 stderr。如果你使用 BashZsh 之类的 shell,那么理解这些数据流能够让你更好地控制信息流向。

标准输入、标准输出以及标准错误输出都存在于 Linux 文件系统中。你可以在 /dev 查看:

$ ls /dev/std*
/dev/stderr@  /dev/stdin@  /dev/stdout@

你可能没法直接使用它们,但将它们想象成你能传递数据的元位置,会很有帮助。

重定向的基础很简单:用一些 > 符号重定向输出,然后用另外一些 < 符号重定向输入。

重定向输出

ls 命令的输出写入一个文件:

$ ls > list.txt

你没法像平常那样看到 ls 的输出,因为它们并没有被发送到屏幕,而是被写入 list.txt 文件了,这个功能用处太多了,事实上,你甚至可以用它来将文件内容拷贝到另一个文件。不一定是文本文件,你也可以用将重定向用于二进制数据:

$ cat image.png > picture.png

(你可能会好奇为什么要这样做,有时候对于 文件权限信息 而间接有用。)

重定向输入

你也能将输入重定向“到”一个命令。可以说,它没有重定向输出那么有用,因为许多命令已经被硬编码,只从你的参数中接收输入。但是,如果某个命令需要一系列参数,而且你把这些参数写在文件里,想要快速“复制粘贴”到终端的时候(除非你并不想复制粘贴),它就帮得上忙了。

$ sudo dnf install $(<package.list)

重定向输入得常规用法是 嵌入文档 here-document (简写成 here-doc)和 嵌入字符串 here-string 技巧。这种输入方法将一整块文本重定向至标准输入流,直到碰见一个特殊的文件结束标记(许多人习惯用 EOF,实际上你可以使用任何字符串,只要它是唯一的)。试着把这些(在第二个 EOF 标记之前)敲进你的终端:

$ echo << EOF
> foo
> bar
> baz
> EOF

输出结果:

foo
bar
baz

使用 Bash 编写脚本的人常常用这个技巧,将数行文本一次性写入文件或者打印到屏幕上。只要你别忘了末尾的文件结束标记,这会是一个帮你避免大量繁琐 echoprintf 语句的好办法。

嵌入字符串类似于嵌入文档,但是它只含有一个字符串(或者用引号包裹的几个字符串,同样会被当成一个字符串)

$ cat <<< "foo bar baz"
foo bar baz

重定向错误信息

错误信息流叫做 stderr,通过 2> 实现这个目的。下面这个命令把错误信息定向到 output.log 文件:

$ ls /nope 2> output.log

将数据送往 /dev/null

既然标准输入、标准输出和错误输出都有自己的位置,那么“空空如也”也应该在 Linux 文件系统占有一席之地。没错,它叫做 null,位于 /dev,频繁使用的人懒得说 “slash dev slash null”,于是索性叫它 “devnull”。

通过重定向,你可以把数据发送到 /dev/null。比如,find 命令常常会输出很多具体信息,而且在搜索文件遇到权限冲突时,会事无巨细地报告:

$ find ~ -type f
/home/seth/actual.file
find: `/home/seth/foggy': Permission denied
find: `/home/seth/groggy': Permission denied
find: `/home/seth/soggy': Permission denied
/home/seth/zzz.file

find 命令把那些当作错误,所以你可以只把错误信息重定向至 /dev/null

$ find ~ -type f 2> /dev/null
/home/seth/actual.file
/home/seth/zzz.file

使用重定向

在 Bash 中,重定向是转移数据的有效方法。你可能不会频繁使用重定向,但是学会如何使用它,能帮你在打开文件、复制粘贴数据这类需要移动鼠标、大量按键操作上,节省很多不必要的时间。不要做如此浪费时间的事情。使用重定向,好好享受生活。


via: https://opensource.com/article/20/6/redirection-bash

作者:Seth Kenlon 选题:lujun9972 译者:nophDog 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

想细看网络图像并不总是那么简单,但是 Hover Zoom+ 让它像鼠标滑动一样容易。

 title=

你是否曾经在访问网站时希望查看更大的图像?我经常遇到这种情况,而要做到这点并不总是那么容易。

有时,我在源码中筛选,使用 Ctrl + F 搜索图像,复制图像源地址并将其粘贴到新窗口中,以便以全尺寸查看图像。或者,另一个选择是右键单击,复制图像地址,然后粘贴到新选项卡中。

 title=

Hover Zoom+ 让这个过程更加简单。Hover Zoom+ 是一个简单 Chrome 扩展程序,在 MIT 许可证下发布,可在 Chrome 商店中找到,它的源码可在 GitHub 上获得。它也适用于 Firefox。

这个应用使得该过程更加容易。只需将鼠标悬停在图像上,你将看到一个弹出窗口来显示该图像的全部内容,它会匹配你的浏览器窗口,无论图像是否被裁剪(或者图像尺寸适当,它看上去会是一样的)。这可能很有趣,因为有时可能会裁剪原始图像,以适应空间或聚焦于图像的特定部分。但是,你无法右键单击并直接从弹出窗口中保存图像。

根据加州圣何塞的开发人员 Oleg Anashkin 的说法,“这是原始 HoverZoom 扩展的开源版本,现已被恶意软件所占领,并被从商店中删除。在此版本中,所有间谍软件均已删除,许多 bug 已被修复,并添加了新功能。它默认不会收集任何统计信息。”

我在 Windows 10 笔记本上的 Chrome 中安装了此扩展,然后试用了一下。安装扩展后,我将鼠标悬停在图像上,它在弹出窗口中显示了比实际更大的图像。

但是,Hover Zoom+ 不适用于所有网站或所有图像。它适用于 Facebook 和 Twitter,但不适用于这些网站上的赞助内容。用户可以轻松切换该应用以针对特定站点启用或禁用它。使用 Hover Zoom+ 可以很容易地看到 Instagram 上的这只可爱小猫而无需实际阅读帖子(方便!):

 title=


via: https://opensource.com/article/20/6/hoverzoom

作者:Jeff Macharyas 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出