Merge pull request #707 from apache/feature/ui-protocol

Init ui-protocol
This commit is contained in:
彭勇升 pengys 2017-12-31 00:01:27 +08:00 committed by GitHub
commit 8399452ec8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 451 additions and 4 deletions

View File

@ -27,7 +27,13 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apm-ui-query</artifactId>
<artifactId>apm-ui-protocol</artifactId>
</project>
<dependencies>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>6.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,41 @@
# Abstract
**apm-ui-protocol** declares all services, using GraphQL API style, which provide by Collector UI module.
## Services
### [Common](common.graphqls)
Include common objects, which used in global
### [Overview Layer Service](overview-layer.graphqls)
Query data without specific application, server or service. It includes info for overview the whole cluster.
### [Application Layer Service](application-layer.graphqls)
Query application related data with specific application code.
### [Server Layer Service](server-layer.graphqls)
Query server related data with specific server id.
### [Service Layer Service](service-layer.graphqls)
Query service related data with specific service id
### [Trace Service](trace.graphqls)
Query trace by some conditions.
### [Alarm Service](alarm.graphqls)
Query alarm info.
## Version
v1alpha1
### Versioning
Use URI Versioning, to follow the most straightforward approach,
though it does violate the principle that a URI should refer to a unique resource.
e.g.
http://collector.host/graphql/v1alpha1

View File

@ -0,0 +1,15 @@
type AlarmItem {
content: String!
startTime: String!
alertType: AlarmType!
}
enum AlarmType {
APPLICATION,
SERVER,
SERVICE
}
extend type Query {
loadAlertList(keyword: String, alertType: AlarmType, duration:Duration!):[AlarmItem]
}

View File

@ -0,0 +1,37 @@
# ApplicationNode represents this node is under monitoring by agent.
type ApplicationNode implements Node {
id: ID!
name: String!
type: String
# Success rate of all incoming requests.
# Max value is 100.
# 2 Digits after floating point.
sla: Float!
# The number of incoming calls
calls: Long!
# ref: http://www.apdex.org/
# Max value is 1
# 2 Digits after floating point.
apdex: Float!
# The number of servers in the application code
numOfServer: Int!
# The number of servers alerting
numOfServerAlarm: Int!
# The number of services alerting
numOfServiceAlarm: Int!
}
# The conjectural node generated by exit span
type ConjecturalNode implements Node {
id: ID!
name: String!
type: String
}
extend type Query {
getAllApplication(duration: Duration!): [ApplicationNode]
getApplicationTopology(applicationId: ID!, duration: Duration!): Topology
getSlowService(applicationId: ID!, duration: Duration!): [ServiceInfo!]
getServerThroughput(applicationId: ID!, duration: Duration!): [AppServerInfo!]
}

View File

@ -0,0 +1,88 @@
schema {
query: Query
}
#Root node
type Query {
version: String
}
# The Duration defines the start and end time for each query operation.
# Fields: `start` and `end`
# represents the time span. And each of them matches the step.
# ref https://www.ietf.org/rfc/rfc3339.txt
# The time formats are
# `SECOND` step: yyyy-MM-dd HHmmss
# `MINUTE` step: yyyy-MM-dd HHmm
# `HOUR` step: yyyy-MM-dd HH
# `DAY` step: yyyy-MM-dd
# `MONTH` step: yyyy-MM
# Field: `step`
# represents the accurate time point.
# e.g.
# if step==HOUR , start=2017-11-08 09, end=2017-11-08 19
# then
# metrics from the following time points expected
# 2017-11-08 9:00 -> 2017-11-08 19:00
# there are 11 time points (hours) in the time span.
input Duration {
start: String!
end: String!
step: Step!
}
enum Step {
MONTH
DAY
HOUR
MINUTE
SECOND
}
######################################
# Common Metrics and Trends
######################################
type ResponseTimeTrend {
trendList: [Int!]
}
type ThroughputTrend {
trendList: [Int!]
}
type SLATrend {
trendList: [Int!]
}
# The overview topology of the whole application cluster or services,
type Topology {
nodes: [Node]!
calls: [Call]
}
# The base Node of all node types in topology
interface Node {
# The global id of each node,
# 1. `Application ID` represents application under monitoring
# 2. `Peer ID` string represents the conjectural dependency.
id: ID!
# Application Code or literal Peer
name: String!
# The type name
# 1. The most important component in the application, from service provider perspective.
# 2. Conjectural dependent component, e.g. MySQL, Redis, Kafka
type: String
}
# The Call represents a directed distributed call,
# from the `source` to the `target`.
type Call {
source: ID!
target: ID!
isAlert: Boolean
# The protocol and tech stack used in this distributed call
callType: String!
callsPerSec: Int!
# Unit: millisecond
responseTimePerSec: Int!
}

View File

@ -0,0 +1,37 @@
# Query the cluster brief based on the given duration
type ClusterBrief {
numOfApplication: Int
numOfService: Int
numOfDatabase: Int
numOfCache: Int
numOfMQ: Int
}
# Query the trend of alarm rate based on the given duration
type AlarmTrend {
numOfAlarmRate: [Int]!
}
# Query all conjectural applications based on the given duration
# All applications here are not installed agent.
type ConjecturalAppBrief {
apps: [ConjecturalApp!]
}
# The basic info of the conjectural application,
# includes the type and num of same type application
type ConjecturalApp {
# The display name of the application
# e.g. MySQL, RocketMQ, Kafka, Nginx
name: String!
num: Int!
}
extend type Query {
getClusterTopology(duration: Duration!): Topology
getClusterBrief(duration: Duration!): ClusterBrief
getAlarmTrend(duration: Duration!): AlarmTrend
getConjecturalApps(duration: Duration!): ConjecturalAppBrief
getTopNSlowService(duration: Duration!, topN: Int!): [ServiceInfo!]
getTopNServerThroughput(duration: Duration!, topN: Int!): [AppServerInfo!]
}

View File

@ -0,0 +1,42 @@
# The server info.
# At here, `Server` represents a process in OS,
# e.g.
# 1. Spring boot application
# 2. A Tomcat server instance
type AppServerInfo {
id: ID!
name: String!
tps: Int!
os: String
host: String
pid: Int
IPv4: String
IPv6: String
}
type CPUTrend {
cost: [Int!]
}
# The gc trend represents the numbers of Garbage Collector execution
type GCTrend {
youngGC: [Int!]
oldGC: [Int!]
}
# The memory used and max limit in heap and noheap space.
type MemoryTrend {
heap: [Int!]
maxHeap: [Int!]
noheap: [Int!]
maxNoheap: [Int!]
}
extend type Query {
searchServer(keyword: String!, duration: Duration!): [AppServerInfo]
getServerResponseTimeTrend(serverId: ID!, duration: Duration!): ResponseTimeTrend
getServerTPSTrend(serverId: ID!, duration: Duration!): ThroughputTrend
getCPUTrend(serverId: ID!, duration: Duration!): CPUTrend
getGCTrend(serverId: ID!, duration: Duration!): GCTrend
getMemoryTrend(serverId: ID!, duration: Duration!): MemoryTrend
}

View File

@ -0,0 +1,35 @@
type ServiceNode implements Node {
id: ID!
name: String!
type: String
# Success rate of all incoming requests.
# Max value is 100.
# 2 Digits after floating point.
sla: Float!
# The number of incoming calls
calls: Long!
# The number of services alerting
numOfServiceAlarm: Int!
}
type ServiceInfo {
id: ID!
name: String
# The unit is millisecond.
avgResponseTime: Int!
tps: Int!
}
type TraceItem {
time: String!
entry: String!
duration: Int!
}
extend type Query {
searchService(keyword: String!, duration: Duration!): [ServiceNode]
getServiceResponseTimeTrend(serviceId: ID!, duration: Duration!): ResponseTimeTrend
getServiceTPSTrend(serviceId: ID!, duration: Duration!): ThroughputTrend
getServiceSLATrend(serviceId: ID!, duration: Duration!): SLATrend
getServiceTopology(serviceId: ID!, duration: Duration!): Topology
}

View File

@ -0,0 +1,89 @@
# The list of traces
type TraceBrief {
traces: [BasicTrace!]
}
# Trace basic info
type BasicTrace {
operationName: String!
duration: Int!
start: String!
isError: Boolean
traceId: String
}
# Represent the conditions used for query TraceBrief
input TraceQueryCondition {
applicationCodes: [String!]
traceId: String
operationName: String
# The time range of traces started
queryDuration: Duration
# The mix time of trace
minTraceDuration: Int
# The max time of trace
maxTraceDuration: Int
topN: Boolean
needTotal: Int
}
enum QueryOrder {
BY_START_TIME
BY_DURATION
}
# The trace represents a distributed trace, includes all segments and spans.
type Trace {
traceId: ID!
segments: [Segment!]
}
type Segment {
segmentId: ID!
appName: String!
isSizeLimited: Boolean!
spans: [Span!]!
}
type Span {
refs: [Ref!]
spanId: Int!
parentSpanId: Int!
startTime: Long!
endTime: Long!
operationName: String
# There are three span types: Local, Entry and Exit
type: String!
# Peer network id, e.g. host+port, ip+port
peer: String
component: String
isError: Boolean
# There are 5 layers: Unknown, Database, RPCFramework, Http, MQ and Cache
layer: String
tags: [KeyValue!]
logs: [LogEntity!]
}
# Ref represents the link between the segment and its parents.
type Ref {
parentSegmentId: ID!
parentSpanId: Int!
# Ref type represents why did the ref happen.
# Include: 1) CrossProcess 2) CrossThread
type: String!
}
type KeyValue {
key: String!
value: String
}
type LogEntity {
time: String
data: [KeyValue!]
}
extend type Query {
queryBasicTraces(condition: TraceQueryCondition): TraceBrief
queryTrace(traceId: ID!): Trace
}

View File

@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.ui.protocol;
import graphql.schema.idl.EchoingWiringFactory;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import java.io.File;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class GraphQLScriptTest {
@Test
public void assertScriptFormat() {
SchemaParser schemaParser = new SchemaParser();
SchemaGenerator schemaGenerator = new SchemaGenerator();
TypeDefinitionRegistry typeRegistry = new TypeDefinitionRegistry();
typeRegistry.merge(schemaParser.parse(loadSchema("common.graphqls")));
typeRegistry.merge(schemaParser.parse(loadSchema("trace.graphqls")));
typeRegistry.merge(schemaParser.parse(loadSchema("overview-layer.graphqls")));
typeRegistry.merge(schemaParser.parse(loadSchema("application-layer.graphqls")));
typeRegistry.merge(schemaParser.parse(loadSchema("server-layer.graphqls")));
typeRegistry.merge(schemaParser.parse(loadSchema("service-layer.graphqls")));
typeRegistry.merge(schemaParser.parse(loadSchema("alarm.graphqls")));
RuntimeWiring wiring = buildRuntimeWiring();
assertTrue(schemaGenerator.makeExecutableSchema(typeRegistry, wiring).getAllTypesAsList().size() > 0);
}
private File loadSchema(final String s) {
return new File(GraphQLScriptTest.class.getClassLoader().getResource("ui-graphql/" + s).getFile());
}
private RuntimeWiring buildRuntimeWiring() {
return RuntimeWiring.newRuntimeWiring().wiringFactory(new EchoingWiringFactory()).build();
}
}

View File

@ -32,6 +32,6 @@
<modules>
<module>apm-network</module>
<module>apm-ui-query</module>
<module>apm-ui-protocol</module>
</modules>
</project>