Add zpages gateway and webapp
This commit is contained in:
parent
615a02d81c
commit
901ae93ee8
|
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed 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.
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
Experimental warning
|
||||||
|
====================
|
||||||
|
|
||||||
|
This tool is a proof of concept, but feedback is welcome.
|
||||||
|
|
||||||
|
Description
|
||||||
|
===========
|
||||||
|
|
||||||
|
gRPC provides debug stats in the form of an RPC service. For example,
|
||||||
|
[channelz](https://github.com/grpc/proposal/blob/master/A14-channelz.md)
|
||||||
|
is a service that provides channel level debug information. This repo
|
||||||
|
contains a tool that connects to a remote gRPC `channelz` service and
|
||||||
|
displays the data as a web page using a local `golang` web server.
|
||||||
|
The goal is to provide a single CLI tool that can display all gRPC
|
||||||
|
debug pages.
|
||||||
|
|
||||||
|
A screenshot of servers page:
|
||||||
|

|
||||||
|
|
||||||
|
A screenshot of a detailed socket page:
|
||||||
|

|
||||||
|
|
||||||
|
Design
|
||||||
|
======
|
||||||
|
|
||||||
|
The tool has two components: an Angular web app and a CLI tool. The
|
||||||
|
web app is responsible for the core GUI logic, and the CLI acts as a
|
||||||
|
proxy that transforms the Angular app's web requests to gRPC
|
||||||
|
requests. The goal is to do the heavy lifting in the web browser in a
|
||||||
|
backend agnostic way. Other translation gateways can be created
|
||||||
|
easily created to suit different operating environments, e.g. as a
|
||||||
|
shared service or on a web server co-located on the gRPC host. The
|
||||||
|
complete set of web requests is defined in:
|
||||||
|
|
||||||
|
`web/channelzui/src/app/channelz.service.ts`
|
||||||
|
|
||||||
|
|
||||||
|
Running the tool
|
||||||
|
================
|
||||||
|
|
||||||
|
This example shows how to connect the tool to a gRPC service runnning
|
||||||
|
[channelz](https://github.com/grpc/proposal/blob/master/A14-channelz.md)
|
||||||
|
at `127.0.0.1:5001`. The local web server runs on port `8080`.
|
||||||
|
|
||||||
|
Tip: The `GOPATH` environment variable determines where `go get`
|
||||||
|
downloads its packages. This is useful if you would like the CLI
|
||||||
|
tool's dependencies to go to a specific directory.
|
||||||
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cd cli
|
||||||
|
$ go get -u github.com/golang/protobuf/protoc-gen-go
|
||||||
|
$ go get -u google.golang.org/grpc
|
||||||
|
$ go run gateway.go -serverAddr=127.0.0.1:50051 -port=8080
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Compile instructions for the web app
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Normally, rebuilding the web app is not necessary. The compiled
|
||||||
|
javascript and HTML files are already present in the repo.
|
||||||
|
|
||||||
|
`npm` is required to be on your `PATH`. This code has been verified to
|
||||||
|
work with version `5.8.0` of `npm`.
|
||||||
|
|
||||||
|
To rebuild and copy the distributable files:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ buildscripts/update_angular.sh
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -eux -o pipefail
|
||||||
|
|
||||||
|
readonly GRPC_ZPAGES_DIR="$(cd "$(dirname "$0")"/.. && pwd)"
|
||||||
|
|
||||||
|
cd $GRPC_ZPAGES_DIR/web/channelzui/
|
||||||
|
npm install
|
||||||
|
ng build --prod --build-optimizer --base-href=/dist_channelz/
|
||||||
|
|
||||||
|
rm $GRPC_ZPAGES_DIR/cli/dist_channelz/*
|
||||||
|
cp $GRPC_ZPAGES_DIR/web/channelzui/dist/* $GRPC_ZPAGES_DIR/cli/dist_channelz/
|
||||||
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
core-js@2.5.5
|
||||||
|
MIT
|
||||||
|
Copyright (c) 2014-2018 Denis Pushkarev
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
zone.js@0.8.26
|
||||||
|
MIT
|
||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016-2018 Google, Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Channelz</title>
|
||||||
|
<base href="/dist_channelz/">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="styles.32f0d240d4c6d000c235.css"></head>
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
<script type="text/javascript" src="runtime.a66f828dca56eeb90e02.js"></script><script type="text/javascript" src="polyfills.7f9d473f1d5c840b0bca.js"></script><script type="text/javascript" src="main.5dde8b72505d5a34f8e5.js"></script></body>
|
||||||
|
</html>
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
||||||
|
!function(r){function e(e){for(var t,p,c=e[0],a=e[1],f=e[2],l=0,s=[];l<c.length;l++)o[p=c[l]]&&s.push(o[p][0]),o[p]=0;for(t in a)Object.prototype.hasOwnProperty.call(a,t)&&(r[t]=a[t]);for(i&&i(e);s.length;)s.shift()();return u.push.apply(u,f||[]),n()}function n(){for(var r,e=0;e<u.length;e++){for(var n=u[e],t=!0,c=1;c<n.length;c++)0!==o[n[c]]&&(t=!1);t&&(u.splice(e--,1),r=p(p.s=n[0]))}return r}var t={},o={0:0},u=[];function p(e){if(t[e])return t[e].exports;var n=t[e]={i:e,l:!1,exports:{}};return r[e].call(n.exports,n,n.exports,p),n.l=!0,n.exports}p.m=r,p.c=t,p.d=function(r,e,n){p.o(r,e)||Object.defineProperty(r,e,{configurable:!1,enumerable:!0,get:n})},p.r=function(r){Object.defineProperty(r,"__esModule",{value:!0})},p.n=function(r){var e=r&&r.__esModule?function(){return r.default}:function(){return r};return p.d(e,"a",e),e},p.o=function(r,e){return Object.prototype.hasOwnProperty.call(r,e)},p.p="";var c=window.webpackJsonp=window.webpackJsonp||[],a=c.push.bind(c);c.push=e,c=c.slice();for(var f=0;f<c.length;f++)e(c[f]);var i=a;n()}([]);
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
body{margin:0;font-family:Roboto,sans-serif}
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"github.com/golang/protobuf/jsonpb"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/channelz/grpc_channelz_v1"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var marshaler = jsonpb.Marshaler{EmitDefaults: true, Indent: " "}
|
||||||
|
var unmarshaler = jsonpb.Unmarshaler{}
|
||||||
|
|
||||||
|
func printHelper(w http.ResponseWriter, pb proto.Message) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json, _ := marshaler.MarshalToString(pb)
|
||||||
|
fmt.Fprintf(w, "%s", json)
|
||||||
|
}
|
||||||
|
|
||||||
|
func errorHelper(w http.ResponseWriter, errstr string) {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
fmt.Fprintf(w, "%s", errstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var serverAddr = flag.String("serverAddr", "", "the target server address")
|
||||||
|
var port = flag.Int("port", 8080, "local port")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
fmt.Println(os.Stdout, "Address: %s", *serverAddr)
|
||||||
|
var opts []grpc.DialOption
|
||||||
|
opts = append(opts, grpc.WithInsecure())
|
||||||
|
conn, err := grpc.Dial(*serverAddr, opts...)
|
||||||
|
defer conn.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to connect to %s\n", serverAddr)
|
||||||
|
}
|
||||||
|
client := grpc_channelz_v1.NewChannelzClient(conn)
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/grpcz_internal", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
q := r.URL.Query()
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
json := strings.NewReader(q["request"][0])
|
||||||
|
switch method := q["full_method_name"][0]; method {
|
||||||
|
case "grpc.channelz.v1.Channelz/GetServers":
|
||||||
|
req := grpc_channelz_v1.GetServersRequest{}
|
||||||
|
unmarshaler.Unmarshal(json, &req)
|
||||||
|
response, err := client.GetServers(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
errorHelper(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
printHelper(w, response)
|
||||||
|
case "grpc.channelz.v1.Channelz/GetServerSockets":
|
||||||
|
req := grpc_channelz_v1.GetServerSocketsRequest{}
|
||||||
|
unmarshaler.Unmarshal(json, &req)
|
||||||
|
response, err := client.GetServerSockets(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
errorHelper(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
printHelper(w, response)
|
||||||
|
case "grpc.channelz.v1.Channelz/GetTopChannels":
|
||||||
|
req := grpc_channelz_v1.GetTopChannelsRequest{}
|
||||||
|
unmarshaler.Unmarshal(json, &req)
|
||||||
|
response, err := client.GetTopChannels(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
errorHelper(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
printHelper(w, response)
|
||||||
|
case "grpc.channelz.v1.Channelz/GetSubchannel":
|
||||||
|
req := grpc_channelz_v1.GetSubchannelRequest{}
|
||||||
|
unmarshaler.Unmarshal(json, &req)
|
||||||
|
response, err := client.GetSubchannel(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
errorHelper(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
printHelper(w, response)
|
||||||
|
case "grpc.channelz.v1.Channelz/GetChannel":
|
||||||
|
req := grpc_channelz_v1.GetSubchannelRequest{}
|
||||||
|
unmarshaler.Unmarshal(json, &req)
|
||||||
|
response, err := client.GetSubchannel(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
errorHelper(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
printHelper(w, response)
|
||||||
|
case "grpc.channelz.v1.Channelz/GetSocket":
|
||||||
|
req := grpc_channelz_v1.GetSocketRequest{}
|
||||||
|
unmarshaler.Unmarshal(json, &req)
|
||||||
|
response, err := client.GetSocket(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
errorHelper(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
printHelper(w, response)
|
||||||
|
default:
|
||||||
|
errorHelper(w, "Invalid method")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if (strings.HasSuffix(r.URL.Path, ".css") || strings.HasSuffix(r.URL.Path, ".js")) {
|
||||||
|
http.ServeFile(w, r, r.URL.Path[1:])
|
||||||
|
} else {
|
||||||
|
http.ServeFile(w, r, "dist_channelz/index.html")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
fmt.Printf("zpages now serving at: http://localhost:%d for %s\n", *port, *serverAddr)
|
||||||
|
|
||||||
|
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), mux))
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 459 KiB |
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Editor configuration, see http://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Channelzui
|
||||||
|
|
||||||
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.7.4.
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||||
|
|
||||||
|
## Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"channelzui": {
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"projectType": "application",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"tsConfig": "src/tsconfig.app.json",
|
||||||
|
"showCircularDependencies": true,
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"assets": [
|
||||||
|
"src/assets",
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.css"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"extractCss": true,
|
||||||
|
"namedChunks": false,
|
||||||
|
"aot": true,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true,
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "channelzui:build"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "channelzui:build:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "channelzui:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "src/test.ts",
|
||||||
|
"karmaConfig": "./karma.conf.js",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "src/tsconfig.spec.json",
|
||||||
|
"scripts": [],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.css"
|
||||||
|
],
|
||||||
|
"assets": [
|
||||||
|
"src/assets",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"src/tsconfig.app.json",
|
||||||
|
"src/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"channelzui-e2e": {
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "",
|
||||||
|
"projectType": "application",
|
||||||
|
"architect": {
|
||||||
|
"e2e": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
"protractorConfig": "./protractor.conf.js",
|
||||||
|
"devServerTarget": "channelzui:serve"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"e2e/tsconfig.e2e.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultProject": "channelzui",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"prefix": "app",
|
||||||
|
"styleext": "css"
|
||||||
|
},
|
||||||
|
"@schematics/angular:directive": {
|
||||||
|
"prefix": "app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { AppPage } from './app.po';
|
||||||
|
|
||||||
|
describe('channelzui App', () => {
|
||||||
|
let page: AppPage;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
page = new AppPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display welcome message', () => {
|
||||||
|
page.navigateTo();
|
||||||
|
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { browser, by, element } from 'protractor';
|
||||||
|
|
||||||
|
export class AppPage {
|
||||||
|
navigateTo() {
|
||||||
|
return browser.get('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
getParagraphText() {
|
||||||
|
return element(by.css('app-root h1')).getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../out-tsc/e2e",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es5",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"jasminewd2",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage-istanbul-reporter'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client:{
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
coverageIstanbulReporter: {
|
||||||
|
dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ],
|
||||||
|
fixWebpackSourcePaths: true
|
||||||
|
},
|
||||||
|
angularCli: {
|
||||||
|
environment: 'dev'
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false
|
||||||
|
});
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"name": "channelzui",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "ng serve",
|
||||||
|
"build": "ng build",
|
||||||
|
"test": "ng test",
|
||||||
|
"lint": "ng lint",
|
||||||
|
"e2e": "ng e2e"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/common": "6.0.3",
|
||||||
|
"@angular/compiler": "6.0.3",
|
||||||
|
"@angular/core": "6.0.3",
|
||||||
|
"@angular/forms": "6.0.3",
|
||||||
|
"@angular/http": "6.0.3",
|
||||||
|
"@angular/platform-browser": "6.0.3",
|
||||||
|
"@angular/platform-browser-dynamic": "6.0.3",
|
||||||
|
"@angular/router": "6.0.3",
|
||||||
|
"core-js": "^2.4.1",
|
||||||
|
"rxjs": "^6.2.0",
|
||||||
|
"ts-loader": "^4.1.0",
|
||||||
|
"webpack": "^4.3.0",
|
||||||
|
"zone.js": "^0.8.26"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "~0.6.6",
|
||||||
|
"@angular/cli": "6.0.7",
|
||||||
|
"@angular/compiler-cli": "6.0.3",
|
||||||
|
"@angular/language-service": "6.0.3",
|
||||||
|
"@types/jasmine": "~2.8.3",
|
||||||
|
"@types/jasminewd2": "~2.0.2",
|
||||||
|
"@types/node": "^6.0.105",
|
||||||
|
"codelyzer": "^4.0.1",
|
||||||
|
"protractor": "~5.1.2",
|
||||||
|
"ts-node": "~4.1.0",
|
||||||
|
"tslint": "~5.9.1",
|
||||||
|
"typescript": "2.7.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Protractor configuration file, see link for more information
|
||||||
|
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||||
|
|
||||||
|
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||||
|
|
||||||
|
exports.config = {
|
||||||
|
allScriptsTimeout: 11000,
|
||||||
|
specs: [
|
||||||
|
'./e2e/**/*.e2e-spec.ts'
|
||||||
|
],
|
||||||
|
capabilities: {
|
||||||
|
'browserName': 'chrome'
|
||||||
|
},
|
||||||
|
directConnect: true,
|
||||||
|
baseUrl: 'http://localhost:4200/',
|
||||||
|
framework: 'jasmine',
|
||||||
|
jasmineNodeOpts: {
|
||||||
|
showColors: true,
|
||||||
|
defaultTimeoutInterval: 30000,
|
||||||
|
print: function() {}
|
||||||
|
},
|
||||||
|
onPrepare() {
|
||||||
|
require('ts-node').register({
|
||||||
|
project: 'e2e/tsconfig.e2e.json'
|
||||||
|
});
|
||||||
|
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
licenses(["notice"]) # Apache 2.0
|
||||||
|
|
||||||
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
|
load("//javascript/angular2:build_defs.bzl", "ng_module")
|
||||||
|
|
||||||
|
ng_module(
|
||||||
|
name = "app",
|
||||||
|
srcs = glob(["**/*.ts"]),
|
||||||
|
assets = glob(["**/*.css"]) + glob(["**/*.html"]),
|
||||||
|
deps = [
|
||||||
|
"//third_party/javascript/angular2:common",
|
||||||
|
"//third_party/javascript/angular2:common_http",
|
||||||
|
"//third_party/javascript/angular2:core",
|
||||||
|
"//third_party/javascript/angular2:forms",
|
||||||
|
"//third_party/javascript/angular2:platform_browser",
|
||||||
|
"//third_party/javascript/angular2:router",
|
||||||
|
"//third_party/javascript/rxjs",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
load("//javascript/typescript:build_defs.bzl", "ts_config")
|
||||||
|
|
||||||
|
ts_config(
|
||||||
|
name = "tsconfig",
|
||||||
|
deps = [
|
||||||
|
":app",
|
||||||
|
"//third_party/javascript/angular2:common",
|
||||||
|
"//third_party/javascript/angular2:common_http",
|
||||||
|
"//third_party/javascript/angular2:core",
|
||||||
|
"//third_party/javascript/angular2:forms",
|
||||||
|
"//third_party/javascript/angular2:platform_browser",
|
||||||
|
"//third_party/javascript/angular2:router",
|
||||||
|
"//third_party/javascript/rxjs",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { ServersComponent } from './servers/servers.component';
|
||||||
|
import { SocketComponent } from './socket/socket.component';
|
||||||
|
import { TopChannelsComponent } from './top-channels/top-channels.component';
|
||||||
|
import { SubchannelComponent } from './subchannel/subchannel.component';
|
||||||
|
import { ChannelComponent } from './channel/channel.component';
|
||||||
|
import { ServerSocketsComponent } from './server-sockets/server-sockets.component';
|
||||||
|
import { HelpComponent } from './help/help.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: 'channelz/servers/:startId', component: ServersComponent },
|
||||||
|
{ path: 'channelz/servers', component: ServersComponent },
|
||||||
|
{ path: 'channelz/servers/:startId', component: ServersComponent },
|
||||||
|
{ path: 'channelz/servers', component: ServersComponent },
|
||||||
|
{ path: 'channelz/topchannels/:startId', component: TopChannelsComponent },
|
||||||
|
{ path: 'channelz/topchannels', component: TopChannelsComponent },
|
||||||
|
{ path: 'channelz/socket/:id', component: SocketComponent},
|
||||||
|
{ path: 'channelz/socket', component: SocketComponent},
|
||||||
|
{ path: 'channelz/channel/:id', component: ChannelComponent },
|
||||||
|
{ path: 'channelz/channel', component: ChannelComponent },
|
||||||
|
{ path: 'channelz/subchannel/:id', component: SubchannelComponent },
|
||||||
|
{ path: 'channelz/subchannel', component: SubchannelComponent },
|
||||||
|
{ path: 'channelz/serversockets/:serverId/:socketStartId', component: ServerSocketsComponent },
|
||||||
|
{ path: 'channelz/serversockets/:serverId', component: ServerSocketsComponent },
|
||||||
|
{ path: 'channelz/serversockets', component: ServerSocketsComponent },
|
||||||
|
{ path: 'channelz/help', component: HelpComponent },
|
||||||
|
{ path: 'channelz', redirectTo: '/', pathMatch: 'full' },
|
||||||
|
{ path: '', redirectTo: '/', pathMatch: 'full' },
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
exports: [ RouterModule ],
|
||||||
|
imports: [ RouterModule.forRoot(routes) ],
|
||||||
|
})
|
||||||
|
export class AppRoutingModule {}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<h2>Channelz</h2>
|
||||||
|
<nav>
|
||||||
|
<a routerLink="/channelz/servers" routerLinkActive="active">Servers</a>
|
||||||
|
<a routerLink="/channelz/topchannels" routerLinkActive="active">TopChannels</a>
|
||||||
|
<a routerLink="/channelz/serversockets" routerLinkActive="active">Server sockets</a>
|
||||||
|
<a routerLink="/channelz/channel" routerLinkActive="active">Channel</a>
|
||||||
|
<a routerLink="/channelz/subchannel" routerLinkActive="active">Subchannel</a>
|
||||||
|
<a routerLink="/channelz/socket" routerLinkActive="active">Socket</a>
|
||||||
|
<a routerLink="/channelz/help" routerLinkActive="active">Help</a>
|
||||||
|
</nav>
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.css']
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
title = 'Channelz';
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { ServersComponent } from './servers/servers.component';
|
||||||
|
import { SocketComponent } from './socket/socket.component';
|
||||||
|
|
||||||
|
import { ChannelComponent } from './channel/channel.component';
|
||||||
|
import { ChannelzService } from './channelz.service';
|
||||||
|
import { HelpComponent } from './help/help.component';
|
||||||
|
import { JsonPretty, AddrPretty } from './utils';
|
||||||
|
import { ServerSocketsComponent } from './server-sockets/server-sockets.component';
|
||||||
|
import { SubchannelComponent } from './subchannel/subchannel.component';
|
||||||
|
import { TopChannelsComponent } from './top-channels/top-channels.component';
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AppComponent,
|
||||||
|
AddrPretty,
|
||||||
|
ChannelComponent,
|
||||||
|
HelpComponent,
|
||||||
|
JsonPretty,
|
||||||
|
ServerSocketsComponent,
|
||||||
|
ServersComponent,
|
||||||
|
SocketComponent,
|
||||||
|
SubchannelComponent,
|
||||||
|
TopChannelsComponent,
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
AppRoutingModule,
|
||||||
|
BrowserModule,
|
||||||
|
CommonModule,
|
||||||
|
FormsModule,
|
||||||
|
HttpClientModule,
|
||||||
|
],
|
||||||
|
providers: [ChannelzService],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
<h3>Showing channel:</h3>
|
||||||
|
<input #textbox type="text" [(ngModel)]="enteredData" (keyup.enter)="processEntry()" required>
|
||||||
|
<button (click)="processEntry()">Refresh</button>
|
||||||
|
<div>
|
||||||
|
<div *ngIf="channel">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Field</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ChannelRef</td>
|
||||||
|
<td><pre>{{channel['ref']['channelId']}}[{{channel['ref']['name']}}]</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Data</td>
|
||||||
|
<td><pre>{{channel['data'] | jsonpretty}}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Channels</td>
|
||||||
|
<td>
|
||||||
|
<div *ngFor="let ref of channel['channelRef']">
|
||||||
|
<a routerLink="/channelz/channel/{{ref['channelId']}}">{{ref['channelId']}}[{{ref['name']}}]</a>,
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Subchannels</td>
|
||||||
|
<td>
|
||||||
|
<div *ngFor="let ref of channel['subchannelRef']">
|
||||||
|
<a routerLink="/channelz/subchannel/{{ref['subchannelId']}}">{{ref['subchannelId']}}[{{ref['name']}}]</a>,
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Sockets</td>
|
||||||
|
<td>
|
||||||
|
<div *ngFor="let ref of channel['socketRef']">
|
||||||
|
<a routerLink="/channelz/socket/{{ref['socketId']}}">{{ref['socketId']}}[{{ref.name}}]</a>,
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!channel && id">
|
||||||
|
<p>Channel does not exist</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ChannelzService } from '../channelz.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-channel',
|
||||||
|
templateUrl: './channel.component.html',
|
||||||
|
styleUrls: ['./channel.component.css']
|
||||||
|
})
|
||||||
|
export class ChannelComponent implements OnInit {
|
||||||
|
enteredData: string = "0";
|
||||||
|
channel: any;
|
||||||
|
id: number = 0;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private channelzService: ChannelzService) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.render();
|
||||||
|
this.route.params.subscribe(e => this.render());
|
||||||
|
}
|
||||||
|
|
||||||
|
processEntry(): void {
|
||||||
|
this.router.navigateByUrl('/channelz/channel/' + this.enteredData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private render(): void {
|
||||||
|
const idParam = this.route.snapshot.paramMap.get('id');
|
||||||
|
this.id = idParam == null ? 0 : +idParam;
|
||||||
|
this.enteredData = this.id.toString();
|
||||||
|
this.channelzService.getChannel(this.id)
|
||||||
|
.subscribe((response: any) => this.handleResponse(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleResponse(resp: any): void {
|
||||||
|
this.channel = resp['channel'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
import { Observable } from "rxjs";
|
||||||
|
import { HttpClient } from "@angular/common/http";
|
||||||
|
import { map } from "rxjs/operators";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ChannelzService {
|
||||||
|
baseUrl = "/grpcz_internal";
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
|
private makeUrl(method: string, req: {}): string {
|
||||||
|
const encodedMethod = encodeURIComponent(method);
|
||||||
|
const encodedReq = encodeURIComponent(JSON.stringify(req));
|
||||||
|
return `${this.baseUrl}?full_method_name=${encodedMethod}&request=${encodedReq}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelper(url: string) {
|
||||||
|
console.log("getting: " + url);
|
||||||
|
return this.http.get(url, {responseType: "text"})
|
||||||
|
.pipe(map((buf: string) => {
|
||||||
|
console.log(`Received: ${buf}`);
|
||||||
|
// TODO: only parse if 200, otherwise put error into UI
|
||||||
|
const json = JSON.parse(buf);
|
||||||
|
console.log(`Parsed into: ${json}`);
|
||||||
|
return json;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
getServers(startId: number): Observable<{}> {
|
||||||
|
const url = this.makeUrl(
|
||||||
|
"grpc.channelz.v1.Channelz/GetServers", {"startServerId": startId});
|
||||||
|
return this.getHelper(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
getServerSockets(serverId: number, startId: number): Observable<{}> {
|
||||||
|
const url = this.makeUrl(
|
||||||
|
"grpc.channelz.v1.Channelz/GetServerSockets",
|
||||||
|
{"serverId": serverId, "startSocketId": startId});
|
||||||
|
return this.getHelper(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTopChannels(startId: number): Observable<{}> {
|
||||||
|
const url = this.makeUrl(
|
||||||
|
"grpc.channelz.v1.Channelz/GetTopChannels", {"startChannelId": startId});
|
||||||
|
return this.getHelper(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSubchannel(id: number): Observable<{}> {
|
||||||
|
const url = this.makeUrl(
|
||||||
|
"grpc.channelz.v1.Channelz/GetSubchannel", {"subchannelId": id});
|
||||||
|
return this.getHelper(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
getChannel(id: number): Observable<{}> {
|
||||||
|
const url = this.makeUrl(
|
||||||
|
"grpc.channelz.v1.Channelz/GetChannel", {"channelId": id});
|
||||||
|
return this.getHelper(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSocket(id: number): Observable<{}> {
|
||||||
|
const url = this.makeUrl(
|
||||||
|
"grpc.channelz.v1.Channelz/GetSocket", {"socketId": id});
|
||||||
|
return this.getHelper(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div>
|
||||||
|
<h2>Java notes:</h2>
|
||||||
|
<ul>
|
||||||
|
<li>InProcessTransport is not a real socket, so in process servers and channels will
|
||||||
|
not provide socket level stats. If you try to load an InProcesTransport, channelz will
|
||||||
|
report that the socket is not found. This is normal. Use the provided channel, subchannel, or
|
||||||
|
server level stats instead.</li>
|
||||||
|
<li>Not all stats specified by channelz.proto are exported yet, but they will be soon.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-help',
|
||||||
|
templateUrl: './help.component.html',
|
||||||
|
styleUrls: ['./help.component.css']
|
||||||
|
})
|
||||||
|
export class HelpComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<h3>Showing server sockets starting from:</h3>
|
||||||
|
Server id:
|
||||||
|
<input #serverIdTextBox type="text" [(ngModel)]="serverId" (keyup.enter)="processEntry()" required>
|
||||||
|
Starting socket:
|
||||||
|
<input #socketStartIdTextBox type="text" [(ngModel)]="socketStartId" (keyup.enter)="processEntry()" required>
|
||||||
|
<button (click)="processEntry()">Refresh</button>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Sockets</th>
|
||||||
|
</tr>
|
||||||
|
<tr *ngFor="let s of sockets">
|
||||||
|
<td>
|
||||||
|
<a routerLink="/channelz/socket/{{s['socketId']}}">{{s['socketId']}}[{{s['name']}}]</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="nextSocketId">
|
||||||
|
<a routerLink="/channelz/serversockets/{{serverId}}/{{nextSocketId}}">Click here for next page</a>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!nextSocketId">
|
||||||
|
<p>End of results</p>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ChannelzService } from '../channelz.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-server-sockets',
|
||||||
|
templateUrl: './server-sockets.component.html',
|
||||||
|
styleUrls: ['./server-sockets.component.css']
|
||||||
|
})
|
||||||
|
export class ServerSocketsComponent implements OnInit {
|
||||||
|
sockets: any[];
|
||||||
|
serverId: number;
|
||||||
|
socketStartId: number;
|
||||||
|
nextSocketId: number;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private channelzService: ChannelzService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.render();
|
||||||
|
this.route.params.subscribe(e => this.render());
|
||||||
|
}
|
||||||
|
|
||||||
|
processEntry(): void {
|
||||||
|
this.router.navigateByUrl(`/channelz/serversockets/${this.serverId}/${this.socketStartId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private render(): void {
|
||||||
|
const serverIdParam = this.route.snapshot.paramMap.get('serverId');
|
||||||
|
this.serverId = serverIdParam == null ? 0 : +serverIdParam;
|
||||||
|
const socketStartIdParam = this.route.snapshot.paramMap.get('socketStartId');
|
||||||
|
this.socketStartId = socketStartIdParam == null ? 0 : +socketStartIdParam;
|
||||||
|
this.channelzService.getServerSockets(this.serverId, this.socketStartId)
|
||||||
|
.subscribe((resp: any) => this.handleResponse(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleResponse(resp: any): void {
|
||||||
|
this.sockets = resp['socketRef'];
|
||||||
|
if (!resp['end']) {
|
||||||
|
const last = this.sockets[this.sockets.length - 1];
|
||||||
|
this.nextSocketId = last['socketId'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
<h3>Showing servers starting from:</h3>
|
||||||
|
Server id:
|
||||||
|
<input #textbox type="text" [(ngModel)]="startId" (keyup.enter)="processEntry()" required>
|
||||||
|
<button (click)="processEntry()">Refresh</button>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Server</th>
|
||||||
|
<th>Calls started</th>
|
||||||
|
<th>Calls succeeded</th>
|
||||||
|
<th>Calls failed</th>
|
||||||
|
<th>Last call started ts</th>
|
||||||
|
<th>Listen Sockets</th>
|
||||||
|
</tr>
|
||||||
|
<tr *ngFor="let server of serversList">
|
||||||
|
<td><a routerLink="/channelz/serversockets/{{server['ref']['serverId']}}">{{server['ref']['serverId']}}[{{server['ref']['name']}}]</a></td>
|
||||||
|
<td>{{server['data']['callsStarted']}}</td>
|
||||||
|
<td>{{server['data']['callsSucceeded']}}</td>
|
||||||
|
<td>{{server['data']['callsFailed']}}</td>
|
||||||
|
<td>{{server['data']['lastCallStartedTimestamp'] | json}}</td>
|
||||||
|
<td>
|
||||||
|
<div *ngFor="let lsock of server['listenSocket']">
|
||||||
|
<a routerLink="/channelz/socket/{{lsock['socketId']}}">{{lsock['socketId']}}[{{lsock['name']}}]</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="nextId">
|
||||||
|
<a routerLink="/channelz/servers/{{nextId}}">Click here for next page</a>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!nextId">
|
||||||
|
<p>End of results</p>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
|
import { ChannelzService } from '../channelz.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-servers',
|
||||||
|
templateUrl: './servers.component.html',
|
||||||
|
styleUrls: ['./servers.component.css']
|
||||||
|
})
|
||||||
|
export class ServersComponent implements OnInit {
|
||||||
|
startId: number = 0;
|
||||||
|
serversList: any[];
|
||||||
|
nextId: string;
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private channelzService: ChannelzService) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.render();
|
||||||
|
this.route.params.subscribe(e => this.render());
|
||||||
|
}
|
||||||
|
|
||||||
|
processEntry(): void {
|
||||||
|
this.router.navigateByUrl(`/channelz/servers/${this.startId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private render(): void {
|
||||||
|
const startIdParam = this.route.snapshot.paramMap.get('startId');
|
||||||
|
this.startId = startIdParam == null ? 0 : +startIdParam;
|
||||||
|
this.channelzService.getServers(this.startId)
|
||||||
|
.subscribe((resp: any) => this.handleResponse(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleResponse(resp: any): void {
|
||||||
|
this.serversList = resp['server'];
|
||||||
|
if (!resp['end']) {
|
||||||
|
const last = this.serversList[this.serversList.length - 1];
|
||||||
|
this.nextId = last['ref']['serverId'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<h3>Showing socket:</h3>
|
||||||
|
<input #textbox type="text" [(ngModel)]="enteredData" (keyup.enter)="processEntry()" required>
|
||||||
|
<button (click)="processEntry()">Refresh</button>
|
||||||
|
<div>
|
||||||
|
<div *ngIf="socket">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Field</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SocketRef</td>
|
||||||
|
<td><pre>{{socket['ref']['socketId']}}[{{socket['ref']['name']}}]</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Local Address</td>
|
||||||
|
<td><pre>{{socket['local'] | addrpretty}}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Remote Address</td>
|
||||||
|
<td><pre>{{socket['remote'] | addrpretty}}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Security</td>
|
||||||
|
<td><pre>{{socket['security'] | jsonpretty}}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Data</td>
|
||||||
|
<td><pre>{{simplifiedData | jsonpretty}}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr *ngFor="let opt of socketOptions()">
|
||||||
|
<td>Socket Option: {{opt['name']}}</td>
|
||||||
|
<!-- opt is an typescript object, and for some reason, bracket notation does not work here -->
|
||||||
|
<td><pre>{{opt.value | jsonpretty}}</pre></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!socket">
|
||||||
|
<p>Socket does not exist</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ChannelzService } from '../channelz.service';
|
||||||
|
import { JsonPretty } from '../utils'
|
||||||
|
|
||||||
|
export class SocketOpt {
|
||||||
|
constructor(public name: string, public value: string) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-socket',
|
||||||
|
templateUrl: './socket.component.html',
|
||||||
|
styleUrls: ['./socket.component.css']
|
||||||
|
})
|
||||||
|
export class SocketComponent implements OnInit {
|
||||||
|
enteredData: string;
|
||||||
|
socket: any;
|
||||||
|
id: number;
|
||||||
|
simplifiedData: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private channelzService: ChannelzService) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.render();
|
||||||
|
this.route.params.subscribe(e => this.render());
|
||||||
|
}
|
||||||
|
|
||||||
|
processEntry(): void {
|
||||||
|
this.router.navigateByUrl(`/channelz/socket/${this.enteredData}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private render(): void {
|
||||||
|
const idParam = this.route.snapshot.paramMap.get('id');
|
||||||
|
this.id = idParam == null ? 0 : +idParam;
|
||||||
|
this.enteredData = this.id.toString();
|
||||||
|
this.channelzService.getSocket(+this.id)
|
||||||
|
.subscribe((response: any) => this.handleResponse(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleResponse(socketResponse: any): void {
|
||||||
|
this.socket = socketResponse['socket'];
|
||||||
|
this.simplifiedData = this.simplifiedDataHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of the socket data, but with socket options removed.
|
||||||
|
*/
|
||||||
|
simplifiedDataHelper(): any {
|
||||||
|
if (this.socket['data'] == null) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const copy: any = JSON.parse(JSON.stringify(this.socket.data));
|
||||||
|
copy['option'] = null;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
socketOptions(): SocketOpt[] {
|
||||||
|
if (this.socket['data'] == null || this.socket['data']['option'] == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return this.socket['data']['option'].map((opt: any) => {
|
||||||
|
// value OR additional is set
|
||||||
|
if (opt['value']) {
|
||||||
|
return new SocketOpt(opt['name'], opt['value']);
|
||||||
|
} else {
|
||||||
|
return new SocketOpt(opt['name'], opt['additional']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
<h3>Showing subchannel:</h3>
|
||||||
|
<input #textbox type="text" [(ngModel)]="enteredData" (keyup.enter)="processEntry()" required>
|
||||||
|
<button (click)="processEntry()">Refresh</button>
|
||||||
|
<div>
|
||||||
|
<div *ngIf="subchannel">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Field</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SubchannelRef</td>
|
||||||
|
<td><pre>{{subchannel['ref']['subchannelId']}}[{{subchannel['ref']['name']}}]</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Data</td>
|
||||||
|
<td><pre>{{subchannel['data'] | jsonpretty}}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Channels</td>
|
||||||
|
<td>
|
||||||
|
<div *ngFor="let ref of subchannel['channelRef']">
|
||||||
|
<a routerLink="/channelz/channel/{{ref['channelId']}}">{{ref['channelId']}}[{{ref['name']}}]</a>,
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Subchannels</td>
|
||||||
|
<td>
|
||||||
|
<div *ngFor="let ref of subchannel['subchannelRef']">
|
||||||
|
<a routerLink="/channelz/subchannel/{{ref['channelId']}}">{{ref['subchannelId']}}[{{ref['name']}}]</a>,
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Sockets</td>
|
||||||
|
<td>
|
||||||
|
<div *ngFor="let ref of subchannel['socketRef']">
|
||||||
|
<a routerLink="/channelz/socket/{{ref['socketId']}}">{{ref['socketId']}}[{{ref['name']}}]</a>,
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!subchannel && id">
|
||||||
|
<p>Subchannel does not exist</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ChannelzService } from '../channelz.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-subchannel',
|
||||||
|
templateUrl: './subchannel.component.html',
|
||||||
|
styleUrls: ['./subchannel.component.css']
|
||||||
|
})
|
||||||
|
export class SubchannelComponent implements OnInit {
|
||||||
|
enteredData: string;
|
||||||
|
subchannel: any;
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private channelzService: ChannelzService) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.render();
|
||||||
|
this.route.params.subscribe(e => this.render());
|
||||||
|
}
|
||||||
|
|
||||||
|
processEntry(): void {
|
||||||
|
this.router.navigateByUrl('/channelz/subchannel/' + this.enteredData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private render(): void {
|
||||||
|
const idParam = this.route.snapshot.paramMap.get('id');
|
||||||
|
this.id = idParam == null ? 0 : +idParam;
|
||||||
|
this.enteredData = this.id.toString();
|
||||||
|
this.channelzService.getSubchannel(this.id)
|
||||||
|
.subscribe((response: any) => this.handleResponse(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleResponse(resp: any): void {
|
||||||
|
this.subchannel = resp['subchannel'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<h3>Showing top level channels starting from:</h3>
|
||||||
|
<input #textbox type="text" [(ngModel)]="startId" (keyup.enter)="processEntry()" required>
|
||||||
|
<button (click)="processEntry()">Refresh</button>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Channel</th>
|
||||||
|
<th>Data</th>
|
||||||
|
<th>Channels</th>
|
||||||
|
<th>Subchannels</th>
|
||||||
|
<th>Sockets</th>
|
||||||
|
</tr>
|
||||||
|
<tr *ngFor="let c of topChannelsList">
|
||||||
|
<td>{{c['ref']['channelId']}}[{{c['ref']['name']}}]</td>
|
||||||
|
<td><pre>{{c.data | jsonpretty}}</pre></td>
|
||||||
|
<td>
|
||||||
|
<div *ngFor="let ref of c['channelRef']">
|
||||||
|
<a routerLink="/channelz/channel/{{ref['channelId']}}">{{ref['channelId']}}[{{ref['name']}}]</a>,
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div *ngFor="let ref of c['subchannelRef']">
|
||||||
|
<a routerLink="/channelz/subchannel/{{ref['subchannelId']}}">{{ref['subchannelId']}}[{{ref['name']}}]</a>,
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div *ngFor="let ref of c['socketRef']">
|
||||||
|
<a routerLink="/channelz/socket/{{ref['socketId']}}">{{ref['socketId']}}[{{ref['name']}}]</a>,
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="nextId">
|
||||||
|
<a routerLink="/channelz/topchannels/{{nextId}}">Click here for next page</a>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!nextId">
|
||||||
|
<p>End of results</p>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ChannelzService } from '../channelz.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-top-channels',
|
||||||
|
templateUrl: './top-channels.component.html',
|
||||||
|
styleUrls: ['./top-channels.component.css']
|
||||||
|
})
|
||||||
|
export class TopChannelsComponent implements OnInit {
|
||||||
|
startId: number = 0;
|
||||||
|
topChannelsList: any[];
|
||||||
|
nextId:number;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private channelzService: ChannelzService) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.render();
|
||||||
|
this.route.params.subscribe(e => this.render());
|
||||||
|
}
|
||||||
|
|
||||||
|
processEntry(): void {
|
||||||
|
this.router.navigateByUrl(`/channelz/topchannels/${this.startId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
private render(): void {
|
||||||
|
const startIdParam = this.route.snapshot.paramMap.get('startId');
|
||||||
|
this.startId = startIdParam == null ? 0 : +startIdParam;
|
||||||
|
this.channelzService.getTopChannels(this.startId)
|
||||||
|
.subscribe((resp: any) => this.handleResponse(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleResponse(resp: any): void {
|
||||||
|
this.topChannelsList = resp['channel'];
|
||||||
|
if (!resp['end']) {
|
||||||
|
const last = this.topChannelsList[this.topChannelsList.length - 1];
|
||||||
|
this.nextId = last['ref']['channelId'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* @license
|
||||||
|
* Copyright 2018, gRPC Authors All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
|
@Pipe({name: 'jsonpretty'})
|
||||||
|
export class JsonPretty implements PipeTransform {
|
||||||
|
transform(value: any): string {
|
||||||
|
return JsonPretty.transform(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static transform(value: any): string {
|
||||||
|
if (value == null) {
|
||||||
|
return "NULL";
|
||||||
|
}
|
||||||
|
return JSON.stringify(value, null, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Pipe({name: 'addrpretty'})
|
||||||
|
export class AddrPretty implements PipeTransform {
|
||||||
|
transform(value: any): string {
|
||||||
|
return AddrPretty.transform(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static transform(addr: {}): string {
|
||||||
|
if (addr['tcpipAddress'] == null) {
|
||||||
|
return JsonPretty.transform(addr);
|
||||||
|
}
|
||||||
|
const copy = JSON.parse(JSON.stringify(addr));
|
||||||
|
const tcpIp = copy['tcpipAddress'];
|
||||||
|
const ipAddress = tcpIp['ipAddress'];
|
||||||
|
const binary = atob(ipAddress);
|
||||||
|
const addressLen = binary.length;
|
||||||
|
if (binary.length === 4) {
|
||||||
|
// ipv4: turn bytes into decimal form
|
||||||
|
tcpIp['ipAddress'] = binary
|
||||||
|
.split("")
|
||||||
|
.map((c: string) => c.charCodeAt(0))
|
||||||
|
.join(".");
|
||||||
|
} else if (binary.length === 16) {
|
||||||
|
// ipv6: turn bytes into hex, pad with a 0 so always 2 digits long
|
||||||
|
const hex = binary.split("")
|
||||||
|
.map((c: string) => ("0" + c.charCodeAt(0).toString(16)).substr(-2))
|
||||||
|
.join("");
|
||||||
|
// use regex to split into 4 character chunks
|
||||||
|
tcpIp['ipAddress'] = hex.match(/..../g).join(":");
|
||||||
|
}
|
||||||
|
return JsonPretty.transform(copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,412 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package grpc.channelz;
|
||||||
|
|
||||||
|
import "google/protobuf/any.proto";
|
||||||
|
import "google/protobuf/duration.proto";
|
||||||
|
import "google/protobuf/timestamp.proto";
|
||||||
|
import "google/protobuf/wrappers.proto";
|
||||||
|
|
||||||
|
option java_multiple_files = true;
|
||||||
|
option java_package = "io.grpc.channelz.v1";
|
||||||
|
option java_outer_classname = "ChannelzProto";
|
||||||
|
|
||||||
|
// Channel is a logical grouping of channels, subchannels, and sockets.
|
||||||
|
message Channel {
|
||||||
|
// The identifier for this channel.
|
||||||
|
ChannelRef ref = 1;
|
||||||
|
// Data specific to this channel.
|
||||||
|
ChannelData data = 2;
|
||||||
|
// At most one of 'channel_ref+subchannel_ref' and 'socket' is set.
|
||||||
|
|
||||||
|
// There are no ordering guarantees on the order of channel refs.
|
||||||
|
// There may not be cycles in the ref graph.
|
||||||
|
// A channel ref may be present in more than one channel or subchannel.
|
||||||
|
repeated ChannelRef channel_ref = 3;
|
||||||
|
|
||||||
|
// At most one of 'channel_ref+subchannel_ref' and 'socket' is set.
|
||||||
|
// There are no ordering guarantees on the order of subchannel refs.
|
||||||
|
// There may not be cycles in the ref graph.
|
||||||
|
// A sub channel ref may be present in more than one channel or subchannel.
|
||||||
|
repeated SubchannelRef subchannel_ref = 4;
|
||||||
|
|
||||||
|
// There are no ordering guarantees on the order of sockets.
|
||||||
|
repeated SocketRef socket_ref = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subchannel is a logical grouping of channels, subchannels, and sockets.
|
||||||
|
// A subchannel is load balanced over by it's ancestor
|
||||||
|
message Subchannel {
|
||||||
|
// The identifier for this channel.
|
||||||
|
SubchannelRef ref = 1;
|
||||||
|
// Data specific to this channel.
|
||||||
|
ChannelData data = 2;
|
||||||
|
// At most one of 'channel_ref+subchannel_ref' and 'socket' is set.
|
||||||
|
|
||||||
|
// There are no ordering guarantees on the order of channel refs.
|
||||||
|
// There may not be cycles in the ref graph.
|
||||||
|
// A channel ref may be present in more than one channel or subchannel.
|
||||||
|
repeated ChannelRef channel_ref = 3;
|
||||||
|
|
||||||
|
// At most one of 'channel_ref+subchannel_ref' and 'socket' is set.
|
||||||
|
// There are no ordering guarantees on the order of subchannel refs.
|
||||||
|
// There may not be cycles in the ref graph.
|
||||||
|
// A sub channel ref may be present in more than one channel or subchannel.
|
||||||
|
repeated SubchannelRef subchannel_ref = 4;
|
||||||
|
|
||||||
|
// There are no ordering guarantees on the order of sockets.
|
||||||
|
repeated SocketRef socket_ref = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ChannelData {
|
||||||
|
enum State {
|
||||||
|
UNKNOWN = 0;
|
||||||
|
IDLE = 1;
|
||||||
|
CONNECTING = 2;
|
||||||
|
READY = 3;
|
||||||
|
TRANSIENT_FAILURE = 4;
|
||||||
|
SHUTDOWN = 5;
|
||||||
|
}
|
||||||
|
State state = 1;
|
||||||
|
|
||||||
|
// The target this channel originally tried to connect to. May be absent
|
||||||
|
string target = 2;
|
||||||
|
|
||||||
|
ChannelTrace trace = 3;
|
||||||
|
|
||||||
|
// The number of calls started on the channel
|
||||||
|
int64 calls_started = 4;
|
||||||
|
// The number of calls that have completed with an OK status
|
||||||
|
int64 calls_succeeded = 5;
|
||||||
|
// The number of calls that have a completed with a non-OK status
|
||||||
|
int64 calls_failed = 6;
|
||||||
|
|
||||||
|
// The last time a call was started on the channel.
|
||||||
|
google.protobuf.Timestamp last_call_started_timestamp = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ChannelTrace {
|
||||||
|
// TODO: fill this in.
|
||||||
|
}
|
||||||
|
|
||||||
|
message ChannelRef {
|
||||||
|
// The globally unique id for this channel. Must be a positive number.
|
||||||
|
int64 channel_id = 1;
|
||||||
|
// An optional name associated with the channel.
|
||||||
|
string name = 2;
|
||||||
|
// Intentionally don't use field numbers from other refs.
|
||||||
|
reserved 3, 4, 5, 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubchannelRef {
|
||||||
|
// The globally unique id for this subchannel. Must be a positive number.
|
||||||
|
int64 subchannel_id = 7;
|
||||||
|
// An optional name associated with the subchannel.
|
||||||
|
string name = 8;
|
||||||
|
// Intentionally don't use field numbers from other refs.
|
||||||
|
reserved 1, 2, 3, 4, 5, 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SocketRef {
|
||||||
|
int64 socket_id = 3;
|
||||||
|
// An optional name associated with the socket.
|
||||||
|
string name = 4;
|
||||||
|
// Intentionally don't use field numbers from other refs.
|
||||||
|
reserved 1, 2, 5, 6, 7, 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ServerRef {
|
||||||
|
// A globally unique identifier for this server. Must be a positive number.
|
||||||
|
int64 server_id = 5;
|
||||||
|
// An optional name associated with the server.
|
||||||
|
string name = 6;
|
||||||
|
// Intentionally don't use field numbers from other refs.
|
||||||
|
reserved 1, 2, 3, 4, 7, 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Server {
|
||||||
|
ServerRef ref = 1;
|
||||||
|
ServerData data = 2;
|
||||||
|
|
||||||
|
// The sockets that the server is listening on. There are no ordering
|
||||||
|
// guarantees.
|
||||||
|
repeated SocketRef listen_socket = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ServerData {
|
||||||
|
ServerChannelTrace trace = 1;
|
||||||
|
|
||||||
|
// The number of incoming calls started on the server
|
||||||
|
int64 calls_started = 2;
|
||||||
|
// The number of incoming calls that have completed with an OK status
|
||||||
|
int64 calls_succeeded = 3;
|
||||||
|
// The number of incoming calls that have a completed with a non-OK status
|
||||||
|
int64 calls_failed = 4;
|
||||||
|
|
||||||
|
// The last time a call was started on the server.
|
||||||
|
google.protobuf.Timestamp last_call_started_timestamp = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ServerChannelTrace {
|
||||||
|
// TODO: fill this in.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Information about an actual connection. Pronounced "sock-ay".
|
||||||
|
message Socket {
|
||||||
|
SocketRef ref = 1;
|
||||||
|
|
||||||
|
SocketData data = 2;
|
||||||
|
// The locally bound address.
|
||||||
|
Address local = 3;
|
||||||
|
// The remote bound address. May be absent.
|
||||||
|
Address remote = 4;
|
||||||
|
Security security = 5;
|
||||||
|
|
||||||
|
// Optional, represents the name of the remote endpoint, if different than
|
||||||
|
// the original target name.
|
||||||
|
string remote_name = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SocketData {
|
||||||
|
// The number of streams that have been started.
|
||||||
|
int64 streams_started = 1;
|
||||||
|
// The number of streams that have ended successfully with the EoS bit set for
|
||||||
|
// both end points
|
||||||
|
int64 streams_succeeded = 2;
|
||||||
|
// The number of incoming streams that have a completed with a non-OK status
|
||||||
|
int64 streams_failed = 3;
|
||||||
|
|
||||||
|
// The number of messages successfully sent on this socket.
|
||||||
|
int64 messages_sent = 4;
|
||||||
|
int64 messages_received = 5;
|
||||||
|
|
||||||
|
// The number of keep alives sent. This is typically implemented with HTTP/2
|
||||||
|
// ping messages.
|
||||||
|
int64 keep_alives_sent = 6;
|
||||||
|
|
||||||
|
// The last time a stream was created by this endpoint. Usually unset for
|
||||||
|
// servers.
|
||||||
|
google.protobuf.Timestamp last_local_stream_created_timestamp = 7;
|
||||||
|
// The last time a stream was created by the remote endpoint. Usually unset
|
||||||
|
// for clients.
|
||||||
|
google.protobuf.Timestamp last_remote_stream_created_timestamp = 8;
|
||||||
|
|
||||||
|
// The last time a message was sent by this endpoint.
|
||||||
|
google.protobuf.Timestamp last_message_sent_timestamp = 9;
|
||||||
|
// The last time a message was received by this endpoint.
|
||||||
|
google.protobuf.Timestamp last_message_received_timestamp = 10;
|
||||||
|
|
||||||
|
// The amount of window, granted to the local endpoint by the remote endpoint.
|
||||||
|
// This may be slightly out of date due to network latency. This does NOT
|
||||||
|
// include stream level or TCP level flow control info.
|
||||||
|
google.protobuf.Int64Value local_flow_control_window = 11;
|
||||||
|
|
||||||
|
// The amount of window, granted to the remote endpoint by the local endpoint.
|
||||||
|
// This may be slightly out of date due to network latency. This does NOT
|
||||||
|
// include stream level or TCP level flow control info.
|
||||||
|
google.protobuf.Int64Value remote_flow_control_window = 12;
|
||||||
|
|
||||||
|
repeated SocketOption option = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Address {
|
||||||
|
message TcpIpAddress {
|
||||||
|
// Either the IPv4 or IPv6 address in bytes. Will either be 4 bytes or 16
|
||||||
|
// bytes in length.
|
||||||
|
bytes ip_address = 1;
|
||||||
|
// 0-64k, or -1 if not appropriate.
|
||||||
|
int32 port = 2;
|
||||||
|
}
|
||||||
|
// A Unix Domain Socket address.
|
||||||
|
message UdsAddress {
|
||||||
|
string filename = 1;
|
||||||
|
}
|
||||||
|
// An address type not included above.
|
||||||
|
message OtherAddress {
|
||||||
|
// The human readable version of the value.
|
||||||
|
string name = 1;
|
||||||
|
// The actual address message.
|
||||||
|
google.protobuf.Any value = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
oneof address {
|
||||||
|
TcpIpAddress tcpip_address = 1;
|
||||||
|
UdsAddress uds_address = 2;
|
||||||
|
OtherAddress other_address = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Security {
|
||||||
|
message Tls {
|
||||||
|
oneof cipher_suite {
|
||||||
|
// The cipher suite name in the RFC 4346 format:
|
||||||
|
// https://tools.ietf.org/html/rfc4346#appendix-C
|
||||||
|
string standard_name = 1;
|
||||||
|
// Some other way to describe the cipher suite if
|
||||||
|
// the RFC 4346 name is not available.
|
||||||
|
string other_name = 2;
|
||||||
|
}
|
||||||
|
// the certificate used by this endpoint.
|
||||||
|
bytes local_certificate = 3;
|
||||||
|
// the certificate used by the remote endpoint.
|
||||||
|
bytes remote_certificate = 4;
|
||||||
|
}
|
||||||
|
message OtherSecurity {
|
||||||
|
// The human readable version of the value.
|
||||||
|
string name = 1;
|
||||||
|
// The actual security details message.
|
||||||
|
google.protobuf.Any value = 2;
|
||||||
|
}
|
||||||
|
oneof model {
|
||||||
|
Tls tls = 1;
|
||||||
|
OtherSecurity other = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message SocketOption {
|
||||||
|
string name = 1;
|
||||||
|
// The human readable value of this socket option. At least one of value or
|
||||||
|
// additional will be set.
|
||||||
|
string value = 2;
|
||||||
|
// Additional data associated with the socket option. At least one of value
|
||||||
|
// or additional will be set.
|
||||||
|
google.protobuf.Any additional = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For use with SocketOption's additional field. This is primarily used for
|
||||||
|
// SO_RCVTIMEO and SO_SNDTIMEO
|
||||||
|
message SocketOptionTimeout {
|
||||||
|
google.protobuf.Duration duration = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SocketOptionLinger {
|
||||||
|
bool active = 1;
|
||||||
|
google.protobuf.Duration duration = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tcp info for SOL_TCP, TCP_INFO
|
||||||
|
message SocketOptionTcpInfo {
|
||||||
|
uint32 tcpi_state = 1;
|
||||||
|
|
||||||
|
uint32 tcpi_ca_state = 2;
|
||||||
|
uint32 tcpi_retransmits = 3;
|
||||||
|
uint32 tcpi_probes = 4;
|
||||||
|
uint32 tcpi_backoff = 5;
|
||||||
|
uint32 tcpi_options = 6;
|
||||||
|
uint32 tcpi_snd_wscale = 7;
|
||||||
|
uint32 tcpi_rcv_wscale = 8;
|
||||||
|
|
||||||
|
uint32 tcpi_rto = 9;
|
||||||
|
uint32 tcpi_ato = 10;
|
||||||
|
uint32 tcpi_snd_mss = 11;
|
||||||
|
uint32 tcpi_rcv_mss = 12;
|
||||||
|
|
||||||
|
uint32 tcpi_unacked = 13;
|
||||||
|
uint32 tcpi_sacked = 14;
|
||||||
|
uint32 tcpi_lost = 15;
|
||||||
|
uint32 tcpi_retrans = 16;
|
||||||
|
uint32 tcpi_fackets = 17;
|
||||||
|
|
||||||
|
uint32 tcpi_last_data_sent = 18;
|
||||||
|
uint32 tcpi_last_ack_sent = 19;
|
||||||
|
uint32 tcpi_last_data_recv = 20;
|
||||||
|
uint32 tcpi_last_ack_recv = 21;
|
||||||
|
|
||||||
|
uint32 tcpi_pmtu = 22;
|
||||||
|
uint32 tcpi_rcv_ssthresh = 23;
|
||||||
|
uint32 tcpi_rtt = 24;
|
||||||
|
uint32 tcpi_rttvar = 25;
|
||||||
|
uint32 tcpi_snd_ssthresh = 26;
|
||||||
|
uint32 tcpi_snd_cwnd = 27;
|
||||||
|
uint32 tcpi_advmss = 28;
|
||||||
|
uint32 tcpi_reordering = 29;
|
||||||
|
}
|
||||||
|
|
||||||
|
service Channelz {
|
||||||
|
// Gets all root channels (e.g. channels the application has directly
|
||||||
|
// created). This does not include subchannels nor non-top level channels.
|
||||||
|
rpc GetTopChannels(GetTopChannelsRequest) returns (GetTopChannelsResponse);
|
||||||
|
// Gets all servers that exist in the process.
|
||||||
|
rpc GetServers(GetServersRequest) returns (GetServersResponse);
|
||||||
|
// Gets all server sockets that exist in the process.
|
||||||
|
rpc GetServerSockets(GetServerSocketsRequest) returns (GetServerSocketsResponse);
|
||||||
|
// Returns a single Channel, or else a NOT_FOUND code.
|
||||||
|
rpc GetChannel(GetChannelRequest) returns (GetChannelResponse);
|
||||||
|
// Returns a single Subchannel, or else a NOT_FOUND code.
|
||||||
|
rpc GetSubchannel(GetSubchannelRequest) returns (GetSubchannelResponse);
|
||||||
|
// Returns a single Socket or else a NOT_FOUND code.
|
||||||
|
rpc GetSocket(GetSocketRequest) returns (GetSocketResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetServersRequest {
|
||||||
|
// start_server_id indicates that only servers at or above this id should be
|
||||||
|
// included in the results.
|
||||||
|
int64 start_server_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetServersResponse {
|
||||||
|
// list of servers that the connection detail service knows about. Sorted in
|
||||||
|
// ascending server_id order.
|
||||||
|
repeated Server server = 1;
|
||||||
|
// If set, indicates that the list of servers is the final list. Requesting
|
||||||
|
// more servers will only return more if they are created after this RPC
|
||||||
|
// completes.
|
||||||
|
bool end = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetServerSocketsRequest {
|
||||||
|
int64 server_id = 1;
|
||||||
|
// start_socket_id indicates that only sockets at or above this id should be
|
||||||
|
// included in the results.
|
||||||
|
int64 start_socket_id = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetServerSocketsResponse {
|
||||||
|
// list of socket refs that the connection detail service knows about. Sorted in
|
||||||
|
// ascending socket_id order.
|
||||||
|
repeated SocketRef socket_ref = 1;
|
||||||
|
// If set, indicates that the list of sockets is the final list. Requesting
|
||||||
|
// more sockets will only return more if they are created after this RPC
|
||||||
|
// completes.
|
||||||
|
bool end = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetTopChannelsRequest {
|
||||||
|
// start_channel_id indicates that only channels at or above this id should be
|
||||||
|
// included in the results.
|
||||||
|
int64 start_channel_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetTopChannelsResponse {
|
||||||
|
// list of channels that the connection detail service knows about. Sorted in
|
||||||
|
// ascending channel_id order.
|
||||||
|
repeated Channel channel = 1;
|
||||||
|
// If set, indicates that the list of channels is the final list. Requesting
|
||||||
|
// more channels can only return more if they are created after this RPC
|
||||||
|
// completes.
|
||||||
|
bool end = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetChannelRequest {
|
||||||
|
int64 channel_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetChannelResponse {
|
||||||
|
Channel channel = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetSubchannelRequest {
|
||||||
|
int64 subchannel_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetSubchannelResponse {
|
||||||
|
Subchannel subchannel = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetSocketRequest {
|
||||||
|
int64 socket_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetSocketResponse {
|
||||||
|
Socket socket = 1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
export const environment = {
|
||||||
|
production: true
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// The file contents for the current environment will overwrite these during build.
|
||||||
|
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||||
|
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||||
|
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||||
|
|
||||||
|
export const environment = {
|
||||||
|
production: false
|
||||||
|
};
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Channelz</title>
|
||||||
|
<base href="/">
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { enableProdMode } from '@angular/core';
|
||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
import { AppModule } from './app/app.module';
|
||||||
|
import { environment } from './environments/environment';
|
||||||
|
|
||||||
|
if (environment.production) {
|
||||||
|
enableProdMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// this file differs with internal, must use instead:
|
||||||
|
// import { AppModuleNgFactory } from './app/app.module.ngfactory';
|
||||||
|
// platformBrowser().bootstrapModuleFactory(AppModuleNgFactory)
|
||||||
|
// .catch((err: any) => console.log(err));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||||
|
.catch((err: any) => console.log(err));
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
/**
|
||||||
|
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||||
|
* You can add your own extra polyfills to this file.
|
||||||
|
*
|
||||||
|
* This file is divided into 2 sections:
|
||||||
|
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||||
|
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||||
|
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||||
|
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||||
|
*
|
||||||
|
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* BROWSER POLYFILLS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
||||||
|
// import 'core-js/es6/symbol';
|
||||||
|
// import 'core-js/es6/object';
|
||||||
|
// import 'core-js/es6/function';
|
||||||
|
// import 'core-js/es6/parse-int';
|
||||||
|
// import 'core-js/es6/parse-float';
|
||||||
|
// import 'core-js/es6/number';
|
||||||
|
// import 'core-js/es6/math';
|
||||||
|
// import 'core-js/es6/string';
|
||||||
|
// import 'core-js/es6/date';
|
||||||
|
// import 'core-js/es6/array';
|
||||||
|
// import 'core-js/es6/regexp';
|
||||||
|
// import 'core-js/es6/map';
|
||||||
|
// import 'core-js/es6/weak-map';
|
||||||
|
// import 'core-js/es6/set';
|
||||||
|
|
||||||
|
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||||
|
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||||
|
|
||||||
|
/** IE10 and IE11 requires the following for the Reflect API. */
|
||||||
|
// import 'core-js/es6/reflect';
|
||||||
|
|
||||||
|
|
||||||
|
/** Evergreen browsers require these. **/
|
||||||
|
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
|
||||||
|
import 'core-js/es7/reflect';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required to support Web Animations `@angular/platform-browser/animations`.
|
||||||
|
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
|
||||||
|
**/
|
||||||
|
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||||
|
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||||
|
*/
|
||||||
|
|
||||||
|
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||||
|
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||||
|
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||||
|
|
||||||
|
/*
|
||||||
|
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||||
|
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||||
|
*/
|
||||||
|
// (window as any).__Zone_enable_cross_context_check = true;
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* Zone JS is required by default for Angular itself.
|
||||||
|
*/
|
||||||
|
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* APPLICATION IMPORTS
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||||
|
|
||||||
|
import 'zone.js/dist/zone-testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
|
declare const require: any;
|
||||||
|
|
||||||
|
// First, initialize the Angular testing environment.
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting()
|
||||||
|
);
|
||||||
|
// Then we find all the tests.
|
||||||
|
const context = require.context('./', true, /\.spec\.ts$/);
|
||||||
|
// And load the modules.
|
||||||
|
context.keys().map(context);
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../out-tsc/app",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"module": "es2015",
|
||||||
|
"types": ["node"],
|
||||||
|
"typeRoots": [ "../node_modules/@types" ]
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"test.ts",
|
||||||
|
"**/*.spec.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../out-tsc/spec",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"module": "commonjs",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"test.ts",
|
||||||
|
"polyfills.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
/* SystemJS module definition */
|
||||||
|
declare var module: NodeModule;
|
||||||
|
interface NodeModule {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": false,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"target": "es5",
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types"
|
||||||
|
],
|
||||||
|
"lib": [
|
||||||
|
"es2017",
|
||||||
|
"dom"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
{
|
||||||
|
"rulesDirectory": [
|
||||||
|
"node_modules/codelyzer"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"arrow-return-shorthand": true,
|
||||||
|
"callable-types": true,
|
||||||
|
"class-name": true,
|
||||||
|
"comment-format": [
|
||||||
|
true,
|
||||||
|
"check-space"
|
||||||
|
],
|
||||||
|
"curly": true,
|
||||||
|
"deprecation": {
|
||||||
|
"severity": "warn"
|
||||||
|
},
|
||||||
|
"eofline": true,
|
||||||
|
"forin": true,
|
||||||
|
"import-blacklist": [
|
||||||
|
true,
|
||||||
|
"rxjs/Rx"
|
||||||
|
],
|
||||||
|
"import-spacing": true,
|
||||||
|
"indent": [
|
||||||
|
true,
|
||||||
|
"spaces"
|
||||||
|
],
|
||||||
|
"interface-over-type-literal": true,
|
||||||
|
"label-position": true,
|
||||||
|
"max-line-length": [
|
||||||
|
true,
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"member-access": false,
|
||||||
|
"member-ordering": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"order": [
|
||||||
|
"static-field",
|
||||||
|
"instance-field",
|
||||||
|
"static-method",
|
||||||
|
"instance-method"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-arg": true,
|
||||||
|
"no-bitwise": true,
|
||||||
|
"no-console": [
|
||||||
|
true,
|
||||||
|
"debug",
|
||||||
|
"info",
|
||||||
|
"time",
|
||||||
|
"timeEnd",
|
||||||
|
"trace"
|
||||||
|
],
|
||||||
|
"no-construct": true,
|
||||||
|
"no-debugger": true,
|
||||||
|
"no-duplicate-super": true,
|
||||||
|
"no-empty": false,
|
||||||
|
"no-empty-interface": true,
|
||||||
|
"no-eval": true,
|
||||||
|
"no-inferrable-types": [
|
||||||
|
true,
|
||||||
|
"ignore-params"
|
||||||
|
],
|
||||||
|
"no-misused-new": true,
|
||||||
|
"no-non-null-assertion": true,
|
||||||
|
"no-shadowed-variable": true,
|
||||||
|
"no-string-literal": false,
|
||||||
|
"no-string-throw": true,
|
||||||
|
"no-switch-case-fall-through": true,
|
||||||
|
"no-trailing-whitespace": true,
|
||||||
|
"no-unnecessary-initializer": true,
|
||||||
|
"no-unused-expression": true,
|
||||||
|
"no-use-before-declare": true,
|
||||||
|
"no-var-keyword": true,
|
||||||
|
"object-literal-sort-keys": false,
|
||||||
|
"one-line": [
|
||||||
|
true,
|
||||||
|
"check-open-brace",
|
||||||
|
"check-catch",
|
||||||
|
"check-else",
|
||||||
|
"check-whitespace"
|
||||||
|
],
|
||||||
|
"prefer-const": true,
|
||||||
|
"quotemark": [
|
||||||
|
true,
|
||||||
|
"single"
|
||||||
|
],
|
||||||
|
"radix": true,
|
||||||
|
"semicolon": [
|
||||||
|
true,
|
||||||
|
"always"
|
||||||
|
],
|
||||||
|
"triple-equals": [
|
||||||
|
true,
|
||||||
|
"allow-null-check"
|
||||||
|
],
|
||||||
|
"typedef-whitespace": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"call-signature": "nospace",
|
||||||
|
"index-signature": "nospace",
|
||||||
|
"parameter": "nospace",
|
||||||
|
"property-declaration": "nospace",
|
||||||
|
"variable-declaration": "nospace"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"unified-signatures": true,
|
||||||
|
"variable-name": false,
|
||||||
|
"whitespace": [
|
||||||
|
true,
|
||||||
|
"check-branch",
|
||||||
|
"check-decl",
|
||||||
|
"check-operator",
|
||||||
|
"check-separator",
|
||||||
|
"check-type"
|
||||||
|
],
|
||||||
|
"directive-selector": [
|
||||||
|
true,
|
||||||
|
"attribute",
|
||||||
|
"app",
|
||||||
|
"camelCase"
|
||||||
|
],
|
||||||
|
"component-selector": [
|
||||||
|
true,
|
||||||
|
"element",
|
||||||
|
"app",
|
||||||
|
"kebab-case"
|
||||||
|
],
|
||||||
|
"no-output-on-prefix": true,
|
||||||
|
"use-input-property-decorator": true,
|
||||||
|
"use-output-property-decorator": true,
|
||||||
|
"use-host-property-decorator": true,
|
||||||
|
"no-input-rename": true,
|
||||||
|
"no-output-rename": true,
|
||||||
|
"use-life-cycle-interface": true,
|
||||||
|
"use-pipe-transform-interface": true,
|
||||||
|
"component-class-suffix": true,
|
||||||
|
"directive-class-suffix": true
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue