mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-06-05 23:03:48 +00:00
144 lines
4.3 KiB
Go
144 lines
4.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
fiber "github.com/gofiber/fiber/v2"
|
|
"github.com/graphql-go/graphql/language/ast"
|
|
"github.com/graphql-go/graphql/language/parser"
|
|
"github.com/graphql-go/graphql/language/source"
|
|
libpack_logger "github.com/lukaszraczylo/graphql-monitoring-proxy/logging"
|
|
)
|
|
|
|
// debugParseGraphQLQuery provides detailed logging for mutation routing analysis
|
|
// This is automatically called when LOG_LEVEL=DEBUG to help identify routing issues
|
|
//
|
|
// It logs:
|
|
// - GraphQL query structure (operations, selections, directives)
|
|
// - Final routing decision (which endpoint was chosen)
|
|
// - Automatic detection of mutations routed to wrong endpoints
|
|
//
|
|
// To enable: Set LOG_LEVEL=DEBUG and restart the proxy
|
|
func debugParseGraphQLQuery(c *fiber.Ctx, query string) {
|
|
if cfg == nil || cfg.Logger == nil {
|
|
return
|
|
}
|
|
|
|
cfg.Logger.Info(&libpack_logger.LogMessage{
|
|
Message: "=== DEBUG: Parsing GraphQL Query ===",
|
|
Pairs: map[string]interface{}{
|
|
"query_length": len(query),
|
|
"query_preview": truncateString(query, 100),
|
|
},
|
|
})
|
|
|
|
// Parse the query
|
|
src := source.NewSource(&source.Source{
|
|
Body: []byte(query),
|
|
Name: "Debug GraphQL request",
|
|
})
|
|
|
|
p, err := parser.Parse(parser.ParseParams{Source: src})
|
|
if err != nil {
|
|
cfg.Logger.Error(&libpack_logger.LogMessage{
|
|
Message: "DEBUG: Failed to parse query",
|
|
Pairs: map[string]interface{}{"error": err.Error()},
|
|
})
|
|
return
|
|
}
|
|
|
|
cfg.Logger.Info(&libpack_logger.LogMessage{
|
|
Message: "DEBUG: Query parsed successfully",
|
|
Pairs: map[string]interface{}{
|
|
"definitions_count": len(p.Definitions),
|
|
},
|
|
})
|
|
|
|
// Analyze each definition
|
|
for i, d := range p.Definitions {
|
|
if oper, ok := d.(*ast.OperationDefinition); ok {
|
|
operationType := strings.ToLower(oper.Operation)
|
|
operationName := "unnamed"
|
|
if oper.Name != nil {
|
|
operationName = oper.Name.Value
|
|
}
|
|
|
|
// Count selections
|
|
selectionCount := 0
|
|
if oper.SelectionSet != nil {
|
|
selectionCount = len(oper.GetSelectionSet().Selections)
|
|
}
|
|
|
|
cfg.Logger.Info(&libpack_logger.LogMessage{
|
|
Message: fmt.Sprintf("DEBUG: Definition #%d (OperationDefinition)", i),
|
|
Pairs: map[string]interface{}{
|
|
"operation_type": operationType,
|
|
"operation_name": operationName,
|
|
"selection_count": selectionCount,
|
|
"is_mutation": operationType == "mutation",
|
|
"directive_count": len(oper.Directives),
|
|
},
|
|
})
|
|
|
|
// Log selections for mutations
|
|
if operationType == "mutation" && oper.SelectionSet != nil {
|
|
for j, sel := range oper.GetSelectionSet().Selections {
|
|
if field, ok := sel.(*ast.Field); ok {
|
|
cfg.Logger.Info(&libpack_logger.LogMessage{
|
|
Message: fmt.Sprintf("DEBUG: Mutation field #%d", j),
|
|
Pairs: map[string]interface{}{
|
|
"field_name": field.Name.Value,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
}
|
|
} else if frag, ok := d.(*ast.FragmentDefinition); ok {
|
|
cfg.Logger.Info(&libpack_logger.LogMessage{
|
|
Message: fmt.Sprintf("DEBUG: Definition #%d (FragmentDefinition)", i),
|
|
Pairs: map[string]interface{}{
|
|
"fragment_name": frag.Name.Value,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
// Now run the actual parsing to see the result
|
|
result := parseGraphQLQuery(c)
|
|
|
|
cfg.Logger.Info(&libpack_logger.LogMessage{
|
|
Message: "DEBUG: Final routing decision",
|
|
Pairs: map[string]interface{}{
|
|
"operation_type": result.operationType,
|
|
"operation_name": result.operationName,
|
|
"active_endpoint": result.activeEndpoint,
|
|
"should_block": result.shouldBlock,
|
|
"should_ignore": result.shouldIgnore,
|
|
"write_endpoint": cfg.Server.HostGraphQL,
|
|
"read_endpoint": cfg.Server.HostGraphQLReadOnly,
|
|
"is_using_write": result.activeEndpoint == cfg.Server.HostGraphQL,
|
|
},
|
|
})
|
|
|
|
// Check for potential issues
|
|
if result.operationType == "mutation" && result.activeEndpoint != cfg.Server.HostGraphQL {
|
|
cfg.Logger.Error(&libpack_logger.LogMessage{
|
|
Message: "DEBUG: ⚠️ BUG DETECTED: Mutation routed to wrong endpoint!",
|
|
Pairs: map[string]interface{}{
|
|
"expected_endpoint": cfg.Server.HostGraphQL,
|
|
"actual_endpoint": result.activeEndpoint,
|
|
},
|
|
})
|
|
}
|
|
|
|
if result.operationType == "mutation" && strings.Contains(strings.ToLower(result.activeEndpoint), "read") {
|
|
cfg.Logger.Error(&libpack_logger.LogMessage{
|
|
Message: "DEBUG: ⚠️ CRITICAL: Mutation endpoint contains 'read' in URL!",
|
|
Pairs: map[string]interface{}{
|
|
"endpoint": result.activeEndpoint,
|
|
},
|
|
})
|
|
}
|
|
}
|