2020-05-22 03:58:49 +00:00
|
|
|
use crate::extensions::{Extension, ResolveInfo};
|
2020-06-13 14:14:47 +00:00
|
|
|
use crate::{Error, Variables};
|
2020-05-27 12:47:22 +00:00
|
|
|
use async_graphql_parser::query::{Definition, Document, OperationDefinition, Selection};
|
2020-05-22 03:58:49 +00:00
|
|
|
use itertools::Itertools;
|
2020-06-13 14:14:47 +00:00
|
|
|
use std::borrow::Cow;
|
2020-05-22 03:58:49 +00:00
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
|
|
/// Logger extension
|
2020-05-27 12:47:22 +00:00
|
|
|
pub struct Logger {
|
|
|
|
id: Uuid,
|
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 {
|
|
|
|
id: Uuid::new_v4(),
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_end(&mut self, document: &Document) {
|
2020-05-27 12:47:22 +00:00
|
|
|
let mut is_schema = false;
|
|
|
|
|
|
|
|
for definition in document.definitions() {
|
|
|
|
if let Definition::Operation(operation) = &definition.node {
|
|
|
|
let selection_set = match &operation.node {
|
|
|
|
OperationDefinition::Query(query) => &query.selection_set,
|
|
|
|
OperationDefinition::SelectionSet(selection_set) => &selection_set.node,
|
|
|
|
_ => continue,
|
|
|
|
};
|
|
|
|
is_schema = selection_set.items.iter().any(|selection| {
|
|
|
|
if let Selection::Field(field) = &selection.node {
|
|
|
|
if field.name.as_str() == "__schema" {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
});
|
|
|
|
if is_schema {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if is_schema {
|
2020-06-13 14:14:47 +00:00
|
|
|
self.enabled = false;
|
2020-05-27 12:47:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-13 14:14:47 +00:00
|
|
|
info!(target: "async-graphql", "[Query] id: \"{}\", query: \"{}\", variables: {}", self.id, &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-06-13 14:14:47 +00:00
|
|
|
trace!(target: "async-graphql", "[ResolveStart] id: \"{}\", path: \"{}\"", self.id, 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-06-13 14:14:47 +00:00
|
|
|
trace!(target: "async-graphql", "[ResolveEnd] id: \"{}\", path: \"{}\"", self.id, 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-06-13 14:14:47 +00:00
|
|
|
error!(target: "async-graphql", "[ParseError] id: \"{}\", pos: [{}:{}], query: \"{}\", variables: {}, {}", self.id, err.pos.line, err.pos.column, self.query, self.variables, err)
|
2020-05-22 03:58:49 +00:00
|
|
|
}
|
|
|
|
Error::Query { pos, path, err } => {
|
|
|
|
if let Some(path) = path {
|
2020-06-13 14:14:47 +00:00
|
|
|
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()
|
|
|
|
};
|
|
|
|
error!(target: "async-graphql", "[QueryError] id: \"{}\", path: \"{}\", pos: [{}:{}], query: \"{}\", variables: {}, {}", self.id, path, pos.line, pos.column, self.query, self.variables, err)
|
2020-05-22 03:58:49 +00:00
|
|
|
} else {
|
2020-06-13 14:14:47 +00:00
|
|
|
error!(target: "async-graphql", "[QueryError] id: \"{}\", pos: [{}:{}], query: \"{}\", variables: {}, {}", self.id, pos.line, pos.column, self.query, self.variables, err)
|
2020-05-22 03:58:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Error::Rule { errors } => {
|
|
|
|
for error in errors {
|
|
|
|
let locations = error
|
|
|
|
.locations
|
|
|
|
.iter()
|
|
|
|
.map(|pos| format!("{}:{}", pos.line, pos.column))
|
|
|
|
.join(", ");
|
2020-06-13 14:14:47 +00:00
|
|
|
error!(target: "async-graphql", "[ValidationError] id: \"{}\", pos: [{}], query: \"{}\", variables: {}, {}", self.id, locations, self.query, self.variables, error.message)
|
2020-05-22 03:58:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|