mirror of
https://github.com/LukeMathWalker/zero-to-production.git
synced 2024-12-18 14:06:37 +00:00
Chapter04 (#9)
* Add chapter 4 code. * Add logger middleware. * Add env_logger. * Instrumented. * Test logs. * Introduce instrument. * Refactor handler. * Use TracingLogger. * Update. * Fix linter error.
This commit is contained in:
parent
3e01540d57
commit
3e553eaf60
16 changed files with 644 additions and 4 deletions
223
Cargo.lock
generated
223
Cargo.lock
generated
|
@ -271,6 +271,14 @@ dependencies = [
|
|||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.32"
|
||||
|
@ -304,6 +312,16 @@ dependencies = [
|
|||
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
|
@ -449,6 +467,31 @@ dependencies = [
|
|||
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chapter04"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix-rt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"actix-web 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"anyhow 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"config 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.10.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sqlx 0.4.0-beta.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-actix-web 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-bunyan-formatter 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-futures 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-log 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-subscriber 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.15"
|
||||
|
@ -608,6 +651,18 @@ dependencies = [
|
|||
"syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
|
@ -774,6 +829,15 @@ dependencies = [
|
|||
"version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
|
@ -880,6 +944,14 @@ name = "httparse"
|
|||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.13.7"
|
||||
|
@ -1051,6 +1123,14 @@ name = "match_cfg"
|
|||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
|
@ -1396,6 +1476,15 @@ dependencies = [
|
|||
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.18"
|
||||
|
@ -1566,6 +1655,14 @@ dependencies = [
|
|||
"opaque-debug 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.2.1"
|
||||
|
@ -1741,6 +1838,14 @@ dependencies = [
|
|||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.20"
|
||||
|
@ -1877,17 +1982,104 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-core 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-attributes 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-actix-web"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"actix-web 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-futures 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-bunyan-formatter"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"chrono 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gethostname 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-log 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-subscriber 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.15"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-futures"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"pin-project 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-serde"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matchers 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sharded-slab 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-log 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tracing-serde 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trust-dns-proto"
|
||||
version = "0.18.0-alpha.2"
|
||||
|
@ -2116,6 +2308,14 @@ name = "winapi-i686-pc-windows-gnu"
|
|||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
@ -2173,11 +2373,13 @@ dependencies = [
|
|||
"checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
||||
"checksum ahash 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
|
||||
"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
|
||||
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
"checksum anyhow 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
|
||||
"checksum arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034"
|
||||
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
"checksum async-trait 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6e1a4a2f97ce50c9d0282c1468816208588441492b40d813b2e0419c22c05e7f"
|
||||
"checksum atoi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e0afb7287b68575f5ca0e5c7e40191cbd4be59d325781f46faa603e176eaef47"
|
||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
"checksum awc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7601d4d1d7ef2335d6597a41b5fe069f6ab799b85f53565ab390e7b7065aac5"
|
||||
"checksum backtrace 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)" = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
|
||||
|
@ -2214,6 +2416,7 @@ dependencies = [
|
|||
"checksum either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f"
|
||||
"checksum encoding_rs 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "e8ac63f94732332f44fe654443c46f6375d1939684c17b0afb6cb56b0456e171"
|
||||
"checksum enum-as-inner 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595"
|
||||
"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
"checksum failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
|
||||
"checksum failure_derive 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
"checksum flate2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94"
|
||||
|
@ -2233,6 +2436,7 @@ dependencies = [
|
|||
"checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6"
|
||||
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||
"checksum generic-array 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
|
||||
"checksum gethostname 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e692e296bfac1d2533ef168d0b60ff5897b8b70a4009276834014dd8924cc028"
|
||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
"checksum gimli 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
|
||||
"checksum h2 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "993f9e0baeed60001cf565546b0d3dbe6a6ad23f2bd31644a133c641eccf6d53"
|
||||
|
@ -2245,6 +2449,7 @@ dependencies = [
|
|||
"checksum http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9"
|
||||
"checksum http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
|
||||
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
|
||||
"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
||||
"checksum hyper 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3e68a8dd9716185d9e64ea473ea6ef63529252e3e27623295a0378a19665d5eb"
|
||||
"checksum hyper-tls 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed"
|
||||
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
|
||||
|
@ -2266,6 +2471,7 @@ dependencies = [
|
|||
"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
|
||||
"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||
"checksum match_cfg 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||
"checksum matchers 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
|
||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
"checksum md-5 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15"
|
||||
|
@ -2308,6 +2514,7 @@ dependencies = [
|
|||
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
"checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
|
||||
"checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
|
||||
"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
||||
"checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
"checksum reqwest 0.10.7 (registry+https://github.com/rust-lang/crates.io-index)" = "12427a5577082c24419c9c417db35cfeb65962efc7675bb6b0d5f1f9d315bfe6"
|
||||
|
@ -2325,6 +2532,7 @@ dependencies = [
|
|||
"checksum sha-1 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "170a36ea86c864a3f16dd2687712dd6646f7019f301e57537c7f4dc9f5916770"
|
||||
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||
"checksum sha2 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1"
|
||||
"checksum sharded-slab 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "06d5a3f5166fb5b42a5439f2eee8b9de149e235961e3eb21c5808fc3ea17ff3e"
|
||||
"checksum signal-hook-registry 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum smallvec 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
|
||||
|
@ -2340,6 +2548,7 @@ dependencies = [
|
|||
"checksum syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9"
|
||||
"checksum synstructure 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
|
||||
"checksum thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
|
||||
"checksum thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
|
||||
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||
|
@ -2354,7 +2563,14 @@ dependencies = [
|
|||
"checksum tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
|
||||
"checksum tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860"
|
||||
"checksum tracing 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c"
|
||||
"checksum tracing-core 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5"
|
||||
"checksum tracing-actix-web 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d9e2e3bdcd192ec7786b47addd10f66fbc7c06d32f1757ddaa31e28eec045aea"
|
||||
"checksum tracing-attributes 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada"
|
||||
"checksum tracing-bunyan-formatter 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8d8dfd28e9ee6d79937f139ae4f112fa2172018cfdf111c0dac1f3f8c6912053"
|
||||
"checksum tracing-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5bcf46c1f1f06aeea2d6b81f3c863d0930a596c86ad1920d4e5bad6dd1d7119a"
|
||||
"checksum tracing-futures 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c"
|
||||
"checksum tracing-log 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e0f8c7178e13481ff6765bd169b33e8d554c5d2bbede5e32c356194be02b9b9"
|
||||
"checksum tracing-serde 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
|
||||
"checksum tracing-subscriber 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "82bb5079aa76438620837198db8a5c529fb9878c730bc2b28179b0241cf04c10"
|
||||
"checksum trust-dns-proto 0.18.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2a7f3a2ab8a919f5eca52a468866a67ed7d3efa265d48a652a9a3452272b413f"
|
||||
"checksum trust-dns-resolver 0.18.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6f90b1502b226f8b2514c6d5b37bafa8c200d7ca4102d57dc36ee0f3b7a04a2f"
|
||||
"checksum try-lock 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||
|
@ -2383,6 +2599,7 @@ dependencies = [
|
|||
"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
|
||||
"checksum winreg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[workspace]
|
||||
members = ["chapter03-0", "chapter03-1"]
|
||||
members = ["chapter03-0", "chapter03-1", "chapter04"]
|
||||
|
|
1
chapter04/.env
Normal file
1
chapter04/.env
Normal file
|
@ -0,0 +1 @@
|
|||
DATABASE_URL="postgres://postgres:password@localhost:5432/newsletter"
|
36
chapter04/Cargo.toml
Normal file
36
chapter04/Cargo.toml
Normal file
|
@ -0,0 +1,36 @@
|
|||
[package]
|
||||
name = "chapter04"
|
||||
version = "0.1.0"
|
||||
authors = ["LukeMathWalker <rust@lpalmieri.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
path = "src/main.rs"
|
||||
name = "chapter04"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "2.0.0"
|
||||
actix-rt = "1.1.1"
|
||||
tokio = "0.2.22"
|
||||
serde = "1.0.115"
|
||||
config = { version = "0.10.1", default-features = false, features = ["yaml"] }
|
||||
sqlx = { version = "0.4.0-beta.1", default-features = false, features = [ "runtime-tokio", "macros", "postgres", "uuid", "chrono", "migrate"] }
|
||||
anyhow = "1.0.32"
|
||||
uuid = { version = "0.8.1", features = ["v4"] }
|
||||
chrono = "0.4.15"
|
||||
env_logger = "0.7.1"
|
||||
log = "0.4.11"
|
||||
tracing = "0.1.19"
|
||||
tracing-futures = "0.2.4"
|
||||
tracing-subscriber = { version = "0.2.12", features = ["registry", "env-filter"] }
|
||||
tracing-bunyan-formatter = "0.1.6"
|
||||
tracing-log = "0.1.1"
|
||||
tracing-actix-web = "0.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
reqwest = { version = "0.10.7", features = ["json"] }
|
||||
lazy_static = "1.4.0"
|
7
chapter04/configuration.yaml
Normal file
7
chapter04/configuration.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
application_port: 8000
|
||||
database:
|
||||
host: "localhost"
|
||||
port: 5432
|
||||
username: "postgres"
|
||||
password: "password"
|
||||
database_name: "newsletter"
|
|
@ -0,0 +1,8 @@
|
|||
-- Create Subscriptions Table
|
||||
CREATE TABLE subscriptions(
|
||||
id uuid NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
subscribed_at timestamptz NOT NULL
|
||||
);
|
40
chapter04/scripts/init_db.sh
Executable file
40
chapter04/scripts/init_db.sh
Executable file
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -eo pipefail
|
||||
|
||||
# Check if a custom user has been set, otherwise default to 'postgres'
|
||||
DB_USER=${POSTGRES_USER:=postgres}
|
||||
# Check if a custom password has been set, otherwise default to 'password'
|
||||
DB_PASSWORD="${POSTGRES_PASSWORD:=password}"
|
||||
# Check if a custom password has been set, otherwise default to 'newsletter'
|
||||
DB_NAME="${POSTGRES_DB:=newsletter}"
|
||||
# Check if a custom port has been set, otherwise default to '5432'
|
||||
DB_PORT="${POSTGRES_PORT:=5432}"
|
||||
|
||||
# Allow to skip Docker if a dockerized Postgres database is already running
|
||||
if [[ -z "${SKIP_DOCKER}" ]]
|
||||
then
|
||||
# Launch postgres using Docker
|
||||
docker run \
|
||||
-e POSTGRES_USER=${DB_USER} \
|
||||
-e POSTGRES_PASSWORD=${DB_PASSWORD} \
|
||||
-e POSTGRES_DB=${DB_NAME} \
|
||||
-p "${DB_PORT}":5432 \
|
||||
-d postgres \
|
||||
postgres -N 1000
|
||||
# ^ Increased maximum number of connections for testing purposes
|
||||
fi
|
||||
|
||||
# Keep pinging Postgres until it's ready to accept commands
|
||||
until PGPASSWORD="${DB_PASSWORD}" psql -h "localhost" -U "${DB_USER}" -p "${DB_PORT}" -d "postgres" -c '\q'; do
|
||||
>&2 echo "Postgres is still unavailable - sleeping"
|
||||
sleep 1
|
||||
done
|
||||
|
||||
>&2 echo "Postgres is up and running on port ${DB_PORT} - running migrations now!"
|
||||
|
||||
export DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@localhost:${DB_PORT}/${DB_NAME}
|
||||
sqlx database create
|
||||
sqlx migrate run
|
||||
|
||||
>&2 echo "Postgres has been migrated, ready to go!"
|
38
chapter04/src/configuration.rs
Normal file
38
chapter04/src/configuration.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
#[derive(serde::Deserialize)]
|
||||
pub struct Settings {
|
||||
pub database: DatabaseSettings,
|
||||
pub application_port: u16,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct DatabaseSettings {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub port: u16,
|
||||
pub host: String,
|
||||
pub database_name: String,
|
||||
}
|
||||
|
||||
impl DatabaseSettings {
|
||||
pub fn connection_string(&self) -> String {
|
||||
format!(
|
||||
"postgres://{}:{}@{}:{}/{}",
|
||||
self.username, self.password, self.host, self.port, self.database_name
|
||||
)
|
||||
}
|
||||
|
||||
pub fn connection_string_without_db(&self) -> String {
|
||||
format!(
|
||||
"postgres://{}:{}@{}:{}",
|
||||
self.username, self.password, self.host, self.port
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_configuration() -> Result<Settings, config::ConfigError> {
|
||||
let mut settings = config::Config::default();
|
||||
|
||||
settings.merge(config::File::with_name("configuration"))?;
|
||||
|
||||
settings.try_into()
|
||||
}
|
5
chapter04/src/lib.rs
Normal file
5
chapter04/src/lib.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
#![allow(clippy::toplevel_ref_arg)]
|
||||
pub mod configuration;
|
||||
pub mod routes;
|
||||
pub mod startup;
|
||||
pub mod telemetry;
|
29
chapter04/src/main.rs
Normal file
29
chapter04/src/main.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use anyhow::Context;
|
||||
use chapter04::configuration::get_configuration;
|
||||
use chapter04::startup::run;
|
||||
use chapter04::telemetry::{get_subscriber, init_subscriber};
|
||||
use sqlx::postgres::PgPool;
|
||||
use std::net::TcpListener;
|
||||
|
||||
#[actix_rt::main]
|
||||
async fn main() -> Result<(), anyhow::Error> {
|
||||
let subscriber = get_subscriber("zero2prod".into(), "info".into());
|
||||
init_subscriber(subscriber);
|
||||
|
||||
let configuration = get_configuration().expect("Failed to read configuration.");
|
||||
let connection_pool = PgPool::connect(&configuration.database.connection_string())
|
||||
.await
|
||||
.map_err(anyhow::Error::from)
|
||||
.with_context(|| "Failed to connect to Postgres.")?;
|
||||
|
||||
// Here we choose to bind explicitly to localhost, 127.0.0.1, for security
|
||||
// reasons. This binding may cause issues in some environments. For example,
|
||||
// it causes connectivity issues running in WSL2, where you cannot reach the
|
||||
// server when it is bound to WSL2's localhost interface. As a workaround,
|
||||
// you can choose to bind to all interfaces, 0.0.0.0, instead, but be aware
|
||||
// of the security implications when you expose the server on all interfaces.
|
||||
let address = format!("127.0.0.1:{}", configuration.application_port);
|
||||
let listener = TcpListener::bind(address)?;
|
||||
run(listener, connection_pool)?.await?;
|
||||
Ok(())
|
||||
}
|
5
chapter04/src/routes/health_check.rs
Normal file
5
chapter04/src/routes/health_check.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
use actix_web::HttpResponse;
|
||||
|
||||
pub async fn health_check() -> HttpResponse {
|
||||
HttpResponse::Ok().finish()
|
||||
}
|
5
chapter04/src/routes/mod.rs
Normal file
5
chapter04/src/routes/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod health_check;
|
||||
mod subscriptions;
|
||||
|
||||
pub use health_check::*;
|
||||
pub use subscriptions::*;
|
56
chapter04/src/routes/subscriptions.rs
Normal file
56
chapter04/src/routes/subscriptions.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use actix_web::{web, HttpResponse};
|
||||
use chrono::Utc;
|
||||
use sqlx::PgPool;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct SubscribeRequest {
|
||||
email: String,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "Adding a new subscriber",
|
||||
skip(payload, pool),
|
||||
fields(
|
||||
request_id=%Uuid::new_v4(),
|
||||
email = %payload.email,
|
||||
name = %payload.name
|
||||
)
|
||||
)]
|
||||
pub async fn subscribe(
|
||||
payload: web::Form<SubscribeRequest>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> Result<HttpResponse, HttpResponse> {
|
||||
insert_subscriber(&pool, &payload)
|
||||
.await
|
||||
.map_err(|_| HttpResponse::InternalServerError().finish())?;
|
||||
Ok(HttpResponse::Ok().finish())
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "Saving new subscriber details in the database",
|
||||
skip(payload, pool)
|
||||
)]
|
||||
pub async fn insert_subscriber(
|
||||
pool: &PgPool,
|
||||
payload: &SubscribeRequest,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO subscriptions (id, email, name, subscribed_at)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
"#,
|
||||
Uuid::new_v4(),
|
||||
payload.email,
|
||||
payload.name,
|
||||
Utc::now()
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Failed to execute query: {:?}", e);
|
||||
e
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
21
chapter04/src/startup.rs
Normal file
21
chapter04/src/startup.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use crate::routes::{health_check, subscribe};
|
||||
use actix_web::dev::Server;
|
||||
use actix_web::web::Data;
|
||||
use actix_web::{web, App, HttpServer};
|
||||
use sqlx::PgPool;
|
||||
use std::net::TcpListener;
|
||||
use tracing_actix_web::TracingLogger;
|
||||
|
||||
pub fn run(listener: TcpListener, db_pool: PgPool) -> Result<Server, std::io::Error> {
|
||||
let db_pool = Data::new(db_pool);
|
||||
let server = HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(TracingLogger)
|
||||
.route("/health_check", web::get().to(health_check))
|
||||
.route("/subscriptions", web::post().to(subscribe))
|
||||
.app_data(db_pool.clone())
|
||||
})
|
||||
.listen(listener)?
|
||||
.run();
|
||||
Ok(server)
|
||||
}
|
29
chapter04/src/telemetry.rs
Normal file
29
chapter04/src/telemetry.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use tracing::subscriber::set_global_default;
|
||||
use tracing::Subscriber;
|
||||
use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
|
||||
use tracing_log::LogTracer;
|
||||
use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
|
||||
|
||||
/// Compose multiple layers into a `tracing`'s subscriber.
|
||||
///
|
||||
/// # Implementation Notes
|
||||
///
|
||||
/// We are using `impl Subscriber` as return type to avoid having to spell out the actual
|
||||
/// type of the returned subscriber, which is indeed quite complex.
|
||||
pub fn get_subscriber(name: String, env_filter: String) -> impl Subscriber + Sync + Send {
|
||||
let env_filter =
|
||||
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(env_filter));
|
||||
let formatting_layer = BunyanFormattingLayer::new(name, std::io::stdout);
|
||||
Registry::default()
|
||||
.with(env_filter)
|
||||
.with(JsonStorageLayer)
|
||||
.with(formatting_layer)
|
||||
}
|
||||
|
||||
/// Register a subscriber as global default to process span data.
|
||||
///
|
||||
/// It should only be called once!
|
||||
pub fn init_subscriber(subscriber: impl Subscriber + Sync + Send) {
|
||||
LogTracer::init().expect("Failed to set logger");
|
||||
set_global_default(subscriber).expect("Failed to set subscriber");
|
||||
}
|
143
chapter04/tests/health_check.rs
Normal file
143
chapter04/tests/health_check.rs
Normal file
|
@ -0,0 +1,143 @@
|
|||
use chapter04::configuration::{get_configuration, DatabaseSettings};
|
||||
use chapter04::startup::run;
|
||||
use chapter04::telemetry::{get_subscriber, init_subscriber};
|
||||
use sqlx::{Connection, Executor, PgConnection, PgPool};
|
||||
use std::net::TcpListener;
|
||||
use uuid::Uuid;
|
||||
|
||||
// Ensure that the `tracing` stack is only initialised once using `lazy_static`
|
||||
lazy_static::lazy_static! {
|
||||
static ref TRACING: () = {
|
||||
let filter = if std::env::var("TEST_LOG").is_ok() { "debug" } else { "" };
|
||||
let subscriber = get_subscriber("test".into(), filter.into());
|
||||
init_subscriber(subscriber);
|
||||
};
|
||||
}
|
||||
|
||||
pub struct TestApp {
|
||||
pub address: String,
|
||||
pub db_pool: PgPool,
|
||||
}
|
||||
|
||||
async fn spawn_app() -> TestApp {
|
||||
// The first time `initialize` is invoked the code in `TRACING` is executed.
|
||||
// All other invocations will instead skip execution.
|
||||
lazy_static::initialize(&TRACING);
|
||||
|
||||
let listener = TcpListener::bind("127.0.0.1:0").expect("Failed to bind random port");
|
||||
// We retrieve the port assigned to us by the OS
|
||||
let port = listener.local_addr().unwrap().port();
|
||||
let address = format!("http://127.0.0.1:{}", port);
|
||||
|
||||
let mut configuration = get_configuration().expect("Failed to read configuration.");
|
||||
configuration.database.database_name = Uuid::new_v4().to_string();
|
||||
let connection_pool = configure_database(&configuration.database).await;
|
||||
|
||||
let server = run(listener, connection_pool.clone()).expect("Failed to bind address");
|
||||
let _ = tokio::spawn(server);
|
||||
TestApp {
|
||||
address,
|
||||
db_pool: connection_pool,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn configure_database(config: &DatabaseSettings) -> PgPool {
|
||||
// Create database
|
||||
let mut connection = PgConnection::connect(&config.connection_string_without_db())
|
||||
.await
|
||||
.expect("Failed to connect to Postgres");
|
||||
connection
|
||||
.execute(&*format!(r#"CREATE DATABASE "{}";"#, config.database_name))
|
||||
.await
|
||||
.expect("Failed to create database.");
|
||||
|
||||
// Migrate database
|
||||
let connection_pool = PgPool::connect(&config.connection_string())
|
||||
.await
|
||||
.expect("Failed to connect to Postgres.");
|
||||
sqlx::migrate!("./migrations")
|
||||
.run(&connection_pool)
|
||||
.await
|
||||
.expect("Failed to migrate the database");
|
||||
|
||||
connection_pool
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn health_check_works() {
|
||||
// Arrange
|
||||
let app = spawn_app().await;
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
// Act
|
||||
let response = client
|
||||
// Use the returned application address
|
||||
.get(&format!("{}/health_check", &app.address))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request.");
|
||||
|
||||
// Assert
|
||||
assert!(response.status().is_success());
|
||||
assert_eq!(Some(0), response.content_length());
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn subscribe_returns_a_200_for_valid_form_data() {
|
||||
// Arrange
|
||||
let app = spawn_app().await;
|
||||
let client = reqwest::Client::new();
|
||||
let body = "name=le%20guin&email=ursula_le_guin%40gmail.com";
|
||||
|
||||
// Act
|
||||
let response = client
|
||||
.post(&format!("{}/subscriptions", &app.address))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.body(body)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request.");
|
||||
|
||||
// Assert
|
||||
assert_eq!(200, response.status().as_u16());
|
||||
|
||||
let saved = sqlx::query!("SELECT email, name FROM subscriptions",)
|
||||
.fetch_one(&app.db_pool)
|
||||
.await
|
||||
.expect("Failed to fetch saved subscription.");
|
||||
|
||||
assert_eq!(saved.email, "ursula_le_guin@gmail.com");
|
||||
assert_eq!(saved.name, "le guin");
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn subscribe_returns_a_400_when_data_is_missing() {
|
||||
// Arrange
|
||||
let app = spawn_app().await;
|
||||
let client = reqwest::Client::new();
|
||||
let test_cases = vec![
|
||||
("name=le%20guin", "missing the email"),
|
||||
("email=ursula_le_guin%40gmail.com", "missing the name"),
|
||||
("", "missing both name and email"),
|
||||
];
|
||||
|
||||
for (invalid_body, error_message) in test_cases {
|
||||
// Act
|
||||
let response = client
|
||||
.post(&format!("{}/subscriptions", &app.address))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.body(invalid_body)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request.");
|
||||
|
||||
// Assert
|
||||
assert_eq!(
|
||||
400,
|
||||
response.status().as_u16(),
|
||||
// Additional customised error message on test failure
|
||||
"The API did not fail with 400 Bad Request when the payload was {}.",
|
||||
error_message
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue