2020-05-22 03:58:49 +00:00
|
|
|
use crate::extensions::{Extension, ResolveInfo};
|
2020-09-22 18:59:48 +00:00
|
|
|
use crate::parser::types::{ExecutableDocument, OperationType, Selection};
|
2020-06-13 14:14:47 +00:00
|
|
|
use crate::{Error, Variables};
|
2020-07-24 08:55:46 +00:00
|
|
|
use itertools::Itertools;
|
2020-08-31 18:18:02 +00:00
|
|
|
use log::{error, info, trace};
|
2020-07-24 08:55:46 +00:00
|
|
|
use std::borrow::Cow;
|
2020-05-22 03:58:49 +00:00
|
|
|
|
|
|
|
/// Logger extension
|
2020-09-15 18:32:13 +00:00
|
|
|
#[cfg_attr(feature = "nightly", doc(cfg(feature = "log")))]
|
2020-05-27 12:47:22 +00:00
|
|
|
pub struct Logger {
|
2020-06-13 14:14:47 +00:00
|
|
|
enabled: bool,
|
|
|
|
query: String,
|
|
|
|
variables: Variables,
|
2020-05-27 12:47:22 +00:00
|
|
|
}
|
2020-05-22 03:58:49 +00:00
|
|
|
|
|
|
|
impl Default for Logger {
|
|
|
|
fn default() -> Self {
|
2020-05-27 12:47:22 +00:00
|
|
|
Self {
|
2020-06-13 14:14:47 +00:00
|
|
|
enabled: true,
|
|
|
|
query: String::new(),
|
|
|
|
variables: Default::default(),
|
2020-05-27 12:47:22 +00:00
|
|
|
}
|
2020-05-22 03:58:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Extension for Logger {
|
2020-06-13 14:14:47 +00:00
|
|
|
fn parse_start(&mut self, query_source: &str, variables: &Variables) {
|
|
|
|
self.query = query_source.replace(char::is_whitespace, "");
|
|
|
|
self.variables = variables.clone();
|
|
|
|
}
|
|
|
|
|
2020-09-08 08:21:27 +00:00
|
|
|
fn parse_end(&mut self, document: &ExecutableDocument) {
|
2020-09-06 05:38:31 +00:00
|
|
|
let is_schema = document
|
2020-09-22 18:59:48 +00:00
|
|
|
.operations
|
2020-09-06 05:38:31 +00:00
|
|
|
.iter()
|
2020-09-22 18:59:48 +00:00
|
|
|
.filter(|(_, operation)| operation.node.ty == OperationType::Query)
|
|
|
|
.any(|(_, operation)| operation.node.selection_set.node.items.iter().any(|selection| matches!(&selection.node, Selection::Field(field) if field.node.name.node == "__schema")));
|
2020-05-27 12:47:22 +00:00
|
|
|
|
|
|
|
if is_schema {
|
2020-06-13 14:14:47 +00:00
|
|
|
self.enabled = false;
|
2020-05-27 12:47:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-25 07:40:04 +00:00
|
|
|
info!(target: "async-graphql", "[Query] query: \"{}\", variables: {}", &self.query, self.variables);
|
2020-05-22 03:58:49 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 14:14:47 +00:00
|
|
|
fn resolve_start(&mut self, info: &ResolveInfo<'_>) {
|
|
|
|
if !self.enabled {
|
2020-05-27 12:47:22 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-09-25 07:40:04 +00:00
|
|
|
trace!(target: "async-graphql", "[ResolveStart] path: \"{}\"", info.path_node);
|
2020-05-22 03:58:49 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 14:14:47 +00:00
|
|
|
fn resolve_end(&mut self, info: &ResolveInfo<'_>) {
|
|
|
|
if !self.enabled {
|
2020-05-27 12:47:22 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-09-25 07:40:04 +00:00
|
|
|
trace!(target: "async-graphql", "[ResolveEnd] path: \"{}\"", info.path_node);
|
2020-05-22 03:58:49 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 14:14:47 +00:00
|
|
|
fn error(&mut self, err: &Error) {
|
2020-05-22 03:58:49 +00:00
|
|
|
match err {
|
|
|
|
Error::Parse(err) => {
|
2020-09-22 18:59:48 +00:00
|
|
|
error!(
|
2020-09-25 07:40:04 +00:00
|
|
|
target: "async-graphql", "[ParseError] {}query: \"{}\", variables: {}, {}",
|
2020-09-22 18:59:48 +00:00
|
|
|
if let Some(pos) = err.positions().next() {
|
|
|
|
// TODO: Make this more efficient
|
|
|
|
format!("pos: [{}:{}], ", pos.line, pos.column)
|
|
|
|
} else {
|
|
|
|
String::new()
|
|
|
|
},
|
|
|
|
self.query,
|
|
|
|
self.variables,
|
|
|
|
err
|
|
|
|
)
|
2020-05-22 03:58:49 +00:00
|
|
|
}
|
|
|
|
Error::Query { pos, path, err } => {
|
2020-07-24 08:55:46 +00:00
|
|
|
if let Some(path) = path {
|
|
|
|
let path = if let serde_json::Value::Array(values) = path {
|
|
|
|
values
|
|
|
|
.iter()
|
|
|
|
.filter_map(|value| match value {
|
|
|
|
serde_json::Value::String(s) => Some(Cow::Borrowed(s.as_str())),
|
|
|
|
serde_json::Value::Number(n) => Some(Cow::Owned(n.to_string())),
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
.join(".")
|
|
|
|
} else {
|
|
|
|
String::new()
|
|
|
|
};
|
2020-09-25 07:40:04 +00:00
|
|
|
error!(target: "async-graphql", "[QueryError] path: \"{}\", pos: [{}:{}], query: \"{}\", variables: {}, {}", path, pos.line, pos.column, self.query, self.variables, err)
|
2020-07-24 08:55:46 +00:00
|
|
|
} else {
|
2020-09-25 07:40:04 +00:00
|
|
|
error!(target: "async-graphql", "[QueryError] pos: [{}:{}], query: \"{}\", variables: {}, {}", pos.line, pos.column, self.query, self.variables, err)
|
2020-07-24 08:55:46 +00:00
|
|
|
}
|
2020-05-22 03:58:49 +00:00
|
|
|
}
|
|
|
|
Error::Rule { errors } => {
|
2020-09-26 04:35:28 +00:00
|
|
|
for error in errors.iter() {
|
2020-07-24 08:55:46 +00:00
|
|
|
let locations = error
|
|
|
|
.locations
|
|
|
|
.iter()
|
|
|
|
.map(|pos| format!("{}:{}", pos.line, pos.column))
|
|
|
|
.join(", ");
|
2020-09-25 07:40:04 +00:00
|
|
|
error!(target: "async-graphql", "[ValidationError] pos: [{}], query: \"{}\", variables: {}, {}", locations, self.query, self.variables, error.message)
|
2020-05-22 03:58:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|