Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
07b76c54
Commit
07b76c54
authored
Mar 23, 2021
by
Mehmet Emin INAC
Committed by
Alex Kalderimis
Mar 23, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Log all GraphQL operation names
Changes the log analyzer to log all operation names in multiplex queries.
parent
25903c13
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
66 additions
and
34 deletions
+66
-34
app/controllers/graphql_controller.rb
app/controllers/graphql_controller.rb
+2
-3
lib/gitlab/graphql/query_analyzers/logger_analyzer.rb
lib/gitlab/graphql/query_analyzers/logger_analyzer.rb
+5
-2
spec/controllers/graphql_controller_spec.rb
spec/controllers/graphql_controller_spec.rb
+27
-5
spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
...ib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
+25
-22
spec/requests/api/graphql/gitlab_schema_spec.rb
spec/requests/api/graphql/gitlab_schema_spec.rb
+1
-0
spec/requests/api/graphql_spec.rb
spec/requests/api/graphql_spec.rb
+1
-0
spec/support/helpers/graphql_helpers.rb
spec/support/helpers/graphql_helpers.rb
+5
-2
No files found.
app/controllers/graphql_controller.rb
View file @
07b76c54
...
...
@@ -146,8 +146,7 @@ class GraphqlController < ApplicationController
end
def
logs
RequestStore
.
store
[
:graphql_logs
].
to_h
.
except
(
:duration_s
,
:query_string
)
.
merge
(
operation_name:
params
[
:operationName
])
RequestStore
.
store
[
:graphql_logs
].
to_a
.
map
{
|
log
|
log
.
except
(
:duration_s
,
:query_string
)
}
end
end
lib/gitlab/graphql/query_analyzers/logger_analyzer.rb
View file @
07b76c54
...
...
@@ -12,6 +12,7 @@ module Gitlab
def
initial_value
(
query
)
variables
=
process_variables
(
query
.
provided_variables
)
default_initial_values
(
query
).
merge
({
operation_name:
query
.
operation_name
,
query_string:
query
.
query_string
,
variables:
variables
})
...
...
@@ -20,8 +21,8 @@ module Gitlab
default_initial_values
(
query
)
end
def
call
(
memo
,
visit_type
,
irep_node
)
RequestStore
.
store
[
:graphql_logs
]
=
memo
def
call
(
memo
,
*
)
memo
end
def
final_value
(
memo
)
...
...
@@ -37,6 +38,8 @@ module Gitlab
memo
[
:used_fields
]
=
field_usages
.
first
memo
[
:used_deprecated_fields
]
=
field_usages
.
second
RequestStore
.
store
[
:graphql_logs
]
||=
[]
RequestStore
.
store
[
:graphql_logs
]
<<
memo
GraphqlLogger
.
info
(
memo
.
except!
(
:time_started
,
:query
))
rescue
=>
e
Gitlab
::
ErrorTracking
.
track_and_raise_for_dev_exception
(
e
)
...
...
spec/controllers/graphql_controller_spec.rb
View file @
07b76c54
...
...
@@ -175,22 +175,44 @@ RSpec.describe GraphqlController do
end
describe
'#append_info_to_payload'
do
let
(
:graphql_query
)
{
graphql_query_for
(
'project'
,
{
'fullPath'
=>
'foo'
},
%w(id name)
)
}
let
(
:mock_store
)
{
{
graphql_logs:
{
foo: :bar
}
}
}
let
(
:query_1
)
{
{
query:
graphql_query_for
(
'project'
,
{
'fullPath'
=>
'foo'
},
%w(id name)
,
'getProject_1'
)
}
}
let
(
:query_2
)
{
{
query:
graphql_query_for
(
'project'
,
{
'fullPath'
=>
'bar'
},
%w(id)
,
'getProject_2'
)
}
}
let
(
:graphql_queries
)
{
[
query_1
,
query_2
]
}
let
(
:log_payload
)
{
{}
}
let
(
:expected_logs
)
do
[
{
operation_name:
'getProject_1'
,
complexity:
3
,
depth:
2
,
used_deprecated_fields:
[],
used_fields:
[
'Project.id'
,
'Project.name'
,
'Query.project'
],
variables:
'{}'
},
{
operation_name:
'getProject_2'
,
complexity:
2
,
depth:
2
,
used_deprecated_fields:
[],
used_fields:
[
'Project.id'
,
'Query.project'
],
variables:
'{}'
}
]
end
before
do
allow
(
RequestStore
).
to
receive
(
:store
).
and_return
(
mock_store
)
RequestStore
.
clear!
allow
(
controller
).
to
receive
(
:append_info_to_payload
).
and_wrap_original
do
|
method
,
*|
method
.
call
(
log_payload
)
end
end
it
'appends metadata for logging'
do
post
:execute
,
params:
{
query:
graphql_query
,
operationName:
'Foo'
}
post
:execute
,
params:
{
_json:
graphql_queries
}
expect
(
controller
).
to
have_received
(
:append_info_to_payload
)
expect
(
log_payload
.
dig
(
:metadata
,
:graphql
)).
to
eq
({
operation_name:
'Foo'
,
foo: :bar
}
)
expect
(
log_payload
.
dig
(
:metadata
,
:graphql
)).
to
match_array
(
expected_logs
)
end
end
end
spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
View file @
07b76c54
...
...
@@ -3,43 +3,46 @@
require
'spec_helper'
RSpec
.
describe
Gitlab
::
Graphql
::
QueryAnalyzers
::
LoggerAnalyzer
do
subject
{
described_class
.
new
}
describe
'#initial_value'
do
it
'filters out sensitive variables'
do
doc
=
GraphQL
.
parse
<<-
GRAPHQL
mutation createNote($body: String!) {
createNote(input: {noteableId: "1", body: $body}) {
note {
id
}
let
(
:initial_value
)
{
analyzer
.
initial_value
(
query
)
}
let
(
:analyzer
)
{
described_class
.
new
}
let
(
:query
)
{
GraphQL
::
Query
.
new
(
GitlabSchema
,
document:
document
,
context:
{},
variables:
{
body:
"some note"
})
}
let
(
:document
)
do
GraphQL
.
parse
<<-
GRAPHQL
mutation createNote($body: String!) {
createNote(input: {noteableId: "1", body: $body}) {
note {
id
}
}
GRAPHQL
}
GRAPHQL
end
query
=
GraphQL
::
Query
.
new
(
GitlabSchema
,
document:
doc
,
context:
{},
variables:
{
body:
"some note"
})
describe
'variables'
do
subject
{
initial_value
.
fetch
(
:variables
)
}
expect
(
subject
.
initial_value
(
query
)[
:variables
]).
to
eq
(
'{:body=>"[FILTERED]"}'
)
end
it
{
is_expected
.
to
eq
(
'{:body=>"[FILTERED]"}'
)
}
end
describe
'#final_value'
do
let
(
:monotonic_time_before
)
{
42
}
let
(
:monotonic_time_after
)
{
500
}
let
(
:monotonic_time_duration
)
{
monotonic_time_after
-
monotonic_time_before
}
let
(
:memo
)
{
initial_value
}
subject
(
:final_value
)
{
analyzer
.
final_value
(
memo
)
}
before
do
RequestStore
.
store
[
:graphql_logs
]
=
nil
it
'returns a duration in seconds'
do
allow
(
GraphQL
::
Analysis
).
to
receive
(
:analyze_query
).
and_return
([
4
,
2
,
[[],
[]]])
allow
(
Gitlab
::
Metrics
::
System
).
to
receive
(
:monotonic_time
).
and_return
(
monotonic_time_before
,
monotonic_time_after
)
allow
(
Gitlab
::
GraphqlLogger
).
to
receive
(
:info
)
end
expected_duration
=
monotonic_time_duration
memo
=
subject
.
initial_value
(
spy
(
'query'
))
subject
.
final_value
(
memo
)
expect
(
memo
).
to
have_key
(
:duration_s
)
expect
(
memo
[
:duration_s
]).
to
eq
(
expected_duration
)
it
'inserts duration in seconds to memo and sets request store'
do
expect
{
final_value
}.
to
change
{
memo
[
:duration_s
]
}.
to
(
monotonic_time_duration
)
.
and
change
{
RequestStore
.
store
[
:graphql_logs
]
}.
to
([
memo
])
end
end
end
spec/requests/api/graphql/gitlab_schema_spec.rb
View file @
07b76c54
...
...
@@ -191,6 +191,7 @@ RSpec.describe 'GitlabSchema configurations' do
complexity:
181
,
depth:
13
,
duration_s:
7
,
operation_name:
'IntrospectionQuery'
,
used_fields:
an_instance_of
(
Array
),
used_deprecated_fields:
an_instance_of
(
Array
)
}
...
...
spec/requests/api/graphql_spec.rb
View file @
07b76c54
...
...
@@ -13,6 +13,7 @@ RSpec.describe 'GraphQL' do
query_string:
query
,
variables:
variables
.
to_s
,
duration_s:
anything
,
operation_name:
nil
,
depth:
1
,
complexity:
1
,
used_fields:
[
'Query.echo'
],
...
...
spec/support/helpers/graphql_helpers.rb
View file @
07b76c54
...
...
@@ -222,9 +222,12 @@ module GraphqlHelpers
lazy_vals
.
is_a?
(
Array
)
?
lazy_vals
.
map
{
|
val
|
sync
(
val
)
}
:
sync
(
lazy_vals
)
end
def
graphql_query_for
(
name
,
args
=
{},
selection
=
nil
)
def
graphql_query_for
(
name
,
args
=
{},
selection
=
nil
,
operation_name
=
nil
)
type
=
GitlabSchema
.
types
[
'Query'
].
fields
[
GraphqlHelpers
.
fieldnamerize
(
name
)]
&
.
type
wrap_query
(
query_graphql_field
(
name
,
args
,
selection
,
type
))
query
=
wrap_query
(
query_graphql_field
(
name
,
args
,
selection
,
type
))
query
=
"query
#{
operation_name
}#{
query
}
"
if
operation_name
query
end
def
wrap_query
(
query
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment