@@ -10,7 +10,7 @@ use crate::cheap_clone::CheapClone;
1010use crate :: data:: graphql:: { ObjectOrInterface , ObjectTypeExt , TypeExt } ;
1111use crate :: data:: store:: IdType ;
1212use crate :: env:: ENV_VARS ;
13- use crate :: schema:: { ast, META_FIELD_NAME , META_FIELD_TYPE , SCHEMA_TYPE_NAME } ;
13+ use crate :: schema:: { ast, LOGS_FIELD_NAME , META_FIELD_NAME , META_FIELD_TYPE , SCHEMA_TYPE_NAME } ;
1414
1515use crate :: data:: graphql:: ext:: {
1616 camel_cased_names, DefinitionExt , DirectiveExt , DocumentExt , ValueExt ,
@@ -349,7 +349,7 @@ pub(in crate::schema) fn api_schema(
349349) -> Result < s:: Document , APISchemaError > {
350350 // Refactor: Don't clone the schema.
351351 let mut api = init_api_schema ( input_schema) ?;
352- add_meta_field_type ( & mut api. document ) ;
352+ add_builtin_field_types ( & mut api. document ) ;
353353 add_types_for_object_types ( & mut api, input_schema) ?;
354354 add_types_for_interface_types ( & mut api, input_schema) ?;
355355 add_types_for_aggregation_types ( & mut api, input_schema) ?;
@@ -444,18 +444,24 @@ fn init_api_schema(input_schema: &InputSchema) -> Result<Schema, APISchemaError>
444444 . map_err ( |e| APISchemaError :: SchemaCreationFailed ( e. to_string ( ) ) )
445445}
446446
447- /// Adds a global `_Meta_` type to the schema. The `_meta` field
448- /// accepts values of this type
449- fn add_meta_field_type ( api : & mut s:: Document ) {
447+ /// Adds built-in field types to the schema. Currently adds `_Meta_` and `_Log_` types
448+ /// which are used by the `_meta` and `_logs` fields respectively.
449+ fn add_builtin_field_types ( api : & mut s:: Document ) {
450450 lazy_static ! {
451451 static ref META_FIELD_SCHEMA : s:: Document = {
452452 let schema = include_str!( "meta.graphql" ) ;
453453 s:: parse_schema( schema) . expect( "the schema `meta.graphql` is invalid" )
454454 } ;
455+ static ref LOGS_FIELD_SCHEMA : s:: Document = {
456+ let schema = include_str!( "logs.graphql" ) ;
457+ s:: parse_schema( schema) . expect( "the schema `logs.graphql` is invalid" )
458+ } ;
455459 }
456460
457461 api. definitions
458462 . extend ( META_FIELD_SCHEMA . definitions . iter ( ) . cloned ( ) ) ;
463+ api. definitions
464+ . extend ( LOGS_FIELD_SCHEMA . definitions . iter ( ) . cloned ( ) ) ;
459465}
460466
461467fn add_types_for_object_types (
@@ -1098,6 +1104,7 @@ fn add_query_type(api: &mut s::Document, input_schema: &InputSchema) -> Result<(
10981104 fields. append ( & mut agg_fields) ;
10991105 fields. append ( & mut fulltext_fields) ;
11001106 fields. push ( meta_field ( ) ) ;
1107+ fields. push ( logs_field ( ) ) ;
11011108
11021109 let typedef = s:: TypeDefinition :: Object ( s:: ObjectType {
11031110 position : q:: Pos :: default ( ) ,
@@ -1303,6 +1310,102 @@ fn meta_field() -> s::Field {
13031310 META_FIELD . clone ( )
13041311}
13051312
1313+ fn logs_field ( ) -> s:: Field {
1314+ lazy_static ! {
1315+ static ref LOGS_FIELD : s:: Field = s:: Field {
1316+ position: Pos :: default ( ) ,
1317+ description: Some (
1318+ "Query execution logs emitted by the subgraph during indexing. \
1319+ Results are sorted by timestamp in descending order (newest first)."
1320+ . to_string( )
1321+ ) ,
1322+ name: LOGS_FIELD_NAME . to_string( ) ,
1323+ arguments: vec![
1324+ // level: LogLevel
1325+ s:: InputValue {
1326+ position: Pos :: default ( ) ,
1327+ description: Some (
1328+ "Filter logs by severity level. Only logs at this level will be returned."
1329+ . to_string( )
1330+ ) ,
1331+ name: String :: from( "level" ) ,
1332+ value_type: s:: Type :: NamedType ( String :: from( "LogLevel" ) ) ,
1333+ default_value: None ,
1334+ directives: vec![ ] ,
1335+ } ,
1336+ // from: String (RFC3339 timestamp)
1337+ s:: InputValue {
1338+ position: Pos :: default ( ) ,
1339+ description: Some (
1340+ "Filter logs from this timestamp onwards (inclusive). \
1341+ Must be in RFC3339 format (e.g., '2024-01-15T10:30:00Z')."
1342+ . to_string( )
1343+ ) ,
1344+ name: String :: from( "from" ) ,
1345+ value_type: s:: Type :: NamedType ( String :: from( "String" ) ) ,
1346+ default_value: None ,
1347+ directives: vec![ ] ,
1348+ } ,
1349+ // to: String (RFC3339 timestamp)
1350+ s:: InputValue {
1351+ position: Pos :: default ( ) ,
1352+ description: Some (
1353+ "Filter logs until this timestamp (inclusive). \
1354+ Must be in RFC3339 format (e.g., '2024-01-15T23:59:59Z')."
1355+ . to_string( )
1356+ ) ,
1357+ name: String :: from( "to" ) ,
1358+ value_type: s:: Type :: NamedType ( String :: from( "String" ) ) ,
1359+ default_value: None ,
1360+ directives: vec![ ] ,
1361+ } ,
1362+ // search: String (full-text search)
1363+ s:: InputValue {
1364+ position: Pos :: default ( ) ,
1365+ description: Some (
1366+ "Search for logs containing this text in the message. \
1367+ Case-insensitive substring match. Maximum length: 1000 characters."
1368+ . to_string( )
1369+ ) ,
1370+ name: String :: from( "search" ) ,
1371+ value_type: s:: Type :: NamedType ( String :: from( "String" ) ) ,
1372+ default_value: None ,
1373+ directives: vec![ ] ,
1374+ } ,
1375+ // first: Int (default 100, max 1000)
1376+ s:: InputValue {
1377+ position: Pos :: default ( ) ,
1378+ description: Some (
1379+ "Maximum number of logs to return. Default: 100, Maximum: 1000."
1380+ . to_string( )
1381+ ) ,
1382+ name: String :: from( "first" ) ,
1383+ value_type: s:: Type :: NamedType ( String :: from( "Int" ) ) ,
1384+ default_value: Some ( s:: Value :: Int ( 100 . into( ) ) ) ,
1385+ directives: vec![ ] ,
1386+ } ,
1387+ // skip: Int (default 0, max 10000)
1388+ s:: InputValue {
1389+ position: Pos :: default ( ) ,
1390+ description: Some (
1391+ "Number of logs to skip (for pagination). Default: 0, Maximum: 10000."
1392+ . to_string( )
1393+ ) ,
1394+ name: String :: from( "skip" ) ,
1395+ value_type: s:: Type :: NamedType ( String :: from( "Int" ) ) ,
1396+ default_value: Some ( s:: Value :: Int ( 0 . into( ) ) ) ,
1397+ directives: vec![ ] ,
1398+ } ,
1399+ ] ,
1400+ field_type: s:: Type :: NonNullType ( Box :: new( s:: Type :: ListType ( Box :: new(
1401+ s:: Type :: NonNullType ( Box :: new( s:: Type :: NamedType ( String :: from( "_Log_" ) ) ) ) ,
1402+ ) ) ) ) ,
1403+ directives: vec![ ] ,
1404+ } ;
1405+ }
1406+ LOGS_FIELD . clone ( )
1407+ }
1408+
13061409#[ cfg( test) ]
13071410mod tests {
13081411 use crate :: {
0 commit comments