Compare commits
47 Commits
ve_kafka_g
...
v1.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28d985aaf1 | ||
|
|
2397cbf80b | ||
|
|
a13d9daae3 | ||
|
|
c23870e020 | ||
|
|
dd2e29dd40 | ||
|
|
74b5700573 | ||
|
|
ba6abea6d8 | ||
|
|
33b231d512 | ||
|
|
61f0b67a92 | ||
|
|
4b679be310 | ||
|
|
a969795677 | ||
|
|
4f4e7e80fc | ||
|
|
2f72cbb627 | ||
|
|
a460e169ab | ||
|
|
27ce4d6a0d | ||
|
|
ac86f8aded | ||
|
|
93eca239cb | ||
|
|
dc5949d497 | ||
|
|
5e24f6b044 | ||
|
|
0cd31e0545 | ||
|
|
d4dc4b9d0a | ||
|
|
8c6fe40de1 | ||
|
|
e4dc4bae30 | ||
|
|
d99c21f4d7 | ||
|
|
8ef549de80 | ||
|
|
1b57758102 | ||
|
|
553fe30662 | ||
|
|
b6138afe8b | ||
|
|
64d64fe6fe | ||
|
|
f29b356b74 | ||
|
|
b5621d1ffd | ||
|
|
66f0da934d | ||
|
|
13a90fdd57 | ||
|
|
63966887ab | ||
|
|
2865b913af | ||
|
|
893ebdcc9b | ||
|
|
e82437a2db | ||
|
|
c44f08a7ac | ||
|
|
922545096a | ||
|
|
71f00576e0 | ||
|
|
cd11735e72 | ||
|
|
e1a8081f4b | ||
|
|
47265bb8d3 | ||
|
|
15d2fe7cfc | ||
|
|
a7850c4fd7 | ||
|
|
d87e64534d | ||
|
|
fc87aaf0db |
2
.gitignore
vendored
@@ -105,7 +105,7 @@ workspace.xml
|
||||
/output/*
|
||||
.gitversion
|
||||
*/node_modules/*
|
||||
*/templates/*
|
||||
web/src/main/resources/templates/*
|
||||
*/out/*
|
||||
*/dist/*
|
||||
.DS_Store
|
||||
843
CONTRIBUTING.md
@@ -1,835 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="dns-prefetch" href="https://assets-cdn.github.com">
|
||||
<link rel="dns-prefetch" href="https://avatars0.githubusercontent.com">
|
||||
<link rel="dns-prefetch" href="https://avatars1.githubusercontent.com">
|
||||
<link rel="dns-prefetch" href="https://avatars2.githubusercontent.com">
|
||||
<link rel="dns-prefetch" href="https://avatars3.githubusercontent.com">
|
||||
<link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com">
|
||||
<link rel="dns-prefetch" href="https://user-images.githubusercontent.com/">
|
||||
# Contribution Guideline
|
||||
|
||||
Thanks for considering to contribute this project. All issues and pull requests are highly appreciated.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/frameworks-77c3b874f32e71b14cded5a120f42f5c7288fa52e0a37f2d5919fbd8bcfca63c.css" integrity="sha256-d8O4dPMucbFM3tWhIPQvXHKI+lLgo38tWRn72Lz8pjw=" media="all" rel="stylesheet" />
|
||||
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github-7e91a10736ac37b832677484a258d697fe931ba402ccccab1f893155686ad976.css" integrity="sha256-fpGhBzasN7gyZ3SEoljWl/6TG6QCzMyrH4kxVWhq2XY=" media="all" rel="stylesheet" />
|
||||
|
||||
|
||||
|
||||
|
||||
Before sending pull request to this project, please read and follow guidelines below.
|
||||
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<title>VirtualAPK/CONTRIBUTING.md at master · didi/VirtualAPK</title>
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">
|
||||
<link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
|
||||
<meta property="fb:app_id" content="1401488693436528">
|
||||
1. Branch: We only accept pull request on `dev` branch.
|
||||
2. Coding style: Follow the coding style used in kafka-manager.
|
||||
3. Commit message: Use English and be aware of your spell.
|
||||
4. Test: Make sure to test your code.
|
||||
|
||||
|
||||
<meta content="https://avatars2.githubusercontent.com/u/27521938?v=4&s=400" property="og:image" /><meta content="GitHub" property="og:site_name" /><meta content="object" property="og:type" /><meta content="didi/VirtualAPK" property="og:title" /><meta content="https://github.com/didi/VirtualAPK" property="og:url" /><meta content="VirtualAPK - A powerful and lightweight plugin framework for Android" property="og:description" />
|
||||
Add device mode, API version, related log, screenshots and other related information in your pull request if possible.
|
||||
|
||||
<link rel="assets" href="https://assets-cdn.github.com/">
|
||||
<link rel="web-socket" href="wss://live.github.com/_sockets/VjI6MTgwNzY5MzEwOmE5N2I2Yjk2MGRmYmU0ZjZhMTFiOTA5M2Y5MzU5OGEzMmExNjZkYzAzNjYzNTQwMzMzMzQzMGJkMDRmZjNmNmU=--c366cc4384d45c90027d65f977134da25c41a884">
|
||||
<meta name="pjax-timeout" content="1000">
|
||||
<link rel="sudo-modal" href="/sessions/sudo_modal">
|
||||
<meta name="request-id" content="4E29:2AD46:6CCCCFC:BBFD27E:5984674E" data-pjax-transient>
|
||||
|
||||
NOTE: We assume all your contribution can be licensed under the [Apache License 2.0](LICENSE).
|
||||
|
||||
<meta name="selected-link" value="repo_source" data-pjax-transient>
|
||||
## Issues
|
||||
|
||||
<meta name="google-site-verification" content="KT5gs8h0wvaagLKAVWq8bbeNwnZZK1r1XQysX3xurLU">
|
||||
<meta name="google-site-verification" content="ZzhVyEFwb7w3e0-uOTltm8Jsck2F5StVihD0exw2fsA">
|
||||
<meta name="google-analytics" content="UA-3769691-2">
|
||||
We love clearly described issues. :)
|
||||
|
||||
<meta content="collector.githubapp.com" name="octolytics-host" /><meta content="github" name="octolytics-app-id" /><meta content="https://collector.githubapp.com/github-external/browser_event" name="octolytics-event-url" /><meta content="4E29:2AD46:6CCCCFC:BBFD27E:5984674E" name="octolytics-dimension-request_id" /><meta content="iad" name="octolytics-dimension-region_edge" /><meta content="iad" name="octolytics-dimension-region_render" /><meta content="4598761" name="octolytics-actor-id" /><meta content="wbtiger" name="octolytics-actor-login" /><meta content="275cc19fd75d0968078b4b33bd2ac5fac4ab12873218083aeaa8dbc2df60c39f" name="octolytics-actor-hash" />
|
||||
<meta content="/<user-name>/<repo-name>/blob/show" data-pjax-transient="true" name="analytics-location" />
|
||||
|
||||
|
||||
|
||||
|
||||
<meta class="js-ga-set" name="dimension1" content="Logged In">
|
||||
|
||||
|
||||
|
||||
|
||||
<meta name="hostname" content="github.com">
|
||||
<meta name="user-login" content="wbtiger">
|
||||
|
||||
<meta name="expected-hostname" content="github.com">
|
||||
<meta name="js-proxy-site-detection-payload" content="YTJlMTZlMWNkMzY4M2E1ZTVhMWNhODEyNDZmODkwODM5NzQwYjhhMGY5ODRlM2E1OTQyODA0YmZjNDdjZDQwMHx7InJlbW90ZV9hZGRyZXNzIjoiMjEwLjEzLjI0Mi4xIiwicmVxdWVzdF9pZCI6IjRFMjk6MkFENDY6NkNDQ0NGQzpCQkZEMjdFOjU5ODQ2NzRFIiwidGltZXN0YW1wIjoxNTAxODQ5NDI2LCJob3N0IjoiZ2l0aHViLmNvbSJ9">
|
||||
|
||||
<meta name="enabled-features" content="UNIVERSE_BANNER">
|
||||
|
||||
<meta name="html-safe-nonce" content="b2f561be57f18272195251bb7029b59e07e187fe">
|
||||
|
||||
<meta http-equiv="x-pjax-version" content="2a581bbaf84cb76d91db41147f2e3400">
|
||||
|
||||
|
||||
<link href="https://github.com/didi/VirtualAPK/commits/master.atom" rel="alternate" title="Recent Commits to VirtualAPK:master" type="application/atom+xml">
|
||||
|
||||
<meta name="description" content="VirtualAPK - A powerful and lightweight plugin framework for Android">
|
||||
<meta name="go-import" content="github.com/didi/VirtualAPK git https://github.com/didi/VirtualAPK.git">
|
||||
|
||||
<meta content="27521938" name="octolytics-dimension-user_id" /><meta content="didi" name="octolytics-dimension-user_login" /><meta content="95750391" name="octolytics-dimension-repository_id" /><meta content="didi/VirtualAPK" name="octolytics-dimension-repository_nwo" /><meta content="true" name="octolytics-dimension-repository_public" /><meta content="false" name="octolytics-dimension-repository_is_fork" /><meta content="95750391" name="octolytics-dimension-repository_network_root_id" /><meta content="didi/VirtualAPK" name="octolytics-dimension-repository_network_root_nwo" /><meta content="true" name="octolytics-dimension-repository_explore_github_marketplace_ci_cta_shown" />
|
||||
|
||||
|
||||
<link rel="canonical" href="https://github.com/didi/VirtualAPK/blob/master/CONTRIBUTING.md" data-pjax-transient>
|
||||
|
||||
|
||||
<meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">
|
||||
|
||||
<meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">
|
||||
|
||||
<link rel="mask-icon" href="https://assets-cdn.github.com/pinned-octocat.svg" color="#000000">
|
||||
<link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico">
|
||||
|
||||
<meta name="theme-color" content="#1e2327">
|
||||
|
||||
|
||||
<meta name="u2f-support" content="true">
|
||||
|
||||
</head>
|
||||
|
||||
<body class="logged-in env-production page-blob">
|
||||
|
||||
|
||||
<div class="position-relative js-header-wrapper ">
|
||||
<a href="#start-of-content" tabindex="1" class="bg-black text-white p-3 show-on-focus js-skip-to-content">Skip to content</a>
|
||||
<div id="js-pjax-loader-bar" class="pjax-loader-bar"><div class="progress"></div></div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="header" role="banner">
|
||||
<div class="container-lg px-3 clearfix">
|
||||
<div class="d-flex flex-justify-between">
|
||||
<div class="d-flex">
|
||||
<a class="header-logo-invertocat" href="https://github.com/" data-hotkey="g d" aria-label="Homepage" data-ga-click="Header, go to dashboard, icon:logo">
|
||||
<svg aria-hidden="true" class="octicon octicon-mark-github" height="32" version="1.1" viewBox="0 0 16 16" width="32"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="mr-2">
|
||||
<div class="header-search scoped-search site-scoped-search js-site-search" role="search">
|
||||
<!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="/didi/VirtualAPK/search" class="js-site-search-form" data-scoped-search-url="/didi/VirtualAPK/search" data-unscoped-search-url="/search" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
|
||||
<label class="form-control header-search-wrapper js-chromeless-input-container">
|
||||
<a href="/didi/VirtualAPK/blob/master/CONTRIBUTING.md" class="header-search-scope no-underline">This repository</a>
|
||||
<input type="text"
|
||||
class="form-control header-search-input js-site-search-focus js-site-search-field is-clearable"
|
||||
data-hotkey="s"
|
||||
name="q"
|
||||
value=""
|
||||
placeholder="Search"
|
||||
aria-label="Search this repository"
|
||||
data-unscoped-placeholder="Search GitHub"
|
||||
data-scoped-placeholder="Search"
|
||||
autocapitalize="off">
|
||||
<input type="hidden" class="js-site-search-type-field" name="type" >
|
||||
</label>
|
||||
</form></div>
|
||||
|
||||
</div>
|
||||
|
||||
<ul class="d-flex list-style-none" role="navigation">
|
||||
<li>
|
||||
<a href="/pulls" aria-label="Pull requests you created" class="js-selected-navigation-item header-navlink" data-ga-click="Header, click, Nav menu - item:pulls context:user" data-hotkey="g p" data-selected-links="/pulls /pulls/assigned /pulls/mentioned /pulls">
|
||||
Pull requests
|
||||
</a> </li>
|
||||
<li>
|
||||
<a href="/issues" aria-label="Issues you created" class="js-selected-navigation-item header-navlink" data-ga-click="Header, click, Nav menu - item:issues context:user" data-hotkey="g i" data-selected-links="/issues /issues/assigned /issues/mentioned /issues">
|
||||
Issues
|
||||
</a> </li>
|
||||
<li>
|
||||
<a href="/marketplace" class="js-selected-navigation-item header-navlink" data-ga-click="Header, click, Nav menu - item:marketplace context:user" data-selected-links=" /marketplace">
|
||||
Marketplace
|
||||
</a> </li>
|
||||
<li>
|
||||
<a class="header-navlink" href="https://gist.github.com/" data-ga-click="Header, go to gist, text:gist">Gist</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
|
||||
<ul class="d-flex user-nav list-style-none" id="user-links">
|
||||
<li class="dropdown js-menu-container">
|
||||
|
||||
<a href="/notifications" aria-label="You have unread notifications" class="header-navlink notification-indicator tooltipped tooltipped-s js-socket-channel js-notification-indicator" data-channel="notification-changed:4598761" data-ga-click="Header, go to notifications, icon:unread" data-hotkey="g n">
|
||||
<span class="mail-status unread"></span>
|
||||
<svg aria-hidden="true" class="octicon octicon-bell" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path fill-rule="evenodd" d="M14 12v1H0v-1l.73-.58c.77-.77.81-2.55 1.19-4.42C2.69 3.23 6 2 6 2c0-.55.45-1 1-1s1 .45 1 1c0 0 3.39 1.23 4.16 5 .38 1.88.42 3.66 1.19 4.42l.66.58H14zm-7 4c1.11 0 2-.89 2-2H5c0 1.11.89 2 2 2z"/></svg>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="dropdown js-menu-container">
|
||||
<a class="header-navlink tooltipped tooltipped-s js-menu-target" href="/new"
|
||||
aria-label="Create new…"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
data-ga-click="Header, create new, icon:add">
|
||||
<svg aria-hidden="true" class="octicon octicon-plus float-left" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M12 9H7v5H5V9H0V7h5V2h2v5h5z"/></svg>
|
||||
<span class="dropdown-caret"></span>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu-content js-menu-content">
|
||||
<ul class="dropdown-menu dropdown-menu-sw">
|
||||
|
||||
<a class="dropdown-item" href="/new" data-ga-click="Header, create new repository">
|
||||
New repository
|
||||
</a>
|
||||
|
||||
<a class="dropdown-item" href="/new/import" data-ga-click="Header, import a repository">
|
||||
Import repository
|
||||
</a>
|
||||
|
||||
<a class="dropdown-item" href="https://gist.github.com/" data-ga-click="Header, create new gist">
|
||||
New gist
|
||||
</a>
|
||||
|
||||
<a class="dropdown-item" href="/organizations/new" data-ga-click="Header, create new organization">
|
||||
New organization
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
<div class="dropdown-header">
|
||||
<span title="didi/VirtualAPK">This repository</span>
|
||||
</div>
|
||||
<a class="dropdown-item" href="/didi/VirtualAPK/issues/new" data-ga-click="Header, create new issue">
|
||||
New issue
|
||||
</a>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dropdown js-menu-container">
|
||||
<a class="header-navlink name tooltipped tooltipped-sw js-menu-target" href="/wbtiger"
|
||||
aria-label="View profile and more"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
data-ga-click="Header, show menu, icon:avatar">
|
||||
<img alt="@wbtiger" class="avatar" src="https://avatars0.githubusercontent.com/u/4598761?v=4&s=40" height="20" width="20">
|
||||
<span class="dropdown-caret"></span>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu-content js-menu-content">
|
||||
<div class="dropdown-menu dropdown-menu-sw">
|
||||
<div class="dropdown-header header-nav-current-user css-truncate">
|
||||
Signed in as <strong class="css-truncate-target">wbtiger</strong>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<a class="dropdown-item" href="/wbtiger" data-ga-click="Header, go to profile, text:your profile">
|
||||
Your profile
|
||||
</a>
|
||||
<a class="dropdown-item" href="/wbtiger?tab=stars" data-ga-click="Header, go to starred repos, text:your stars">
|
||||
Your stars
|
||||
</a>
|
||||
<a class="dropdown-item" href="/explore" data-ga-click="Header, go to explore, text:explore">
|
||||
Explore
|
||||
</a>
|
||||
<a class="dropdown-item" href="https://help.github.com" data-ga-click="Header, go to help, text:help">
|
||||
Help
|
||||
</a>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<a class="dropdown-item" href="/settings/profile" data-ga-click="Header, go to settings, icon:settings">
|
||||
Settings
|
||||
</a>
|
||||
|
||||
<!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="/logout" class="logout-form" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="iCUyFq9DsN8+PSAXXSFLLHUCaZibvNeiW95cHdbtTULm4wBjigzSEJhDeC8sdAk7tBKHgYY+dXaFjQr1jYhQqg==" /></div>
|
||||
<button type="submit" class="dropdown-item dropdown-signout" data-ga-click="Header, sign out, icon:logout">
|
||||
Sign out
|
||||
</button>
|
||||
</form> </div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="/logout" class="sr-only right-0" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="Flzhb/7RV6uQ+AzooTOZbPkQfbFDgFjQu64VxBLZMuh4mtMa2541ZDaGVNDQZtt7OACTqF4C+gRl/UMsSbwvAA==" /></div>
|
||||
<button type="submit" class="dropdown-item dropdown-signout" data-ga-click="Header, sign out, icon:logout">
|
||||
Sign out
|
||||
</button>
|
||||
</form> </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="flash flash-full js-notice flash-warn">
|
||||
<div class="container">
|
||||
|
||||
|
||||
|
||||
<h4>
|
||||
We are having a problem billing the didichuxing organization.
|
||||
Please <a href="https://github.com/organizations/didichuxing/settings/billing/payment">update your payment method</a>
|
||||
or call your payment provider for details on why the transaction failed.
|
||||
If you don’t need access to your private repositories, you can <a href="http://github.com/organizations/didichuxing/settings/billing">downgrade to the Free plan</a>.
|
||||
</h4>
|
||||
You can always <a href="/contact">contact support</a> with any questions.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="start-of-content" class="show-on-focus"></div>
|
||||
|
||||
<div id="js-flash-container">
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div role="main">
|
||||
<div itemscope itemtype="http://schema.org/SoftwareSourceCode">
|
||||
<div id="js-repo-pjax-container" data-pjax-container>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="pagehead repohead instapaper_ignore readability-menu experiment-repo-nav">
|
||||
<div class="container repohead-details-container">
|
||||
|
||||
<ul class="pagehead-actions">
|
||||
<li>
|
||||
<!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="/notifications/subscribe" class="js-social-container" data-autosubmit="true" data-remote="true" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="ilxSXS07ThXVEaOic735Ui/Z1PnKcDW+esvwfuYtshLhLnKxtLDr9v8bIilW+EP5XZQWYBwRfNG6uSd62UFOJQ==" /></div> <input class="form-control" id="repository_id" name="repository_id" type="hidden" value="95750391" />
|
||||
|
||||
<div class="select-menu js-menu-container js-select-menu">
|
||||
<a href="/didi/VirtualAPK/subscription"
|
||||
class="btn btn-sm btn-with-count select-menu-button js-menu-target"
|
||||
role="button"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle repository notifications menu"
|
||||
data-ga-click="Repository, click Watch settings, action:blob#show">
|
||||
<span class="js-select-button">
|
||||
<svg aria-hidden="true" class="octicon octicon-eye" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M8.06 2C3 2 0 8 0 8s3 6 8.06 6C13 14 16 8 16 8s-3-6-7.94-6zM8 12c-2.2 0-4-1.78-4-4 0-2.2 1.8-4 4-4 2.22 0 4 1.8 4 4 0 2.22-1.78 4-4 4zm2-4c0 1.11-.89 2-2 2-1.11 0-2-.89-2-2 0-1.11.89-2 2-2 1.11 0 2 .89 2 2z"/></svg>
|
||||
Unwatch
|
||||
</span>
|
||||
</a>
|
||||
<a class="social-count js-social-count"
|
||||
href="/didi/VirtualAPK/watchers"
|
||||
aria-label="201 users are watching this repository">
|
||||
201
|
||||
</a>
|
||||
|
||||
<div class="select-menu-modal-holder">
|
||||
<div class="select-menu-modal subscription-menu-modal js-menu-content">
|
||||
<div class="select-menu-header js-navigation-enable" tabindex="-1">
|
||||
<svg aria-label="Close" class="octicon octicon-x js-menu-close" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
|
||||
<span class="select-menu-title">Notifications</span>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-list js-navigation-container" role="menu">
|
||||
|
||||
<div class="select-menu-item js-navigation-item " role="menuitem" tabindex="0">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"/></svg>
|
||||
<div class="select-menu-item-text">
|
||||
<input id="do_included" name="do" type="radio" value="included" />
|
||||
<span class="select-menu-item-heading">Not watching</span>
|
||||
<span class="description">Be notified when participating or @mentioned.</span>
|
||||
<span class="js-select-button-text hidden-select-button-text">
|
||||
<svg aria-hidden="true" class="octicon octicon-eye" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M8.06 2C3 2 0 8 0 8s3 6 8.06 6C13 14 16 8 16 8s-3-6-7.94-6zM8 12c-2.2 0-4-1.78-4-4 0-2.2 1.8-4 4-4 2.22 0 4 1.8 4 4 0 2.22-1.78 4-4 4zm2-4c0 1.11-.89 2-2 2-1.11 0-2-.89-2-2 0-1.11.89-2 2-2 1.11 0 2 .89 2 2z"/></svg>
|
||||
Watch
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-item js-navigation-item selected" role="menuitem" tabindex="0">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"/></svg>
|
||||
<div class="select-menu-item-text">
|
||||
<input checked="checked" id="do_subscribed" name="do" type="radio" value="subscribed" />
|
||||
<span class="select-menu-item-heading">Watching</span>
|
||||
<span class="description">Be notified of all conversations.</span>
|
||||
<span class="js-select-button-text hidden-select-button-text">
|
||||
<svg aria-hidden="true" class="octicon octicon-eye" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M8.06 2C3 2 0 8 0 8s3 6 8.06 6C13 14 16 8 16 8s-3-6-7.94-6zM8 12c-2.2 0-4-1.78-4-4 0-2.2 1.8-4 4-4 2.22 0 4 1.8 4 4 0 2.22-1.78 4-4 4zm2-4c0 1.11-.89 2-2 2-1.11 0-2-.89-2-2 0-1.11.89-2 2-2 1.11 0 2 .89 2 2z"/></svg>
|
||||
Unwatch
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-item js-navigation-item " role="menuitem" tabindex="0">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"/></svg>
|
||||
<div class="select-menu-item-text">
|
||||
<input id="do_ignore" name="do" type="radio" value="ignore" />
|
||||
<span class="select-menu-item-heading">Ignoring</span>
|
||||
<span class="description">Never be notified.</span>
|
||||
<span class="js-select-button-text hidden-select-button-text">
|
||||
<svg aria-hidden="true" class="octicon octicon-mute" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M8 2.81v10.38c0 .67-.81 1-1.28.53L3 10H1c-.55 0-1-.45-1-1V7c0-.55.45-1 1-1h2l3.72-3.72C7.19 1.81 8 2.14 8 2.81zm7.53 3.22l-1.06-1.06-1.97 1.97-1.97-1.97-1.06 1.06L11.44 8 9.47 9.97l1.06 1.06 1.97-1.97 1.97 1.97 1.06-1.06L13.56 8l1.97-1.97z"/></svg>
|
||||
Stop ignoring
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
<div class="js-toggler-container js-social-container starring-container ">
|
||||
<!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="/didi/VirtualAPK/unstar" class="starred" data-remote="true" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="Q+D8KWgxgtZRRzjMMMc9XHi7VS6G1YcZ06JQ7RcxZO8LHmloFHnOw2MryKAWIM4nirolh2QGKRJ1w9d2OhazBg==" /></div>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-sm btn-with-count js-toggler-target"
|
||||
aria-label="Unstar this repository" title="Unstar didi/VirtualAPK"
|
||||
data-ga-click="Repository, click unstar button, action:blob#show; text:Unstar">
|
||||
<svg aria-hidden="true" class="octicon octicon-star" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path fill-rule="evenodd" d="M14 6l-4.9-.64L7 1 4.9 5.36 0 6l3.6 3.26L2.67 14 7 11.67 11.33 14l-.93-4.74z"/></svg>
|
||||
Unstar
|
||||
</button>
|
||||
<a class="social-count js-social-count" href="/didi/VirtualAPK/stargazers"
|
||||
aria-label="4154 users starred this repository">
|
||||
4,154
|
||||
</a>
|
||||
</form>
|
||||
<!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="/didi/VirtualAPK/star" class="unstarred" data-remote="true" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="5rEqD8GHiUII3nNr3fl0ZQis36UU6E62k7uQKTq8bRZr9grFDV61v7EICrRDkxCFz9ECivUVZfvPndKNUpOehA==" /></div>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-sm btn-with-count js-toggler-target"
|
||||
aria-label="Star this repository" title="Star didi/VirtualAPK"
|
||||
data-ga-click="Repository, click star button, action:blob#show; text:Star">
|
||||
<svg aria-hidden="true" class="octicon octicon-star" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path fill-rule="evenodd" d="M14 6l-4.9-.64L7 1 4.9 5.36 0 6l3.6 3.26L2.67 14 7 11.67 11.33 14l-.93-4.74z"/></svg>
|
||||
Star
|
||||
</button>
|
||||
<a class="social-count js-social-count" href="/didi/VirtualAPK/stargazers"
|
||||
aria-label="4154 users starred this repository">
|
||||
4,154
|
||||
</a>
|
||||
</form> </div>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#fork-destination-box" class="btn btn-sm btn-with-count"
|
||||
title="Fork your own copy of didi/VirtualAPK to your account"
|
||||
aria-label="Fork your own copy of didi/VirtualAPK to your account"
|
||||
rel="facebox"
|
||||
data-ga-click="Repository, show fork modal, action:blob#show; text:Fork">
|
||||
<svg aria-hidden="true" class="octicon octicon-repo-forked" height="16" version="1.1" viewBox="0 0 10 16" width="10"><path fill-rule="evenodd" d="M8 1a1.993 1.993 0 0 0-1 3.72V6L5 8 3 6V4.72A1.993 1.993 0 0 0 2 1a1.993 1.993 0 0 0-1 3.72V6.5l3 3v1.78A1.993 1.993 0 0 0 5 15a1.993 1.993 0 0 0 1-3.72V9.5l3-3V4.72A1.993 1.993 0 0 0 8 1zM2 4.2C1.34 4.2.8 3.65.8 3c0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zm3 10c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zm3-10c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2z"/></svg>
|
||||
Fork
|
||||
</a>
|
||||
|
||||
<div id="fork-destination-box" style="display: none;">
|
||||
<h2 class="facebox-header" data-facebox-id="facebox-header">Where should we fork this repository?</h2>
|
||||
<include-fragment src=""
|
||||
class="js-fork-select-fragment fork-select-fragment"
|
||||
data-url="/didi/VirtualAPK/fork?fragment=1">
|
||||
<img alt="Loading" height="64" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-128.gif" width="64" />
|
||||
</include-fragment>
|
||||
</div>
|
||||
|
||||
<a href="/didi/VirtualAPK/network" class="social-count"
|
||||
aria-label="562 users forked this repository">
|
||||
562
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h1 class="public ">
|
||||
<svg aria-hidden="true" class="octicon octicon-repo" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M4 9H3V8h1v1zm0-3H3v1h1V6zm0-2H3v1h1V4zm0-2H3v1h1V2zm8-1v12c0 .55-.45 1-1 1H6v2l-1.5-1.5L3 16v-2H1c-.55 0-1-.45-1-1V1c0-.55.45-1 1-1h10c.55 0 1 .45 1 1zm-1 10H1v2h2v-1h3v1h5v-2zm0-10H2v9h9V1z"/></svg>
|
||||
<span class="author" itemprop="author"><a href="/didi" class="url fn" rel="author">didi</a></span><!--
|
||||
--><span class="path-divider">/</span><!--
|
||||
--><strong itemprop="name"><a href="/didi/VirtualAPK" data-pjax="#js-repo-pjax-container">VirtualAPK</a></strong>
|
||||
|
||||
</h1>
|
||||
|
||||
</div>
|
||||
<div class="container">
|
||||
|
||||
<nav class="reponav js-repo-nav js-sidenav-container-pjax"
|
||||
itemscope
|
||||
itemtype="http://schema.org/BreadcrumbList"
|
||||
role="navigation"
|
||||
data-pjax="#js-repo-pjax-container">
|
||||
|
||||
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
|
||||
<a href="/didi/VirtualAPK" class="js-selected-navigation-item selected reponav-item" data-hotkey="g c" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches /didi/VirtualAPK" itemprop="url">
|
||||
<svg aria-hidden="true" class="octicon octicon-code" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path fill-rule="evenodd" d="M9.5 3L8 4.5 11.5 8 8 11.5 9.5 13 14 8 9.5 3zm-5 0L0 8l4.5 5L6 11.5 2.5 8 6 4.5 4.5 3z"/></svg>
|
||||
<span itemprop="name">Code</span>
|
||||
<meta itemprop="position" content="1">
|
||||
</a> </span>
|
||||
|
||||
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
|
||||
<a href="/didi/VirtualAPK/issues" class="js-selected-navigation-item reponav-item" data-hotkey="g i" data-selected-links="repo_issues repo_labels repo_milestones /didi/VirtualAPK/issues" itemprop="url">
|
||||
<svg aria-hidden="true" class="octicon octicon-issue-opened" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"/></svg>
|
||||
<span itemprop="name">Issues</span>
|
||||
<span class="Counter">44</span>
|
||||
<meta itemprop="position" content="2">
|
||||
</a> </span>
|
||||
|
||||
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
|
||||
<a href="/didi/VirtualAPK/pulls" class="js-selected-navigation-item reponav-item" data-hotkey="g p" data-selected-links="repo_pulls /didi/VirtualAPK/pulls" itemprop="url">
|
||||
<svg aria-hidden="true" class="octicon octicon-git-pull-request" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M11 11.28V5c-.03-.78-.34-1.47-.94-2.06C9.46 2.35 8.78 2.03 8 2H7V0L4 3l3 3V4h1c.27.02.48.11.69.31.21.2.3.42.31.69v6.28A1.993 1.993 0 0 0 10 15a1.993 1.993 0 0 0 1-3.72zm-1 2.92c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zM4 3c0-1.11-.89-2-2-2a1.993 1.993 0 0 0-1 3.72v6.56A1.993 1.993 0 0 0 2 15a1.993 1.993 0 0 0 1-3.72V4.72c.59-.34 1-.98 1-1.72zm-.8 10c0 .66-.55 1.2-1.2 1.2-.65 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2zM2 4.2C1.34 4.2.8 3.65.8 3c0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2z"/></svg>
|
||||
<span itemprop="name">Pull requests</span>
|
||||
<span class="Counter">3</span>
|
||||
<meta itemprop="position" content="3">
|
||||
</a> </span>
|
||||
|
||||
<a href="/didi/VirtualAPK/projects" class="js-selected-navigation-item reponav-item" data-selected-links="repo_projects new_repo_project repo_project /didi/VirtualAPK/projects">
|
||||
<svg aria-hidden="true" class="octicon octicon-project" height="16" version="1.1" viewBox="0 0 15 16" width="15"><path fill-rule="evenodd" d="M10 12h3V2h-3v10zm-4-2h3V2H6v8zm-4 4h3V2H2v12zm-1 1h13V1H1v14zM14 0H1a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h13a1 1 0 0 0 1-1V1a1 1 0 0 0-1-1z"/></svg>
|
||||
Projects
|
||||
<span class="Counter" >0</span>
|
||||
</a>
|
||||
<a href="/didi/VirtualAPK/wiki" class="js-selected-navigation-item reponav-item" data-hotkey="g w" data-selected-links="repo_wiki /didi/VirtualAPK/wiki">
|
||||
<svg aria-hidden="true" class="octicon octicon-book" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M3 5h4v1H3V5zm0 3h4V7H3v1zm0 2h4V9H3v1zm11-5h-4v1h4V5zm0 2h-4v1h4V7zm0 2h-4v1h4V9zm2-6v9c0 .55-.45 1-1 1H9.5l-1 1-1-1H2c-.55 0-1-.45-1-1V3c0-.55.45-1 1-1h5.5l1 1 1-1H15c.55 0 1 .45 1 1zm-8 .5L7.5 3H2v9h6V3.5zm7-.5H9.5l-.5.5V12h6V3z"/></svg>
|
||||
Wiki
|
||||
</a>
|
||||
<a href="/didi/VirtualAPK/settings" class="js-selected-navigation-item reponav-item" data-selected-links="repo_settings repo_branch_settings hooks integration_installations /didi/VirtualAPK/settings">
|
||||
<svg aria-hidden="true" class="octicon octicon-gear" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path fill-rule="evenodd" d="M14 8.77v-1.6l-1.94-.64-.45-1.09.88-1.84-1.13-1.13-1.81.91-1.09-.45-.69-1.92h-1.6l-.63 1.94-1.11.45-1.84-.88-1.13 1.13.91 1.81-.45 1.09L0 7.23v1.59l1.94.64.45 1.09-.88 1.84 1.13 1.13 1.81-.91 1.09.45.69 1.92h1.59l.63-1.94 1.11-.45 1.84.88 1.13-1.13-.92-1.81.47-1.09L14 8.75v.02zM7 11c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3z"/></svg>
|
||||
Settings
|
||||
</a>
|
||||
<div class="reponav-dropdown js-menu-container">
|
||||
<button type="button" class="btn-link reponav-item reponav-dropdown js-menu-target " data-no-toggle aria-expanded="false" aria-haspopup="true">
|
||||
Insights
|
||||
<svg aria-hidden="true" class="octicon octicon-triangle-down v-align-middle text-gray" height="11" version="1.1" viewBox="0 0 12 16" width="8"><path fill-rule="evenodd" d="M0 5l6 6 6-6z"/></svg>
|
||||
</button>
|
||||
<div class="dropdown-menu-content js-menu-content">
|
||||
<div class="dropdown-menu dropdown-menu-sw">
|
||||
<a class="dropdown-item" href="/didi/VirtualAPK/community" data-skip-pjax>
|
||||
<svg aria-hidden="true" class="octicon octicon-heart" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M11.2 3c-.52-.63-1.25-.95-2.2-1-.97 0-1.69.42-2.2 1-.51.58-.78.92-.8 1-.02-.08-.28-.42-.8-1-.52-.58-1.17-1-2.2-1-.95.05-1.69.38-2.2 1-.52.61-.78 1.28-.8 2 0 .52.09 1.52.67 2.67C1.25 8.82 3.01 10.61 6 13c2.98-2.39 4.77-4.17 5.34-5.33C11.91 6.51 12 5.5 12 5c-.02-.72-.28-1.39-.8-2.02V3z"/></svg>
|
||||
<span itemprop="name">Community</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/didi/VirtualAPK/pulse" data-skip-pjax>
|
||||
<svg aria-hidden="true" class="octicon octicon-pulse" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path fill-rule="evenodd" d="M11.5 8L8.8 5.4 6.6 8.5 5.5 1.6 2.38 8H0v2h3.6l.9-1.8.9 5.4L9 8.5l1.6 1.5H14V8z"/></svg>
|
||||
Pulse
|
||||
</a>
|
||||
<a class="dropdown-item" href="/didi/VirtualAPK/graphs" data-skip-pjax>
|
||||
<svg aria-hidden="true" class="octicon octicon-graph" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M16 14v1H0V0h1v14h15zM5 13H3V8h2v5zm4 0H7V3h2v10zm4 0h-2V6h2v7z"/></svg>
|
||||
Graphs
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container new-discussion-timeline experiment-repo-nav">
|
||||
<div class="repository-content">
|
||||
|
||||
|
||||
<a href="/didi/VirtualAPK/blob/0b0745edcd2b4adc411cb77de7c4099b898c23d8/CONTRIBUTING.md" class="d-none js-permalink-shortcut" data-hotkey="y">Permalink</a>
|
||||
|
||||
<!-- blob contrib key: blob_contributors:v21:25812bc73237cfe3552924ee8fa0aacd -->
|
||||
|
||||
<div class="file-navigation js-zeroclipboard-container">
|
||||
|
||||
<div class="select-menu branch-select-menu js-menu-container js-select-menu float-left">
|
||||
<button class=" btn btn-sm select-menu-button js-menu-target css-truncate" data-hotkey="w"
|
||||
|
||||
type="button" aria-label="Switch branches or tags" aria-expanded="false" aria-haspopup="true">
|
||||
<i>Branch:</i>
|
||||
<span class="js-select-button css-truncate-target">master</span>
|
||||
</button>
|
||||
|
||||
<div class="select-menu-modal-holder js-menu-content js-navigation-container" data-pjax>
|
||||
|
||||
<div class="select-menu-modal">
|
||||
<div class="select-menu-header">
|
||||
<svg aria-label="Close" class="octicon octicon-x js-menu-close" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
|
||||
<span class="select-menu-title">Switch branches/tags</span>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-filters">
|
||||
<div class="select-menu-text-filter">
|
||||
<input type="text" aria-label="Find or create a branch…" id="context-commitish-filter-field" class="form-control js-filterable-field js-navigation-enable" placeholder="Find or create a branch…">
|
||||
</div>
|
||||
<div class="select-menu-tabs">
|
||||
<ul>
|
||||
<li class="select-menu-tab">
|
||||
<a href="#" data-tab-filter="branches" data-filter-placeholder="Find or create a branch…" class="js-select-menu-tab" role="tab">Branches</a>
|
||||
</li>
|
||||
<li class="select-menu-tab">
|
||||
<a href="#" data-tab-filter="tags" data-filter-placeholder="Find a tag…" class="js-select-menu-tab" role="tab">Tags</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="branches" role="menu">
|
||||
|
||||
<div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
|
||||
|
||||
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/didi/VirtualAPK/blob/dev/CONTRIBUTING.md"
|
||||
data-name="dev"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"/></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
dev
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open selected"
|
||||
href="/didi/VirtualAPK/blob/master/CONTRIBUTING.md"
|
||||
data-name="master"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"/></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
master
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="/didi/VirtualAPK/branches" class="js-create-branch select-menu-item select-menu-new-item-form js-navigation-item js-new-item-form" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="Biopo2g/9XzE6zpe5jezjUisIeUSshY7es+KSqhR3toFPxwGTd8OXBdAvA6uShHQw4OpTPEpg0GDfZY+S0b0Sg==" /></div>
|
||||
<svg aria-hidden="true" class="octicon octicon-git-branch select-menu-item-icon" height="16" version="1.1" viewBox="0 0 10 16" width="10"><path fill-rule="evenodd" d="M10 5c0-1.11-.89-2-2-2a1.993 1.993 0 0 0-1 3.72v.3c-.02.52-.23.98-.63 1.38-.4.4-.86.61-1.38.63-.83.02-1.48.16-2 .45V4.72a1.993 1.993 0 0 0-1-3.72C.88 1 0 1.89 0 3a2 2 0 0 0 1 1.72v6.56c-.59.35-1 .99-1 1.72 0 1.11.89 2 2 2 1.11 0 2-.89 2-2 0-.53-.2-1-.53-1.36.09-.06.48-.41.59-.47.25-.11.56-.17.94-.17 1.05-.05 1.95-.45 2.75-1.25S8.95 7.77 9 6.73h-.02C9.59 6.37 10 5.73 10 5zM2 1.8c.66 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2C1.35 4.2.8 3.65.8 3c0-.65.55-1.2 1.2-1.2zm0 12.41c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zm6-8c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2z"/></svg>
|
||||
<div class="select-menu-item-text">
|
||||
<span class="select-menu-item-heading">Create branch: <span class="js-new-item-name"></span></span>
|
||||
<span class="description">from ‘master’</span>
|
||||
</div>
|
||||
<input type="hidden" name="name" id="name" class="js-new-item-value">
|
||||
<input type="hidden" name="branch" id="branch" value="master">
|
||||
<input type="hidden" name="path" id="path" value="CONTRIBUTING.md">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="tags">
|
||||
<div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="select-menu-no-results">Nothing to show</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="BtnGroup float-right">
|
||||
<a href="/didi/VirtualAPK/find/master"
|
||||
class="js-pjax-capture-input btn btn-sm BtnGroup-item"
|
||||
data-pjax
|
||||
data-hotkey="t">
|
||||
Find file
|
||||
</a>
|
||||
<button aria-label="Copy file path to clipboard" class="js-zeroclipboard btn btn-sm BtnGroup-item tooltipped tooltipped-s" data-copied-hint="Copied!" type="button">Copy path</button>
|
||||
</div>
|
||||
<div class="breadcrumb js-zeroclipboard-target">
|
||||
<span class="repo-root js-repo-root"><span class="js-path-segment"><a href="/didi/VirtualAPK"><span>VirtualAPK</span></a></span></span><span class="separator">/</span><strong class="final-path">CONTRIBUTING.md</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="commit-tease">
|
||||
<span class="float-right">
|
||||
<a class="commit-tease-sha" href="/didi/VirtualAPK/commit/2740ca13cbba694cf3f435f5a8d6716fa1aa1abc" data-pjax>
|
||||
2740ca1
|
||||
</a>
|
||||
<relative-time datetime="2017-06-29T14:54:01Z">Jun 29, 2017</relative-time>
|
||||
</span>
|
||||
<div>
|
||||
<img alt="@huandu" class="avatar" height="20" src="https://avatars2.githubusercontent.com/u/239739?v=4&s=40" width="20" />
|
||||
<a href="/huandu" class="user-mention" rel="contributor">huandu</a>
|
||||
<a href="/didi/VirtualAPK/commit/2740ca13cbba694cf3f435f5a8d6716fa1aa1abc" class="message" data-pjax="true" title="polish documents">polish documents</a>
|
||||
</div>
|
||||
|
||||
<div class="commit-tease-contributors">
|
||||
<button type="button" class="btn-link muted-link contributors-toggle" data-facebox="#blob_contributors_box">
|
||||
<strong>2</strong>
|
||||
contributors
|
||||
</button>
|
||||
<a class="avatar-link tooltipped tooltipped-s" aria-label="singwhatiwanna" href="/didi/VirtualAPK/commits/master/CONTRIBUTING.md?author=singwhatiwanna"><img alt="@singwhatiwanna" class="avatar" height="20" src="https://avatars3.githubusercontent.com/u/3346272?v=4&s=40" width="20" /> </a>
|
||||
<a class="avatar-link tooltipped tooltipped-s" aria-label="huandu" href="/didi/VirtualAPK/commits/master/CONTRIBUTING.md?author=huandu"><img alt="@huandu" class="avatar" height="20" src="https://avatars2.githubusercontent.com/u/239739?v=4&s=40" width="20" /> </a>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div id="blob_contributors_box" style="display:none">
|
||||
<h2 class="facebox-header" data-facebox-id="facebox-header">Users who have contributed to this file</h2>
|
||||
<ul class="facebox-user-list" data-facebox-id="facebox-description">
|
||||
<li class="facebox-user-list-item">
|
||||
<img alt="@singwhatiwanna" height="24" src="https://avatars1.githubusercontent.com/u/3346272?v=4&s=48" width="24" />
|
||||
<a href="/singwhatiwanna">singwhatiwanna</a>
|
||||
</li>
|
||||
<li class="facebox-user-list-item">
|
||||
<img alt="@huandu" height="24" src="https://avatars0.githubusercontent.com/u/239739?v=4&s=48" width="24" />
|
||||
<a href="/huandu">huandu</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="file">
|
||||
<div class="file-header">
|
||||
<div class="file-actions">
|
||||
|
||||
<div class="BtnGroup">
|
||||
<a href="/didi/VirtualAPK/raw/master/CONTRIBUTING.md" class="btn btn-sm BtnGroup-item" id="raw-url">Raw</a>
|
||||
<a href="/didi/VirtualAPK/blame/master/CONTRIBUTING.md" class="btn btn-sm js-update-url-with-hash BtnGroup-item" data-hotkey="b">Blame</a>
|
||||
<a href="/didi/VirtualAPK/commits/master/CONTRIBUTING.md" class="btn btn-sm BtnGroup-item" rel="nofollow">History</a>
|
||||
</div>
|
||||
|
||||
<a class="btn-octicon tooltipped tooltipped-nw"
|
||||
href="https://desktop.github.com"
|
||||
aria-label="Open this file in GitHub Desktop"
|
||||
data-ga-click="Repository, open with desktop, type:windows">
|
||||
<svg aria-hidden="true" class="octicon octicon-device-desktop" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M15 2H1c-.55 0-1 .45-1 1v9c0 .55.45 1 1 1h5.34c-.25.61-.86 1.39-2.34 2h8c-1.48-.61-2.09-1.39-2.34-2H15c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm0 9H1V3h14v8z"/></svg>
|
||||
</a>
|
||||
|
||||
<!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="/didi/VirtualAPK/edit/master/CONTRIBUTING.md" class="inline-form js-update-url-with-hash" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="QhTGbaFmDHoBMq25j4xu14cHKLdUX6jxgf2RJaWgKTBKa+wMA6PqLifa6IgZUUe41ZmGJxYr6eM37m0/vzfs6w==" /></div>
|
||||
<button class="btn-octicon tooltipped tooltipped-nw" type="submit"
|
||||
aria-label="Edit this file" data-hotkey="e" data-disable-with>
|
||||
<svg aria-hidden="true" class="octicon octicon-pencil" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path fill-rule="evenodd" d="M0 12v3h3l8-8-3-3-8 8zm3 2H1v-2h1v1h1v1zm10.3-9.3L12 6 9 3l1.3-1.3a.996.996 0 0 1 1.41 0l1.59 1.59c.39.39.39 1.02 0 1.41z"/></svg>
|
||||
</button>
|
||||
</form> <!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="/didi/VirtualAPK/delete/master/CONTRIBUTING.md" class="inline-form" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="ccXfryEyc1vQiyQxM36LxZBqUdDDFFxec9O+ylp0/H6Y2nFyHH1okgGAPkc47jJBd62nKEr0mFmdUIU+xSISFw==" /></div>
|
||||
<button class="btn-octicon btn-octicon-danger tooltipped tooltipped-nw" type="submit"
|
||||
aria-label="Delete this file" data-disable-with>
|
||||
<svg aria-hidden="true" class="octicon octicon-trashcan" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M11 2H9c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1H2c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1v9c0 .55.45 1 1 1h7c.55 0 1-.45 1-1V5c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm-1 12H3V5h1v8h1V5h1v8h1V5h1v8h1V5h1v9zm1-10H2V3h9v1z"/></svg>
|
||||
</button>
|
||||
</form> </div>
|
||||
|
||||
<div class="file-info">
|
||||
29 lines (18 sloc)
|
||||
<span class="file-info-divider"></span>
|
||||
938 Bytes
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="readme" class="readme blob instapaper_body">
|
||||
<article class="markdown-body entry-content" itemprop="text"><h1><a id="user-content-contribution-guideline" class="anchor" href="#contribution-guideline" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Contribution Guideline</h1>
|
||||
<p>Thanks for considering to contribute this project. All issues and pull requests are highly appreciated.</p>
|
||||
<h2><a id="user-content-pull-requests" class="anchor" href="#pull-requests" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Pull Requests</h2>
|
||||
<p>Before sending pull request to this project, please read and follow guidelines below.</p>
|
||||
<ol>
|
||||
<li>Branch: We only accept pull request on <code>dev</code> branch.</li>
|
||||
<li>Coding style: Follow the coding style used in VirtualAPK.</li>
|
||||
<li>Commit message: Use English and be aware of your spell.</li>
|
||||
<li>Test: Make sure to test your code.</li>
|
||||
</ol>
|
||||
<p>Add device mode, API version, related log, screenshots and other related information in your pull request if possible.</p>
|
||||
<p>NOTE: We assume all your contribution can be licensed under the <a href="https://github.com/didi/VirtualAPK/blob/master/LICENSE">Apache License 2.0</a>.</p>
|
||||
<h2><a id="user-content-issues" class="anchor" href="#issues" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Issues</h2>
|
||||
<p>We love clearly described issues. :)</p>
|
||||
<p>Following information can help us to resolve the issue faster.</p>
|
||||
<ul>
|
||||
<li>Device mode and hardware information.</li>
|
||||
<li>API version.</li>
|
||||
<li>Logs.</li>
|
||||
<li>Screenshots.</li>
|
||||
<li>Steps to reproduce the issue.</li>
|
||||
</ul>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<button type="button" data-facebox="#jump-to-line" data-facebox-class="linejump" data-hotkey="l" class="d-none">Jump to Line</button>
|
||||
<div id="jump-to-line" style="display:none">
|
||||
<!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="" class="js-jump-to-line-form" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
|
||||
<input class="form-control linejump-input js-jump-to-line-field" type="text" placeholder="Jump to line…" aria-label="Jump to line" autofocus>
|
||||
<button type="submit" class="btn">Go</button>
|
||||
</form> </div>
|
||||
|
||||
</div>
|
||||
<div class="modal-backdrop js-touch-events"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container-lg site-footer-container">
|
||||
<div class="site-footer " role="contentinfo">
|
||||
<ul class="site-footer-links float-right">
|
||||
<li><a href="https://github.com/contact" data-ga-click="Footer, go to contact, text:contact">Contact GitHub</a></li>
|
||||
<li><a href="https://developer.github.com" data-ga-click="Footer, go to api, text:api">API</a></li>
|
||||
<li><a href="https://training.github.com" data-ga-click="Footer, go to training, text:training">Training</a></li>
|
||||
<li><a href="https://shop.github.com" data-ga-click="Footer, go to shop, text:shop">Shop</a></li>
|
||||
<li><a href="https://github.com/blog" data-ga-click="Footer, go to blog, text:blog">Blog</a></li>
|
||||
<li><a href="https://github.com/about" data-ga-click="Footer, go to about, text:about">About</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
<a href="https://github.com" aria-label="Homepage" class="site-footer-mark" title="GitHub">
|
||||
<svg aria-hidden="true" class="octicon octicon-mark-github" height="24" version="1.1" viewBox="0 0 16 16" width="24"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>
|
||||
</a>
|
||||
<ul class="site-footer-links">
|
||||
<li>© 2017 <span title="0.18126s from unicorn-2592397628-tnzmf">GitHub</span>, Inc.</li>
|
||||
<li><a href="https://github.com/site/terms" data-ga-click="Footer, go to terms, text:terms">Terms</a></li>
|
||||
<li><a href="https://github.com/site/privacy" data-ga-click="Footer, go to privacy, text:privacy">Privacy</a></li>
|
||||
<li><a href="https://github.com/security" data-ga-click="Footer, go to security, text:security">Security</a></li>
|
||||
<li><a href="https://status.github.com/" data-ga-click="Footer, go to status, text:status">Status</a></li>
|
||||
<li><a href="https://help.github.com" data-ga-click="Footer, go to help, text:help">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="ajax-error-message" class="ajax-error-message flash flash-error">
|
||||
<svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"/></svg>
|
||||
<button type="button" class="flash-close js-flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
|
||||
<svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
|
||||
</button>
|
||||
You can't perform that action at this time.
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script crossorigin="anonymous" integrity="sha256-OiTVyGEpRWTLRqro9+PHTHqtjluGGBa/2WknMA8gP1E=" src="https://assets-cdn.github.com/assets/frameworks-3a24d5c861294564cb46aae8f7e3c74c7aad8e5b861816bfd96927300f203f51.js"></script>
|
||||
|
||||
<script async="async" crossorigin="anonymous" integrity="sha256-0u/yC9TgTIqxZRfYQjZg/tLvDPt0wXD1XA2s6QOFTaY=" src="https://assets-cdn.github.com/assets/github-d2eff20bd4e04c8ab16517d8423660fed2ef0cfb74c170f55c0dace903854da6.js"></script>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="js-stale-session-flash stale-session-flash flash flash-warn flash-banner d-none">
|
||||
<svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"/></svg>
|
||||
<span class="signed-in-tab-flash">You signed in with another tab or window. <a href="">Reload</a> to refresh your session.</span>
|
||||
<span class="signed-out-tab-flash">You signed out in another tab or window. <a href="">Reload</a> to refresh your session.</span>
|
||||
</div>
|
||||
<div class="facebox" id="facebox" style="display:none;">
|
||||
<div class="facebox-popup">
|
||||
<div class="facebox-content" role="dialog" aria-labelledby="facebox-header" aria-describedby="facebox-description">
|
||||
</div>
|
||||
<button type="button" class="facebox-close js-facebox-close" aria-label="Close modal">
|
||||
<svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Following information can help us to resolve the issue faster.
|
||||
|
||||
* Device mode and hardware information.
|
||||
* API version.
|
||||
* Logs.
|
||||
* Screenshots.
|
||||
* Steps to reproduce the issue.
|
||||
7
Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM fabric8/java-alpine-openjdk8-jdk
|
||||
MAINTAINER xuzhengxi
|
||||
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
|
||||
ADD ./web/target/kafka-manager-web-1.1.0-SNAPSHOT.jar kafka-manager-web.jar
|
||||
ADD ./docker/kafka-manager/application-standalone.yml application.yml
|
||||
ENTRYPOINT ["java","-jar","/kafka-manager-web.jar","--spring.config.location=./application.yml"]
|
||||
EXPOSE 8080
|
||||
92
README.md
@@ -1,7 +1,7 @@
|
||||
|
||||
---
|
||||
|
||||

|
||||

|
||||
|
||||
**一站式`Apache Kafka`集群指标监控与运维管控平台**
|
||||
|
||||
@@ -18,32 +18,104 @@
|
||||
|
||||
### 集群管控维度
|
||||
|
||||
- 集群运维,包括逻辑Region方式管理集群
|
||||
- Broker运维,包括优先副本选举
|
||||
- 集群运维,包括逻辑Region方式管理集群;
|
||||
- Broker运维,包括优先副本选举;
|
||||
- Topic运维,包括创建、查询、扩容、修改属性、数据采样及迁移等;
|
||||
- 消费组运维,包括指定时间或指定偏移两种方式进行重置消费偏移
|
||||
- 消费组运维,包括指定时间或指定偏移两种方式进行重置消费偏移;
|
||||
|
||||
|
||||
### 用户使用维度
|
||||
|
||||
- 管理员用户与普通用户视角区分
|
||||
- 管理员用户与普通用户权限区分
|
||||
- 管理员用户与普通用户视角区分;
|
||||
- 管理员用户与普通用户权限区分;
|
||||
|
||||
---
|
||||
|
||||
## kafka-manager架构图
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
---
|
||||
|
||||
## 安装手册
|
||||
|
||||
### 环境依赖
|
||||
|
||||
- `Maven 3.5.0+`(后端打包依赖)
|
||||
- `node v8.12.0+`(前端打包依赖)
|
||||
- `Java 8+`(运行环境需要)
|
||||
- `MySQL` 或 `PostgreSQL`(数据存储)
|
||||
|
||||
---
|
||||
|
||||
### 环境初始化
|
||||
|
||||
**MySQL**
|
||||
|
||||
执行[create_mysql_table.sql](doc/create_mysql_table.sql)中的SQL命令,从而创建所需的MySQL库及表,默认创建的库名是`kafka_manager`。
|
||||
|
||||
```
|
||||
############# 示例:
|
||||
mysql -uXXXX -pXXX -h XXX.XXX.XXX.XXX -PXXXX < ./create_mysql_table.sql
|
||||
```
|
||||
|
||||
**PostgreSQL**
|
||||
|
||||
执行[create_postgresql_table.sql](doc/create_postgresql_table.sql)中的SQL命令,从而创建所需的PostgreSQL表。
|
||||
|
||||
```
|
||||
############# 示例:
|
||||
psql -h XXX.XXX.XXX.XXX -U XXXX -d kafka_manager -f ./create_postgresql_table.sql
|
||||
```
|
||||
|
||||
*PostgreSQL 用户、数据库创建方式*
|
||||
|
||||
```sql
|
||||
create user admin encrypted password 'admin';
|
||||
create database kafka_manager owner=admin template=template0 encoding='UTF-8' lc_collate='zh_CN.UTF-8' lc_ctype='zh_CN.UTF-8';
|
||||
```
|
||||
|
||||
***默认配置使用 MySQL 数据库,若要使用 PostgreSQL 数据库,使用 `-Dspring.profiles.active=pg` 指定 `application-pg.yml` 配置文件。***
|
||||
|
||||
---
|
||||
|
||||
|
||||
### 打包
|
||||
|
||||
执行`mvn install`命令即可。
|
||||
|
||||
备注:每一次执行`mvn install`命令,都将在`web/src/main/resources/templates`下面生成最新的前端资源文件,如果`console`模块下的代码没有变更,可以修改`./pom.xml`文件,忽略对`console`模块的打包。
|
||||
|
||||
---
|
||||
|
||||
### 启动
|
||||
|
||||
```
|
||||
############# application.yml 是配置文件
|
||||
cp web/src/main/resources/application.yml web/target/
|
||||
cd web/target/
|
||||
nohup java -jar kafka-manager-web-1.1.0-SNAPSHOT.jar --spring.config.location=./application.yml > /dev/null 2>&1 &
|
||||
```
|
||||
|
||||
### 使用
|
||||
|
||||
本地启动的话,访问`http://localhost:8080`,输入帐号及密码进行登录。更多参考:[kafka-manager使用手册](doc/user_cn_guide.md)
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [kafka-manager安装手册](./docs/install_cn_guide.md)
|
||||
- [kafka-manager使用手册](./docs/user_cn_guide.md)
|
||||
- [kafka-manager使用手册](doc/user_cn_guide.md)
|
||||
|
||||
|
||||
## 钉钉交流群
|
||||
|
||||

|
||||
搜索群号:`32821440` 或者扫码可入群交流. 备注:在钉钉搜索框搜索`32821440`,然后搜索结果中点击 "网络查找手机/邮箱/钉钉号" 即可看到我们的钉钉群:滴滴KafkaManager开源用户群。
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
## 项目成员
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<artifactId>kafka-manager-common</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>kafka-manager</artifactId>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.dto.consumer;
|
||||
|
||||
import com.xiaojukeji.kafka.manager.common.entity.zookeeper.PartitionState;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -11,20 +8,33 @@ import java.util.Map;
|
||||
* @date 2015/11/12
|
||||
*/
|
||||
public class ConsumerDTO {
|
||||
/**
|
||||
* 消费group名
|
||||
*/
|
||||
private Long clusterId;
|
||||
|
||||
private String topicName;
|
||||
|
||||
private String consumerGroup;
|
||||
|
||||
/**
|
||||
* 消费类型,一般为static
|
||||
*/
|
||||
private String location;
|
||||
|
||||
/**
|
||||
* 订阅的每个topic的partition状态列表
|
||||
*/
|
||||
private Map<String, List<PartitionState>> topicPartitionMap;
|
||||
private Map<Integer, Long> partitionOffsetMap;
|
||||
|
||||
private Map<Integer, Long> consumerOffsetMap;
|
||||
|
||||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
public void setClusterId(Long clusterId) {
|
||||
this.clusterId = clusterId;
|
||||
}
|
||||
|
||||
public String getTopicName() {
|
||||
return topicName;
|
||||
}
|
||||
|
||||
public void setTopicName(String topicName) {
|
||||
this.topicName = topicName;
|
||||
}
|
||||
|
||||
public String getConsumerGroup() {
|
||||
return consumerGroup;
|
||||
@@ -42,20 +52,31 @@ public class ConsumerDTO {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public Map<String, List<PartitionState>> getTopicPartitionMap() {
|
||||
return topicPartitionMap;
|
||||
public Map<Integer, Long> getPartitionOffsetMap() {
|
||||
return partitionOffsetMap;
|
||||
}
|
||||
|
||||
public void setTopicPartitionMap(Map<String, List<PartitionState>> topicPartitionMap) {
|
||||
this.topicPartitionMap = topicPartitionMap;
|
||||
public void setPartitionOffsetMap(Map<Integer, Long> partitionOffsetMap) {
|
||||
this.partitionOffsetMap = partitionOffsetMap;
|
||||
}
|
||||
|
||||
public Map<Integer, Long> getConsumerOffsetMap() {
|
||||
return consumerOffsetMap;
|
||||
}
|
||||
|
||||
public void setConsumerOffsetMap(Map<Integer, Long> consumerOffsetMap) {
|
||||
this.consumerOffsetMap = consumerOffsetMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Consumer{" +
|
||||
"consumerGroup='" + consumerGroup + '\'' +
|
||||
return "ConsumerDTO{" +
|
||||
"clusterId=" + clusterId +
|
||||
", topicName='" + topicName + '\'' +
|
||||
", consumerGroup='" + consumerGroup + '\'' +
|
||||
", location='" + location + '\'' +
|
||||
", topicPartitionMap=" + topicPartitionMap +
|
||||
", partitionOffsetMap=" + partitionOffsetMap +
|
||||
", consumerOffsetMap=" + consumerOffsetMap +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@ public class OrderPartitionDO extends BaseDO{
|
||||
|
||||
private String applicant;
|
||||
|
||||
private Integer partitionNum;
|
||||
|
||||
private String brokerList;
|
||||
|
||||
private Long peakBytesIn;
|
||||
|
||||
private String description;
|
||||
@@ -51,6 +55,22 @@ public class OrderPartitionDO extends BaseDO{
|
||||
this.applicant = applicant;
|
||||
}
|
||||
|
||||
public Integer getPartitionNum() {
|
||||
return partitionNum;
|
||||
}
|
||||
|
||||
public void setPartitionNum(Integer partitionNum) {
|
||||
this.partitionNum = partitionNum;
|
||||
}
|
||||
|
||||
public String getBrokerList() {
|
||||
return brokerList;
|
||||
}
|
||||
|
||||
public void setBrokerList(String brokerList) {
|
||||
this.brokerList = brokerList;
|
||||
}
|
||||
|
||||
public Long getPeakBytesIn() {
|
||||
return peakBytesIn;
|
||||
}
|
||||
@@ -98,6 +118,8 @@ public class OrderPartitionDO extends BaseDO{
|
||||
", clusterName='" + clusterName + '\'' +
|
||||
", topicName='" + topicName + '\'' +
|
||||
", applicant='" + applicant + '\'' +
|
||||
", partitionNum=" + partitionNum +
|
||||
", brokerList='" + brokerList + '\'' +
|
||||
", peakBytesIn=" + peakBytesIn +
|
||||
", description='" + description + '\'' +
|
||||
", orderStatus=" + orderStatus +
|
||||
|
||||
184
console/package-lock.json
generated
@@ -69,6 +69,12 @@
|
||||
"scheduler": "^0.13.6"
|
||||
}
|
||||
},
|
||||
"@types/anymatch": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/anymatch/download/@types/anymatch-1.3.1.tgz?cache=0&sync_timestamp=1580841236934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fanymatch%2Fdownload%2F%40types%2Fanymatch-1.3.1.tgz",
|
||||
"integrity": "sha1-M2utwb7sudrMOL6izzKt9ieoQho=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/echarts": {
|
||||
"version": "4.1.9",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/echarts/download/@types/echarts-4.1.9.tgz",
|
||||
@@ -78,6 +84,23 @@
|
||||
"@types/zrender": "*"
|
||||
}
|
||||
},
|
||||
"@types/events": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/events/download/@types/events-3.0.0.tgz?cache=0&sync_timestamp=1580841806837&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fevents%2Fdownload%2F%40types%2Fevents-3.0.0.tgz",
|
||||
"integrity": "sha1-KGLz9Yqaf3w+eNefEw3U1xwlwqc=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/glob": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/glob/download/@types/glob-7.1.1.tgz",
|
||||
"integrity": "sha1-qlmhxuP7xCHgfM0xqUTDDrpSFXU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/events": "*",
|
||||
"@types/minimatch": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/history": {
|
||||
"version": "4.7.2",
|
||||
"resolved": "http://registry.npm.taobao.org/@types/history/download/@types/history-4.7.2.tgz",
|
||||
@@ -90,6 +113,18 @@
|
||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/minimatch": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/minimatch/download/@types/minimatch-3.0.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fminimatch%2Fdownload%2F%40types%2Fminimatch-3.0.3.tgz",
|
||||
"integrity": "sha1-PcoOPzOyAPx9ETnAzZbBJoyt/Z0=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "13.9.8",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-13.9.8.tgz",
|
||||
"integrity": "sha1-CZdkIPyAp6AL9AaAxjgV7Yx2FvQ=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.1",
|
||||
"resolved": "http://registry.npm.taobao.org/@types/prop-types/download/@types/prop-types-15.7.1.tgz",
|
||||
@@ -151,6 +186,76 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/source-list-map": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/source-list-map/download/@types/source-list-map-0.1.2.tgz",
|
||||
"integrity": "sha1-AHiDYGP/rxdBI0m7o2QIfgrALsk=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/tapable": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/tapable/download/@types/tapable-1.0.5.tgz?cache=0&sync_timestamp=1580844951142&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Ftapable%2Fdownload%2F%40types%2Ftapable-1.0.5.tgz",
|
||||
"integrity": "sha1-mtvBKVBYKqZerXa//fOf4MJ6PAI=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/uglify-js": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/uglify-js/download/@types/uglify-js-3.0.4.tgz",
|
||||
"integrity": "sha1-lr6uI99vVhhiqDC0KIpJ6GuqwII=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz",
|
||||
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/webpack": {
|
||||
"version": "4.41.10",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/webpack/download/@types/webpack-4.41.10.tgz",
|
||||
"integrity": "sha1-Lh9rNQiiSYVO/j3MdpCQWsXuEL4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/anymatch": "*",
|
||||
"@types/node": "*",
|
||||
"@types/tapable": "*",
|
||||
"@types/uglify-js": "*",
|
||||
"@types/webpack-sources": "*",
|
||||
"source-map": "^0.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz",
|
||||
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/webpack-sources": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/webpack-sources/download/@types/webpack-sources-0.1.7.tgz?cache=0&sync_timestamp=1584978716401&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fwebpack-sources%2Fdownload%2F%40types%2Fwebpack-sources-0.1.7.tgz",
|
||||
"integrity": "sha1-CjMKlFYRNBDHSl1kGArwy8oAcUE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"@types/source-list-map": "*",
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz",
|
||||
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/zrender": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/zrender/download/@types/zrender-4.0.0.tgz",
|
||||
@@ -1271,6 +1376,33 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"clean-webpack-plugin": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/clean-webpack-plugin/download/clean-webpack-plugin-3.0.0.tgz",
|
||||
"integrity": "sha1-qZ2Ow0wcYopFQVZ6p7RXRGRgxis=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/webpack": "^4.4.31",
|
||||
"del": "^4.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"del": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npm.taobao.org/del/download/del-4.1.1.tgz",
|
||||
"integrity": "sha1-no8RciLqRKMf86FWwEm5kFKp8LQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/glob": "^7.1.1",
|
||||
"globby": "^6.1.0",
|
||||
"is-path-cwd": "^2.0.0",
|
||||
"is-path-in-cwd": "^2.0.0",
|
||||
"p-map": "^2.0.0",
|
||||
"pify": "^4.0.1",
|
||||
"rimraf": "^2.6.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "http://registry.npm.taobao.org/cliui/download/cliui-4.1.0.tgz",
|
||||
@@ -1656,6 +1788,58 @@
|
||||
"gud": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"cross-env": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npm.taobao.org/cross-env/download/cross-env-7.0.2.tgz?cache=0&sync_timestamp=1583443602692&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-env%2Fdownload%2Fcross-env-7.0.2.tgz",
|
||||
"integrity": "sha1-vV7TEzmpOjQYrE88qco0Awgq5fk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cross-spawn": "^7.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"cross-spawn": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-7.0.1.tgz",
|
||||
"integrity": "sha1-CrVihuD3wk4VPQTMKqAn5DqaXRQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npm.taobao.org/path-key/download/path-key-3.1.1.tgz",
|
||||
"integrity": "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=",
|
||||
"dev": true
|
||||
},
|
||||
"shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-2.0.0.tgz?cache=0&sync_timestamp=1567781622888&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshebang-command%2Fdownload%2Fshebang-command-2.0.0.tgz",
|
||||
"integrity": "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=",
|
||||
"dev": true
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwhich%2Fdownload%2Fwhich-2.0.2.tgz",
|
||||
"integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "http://registry.npm.taobao.org/cross-spawn/download/cross-spawn-6.0.5.tgz",
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"start": "webpack-dev-server",
|
||||
"daily-build": "rm -rf dist && NODE_ENV=production webpack",
|
||||
"pre-build": "rm -rf dist && NODE_ENV=production webpack",
|
||||
"prod-build": "rm -rf dist && NODE_ENV=production webpack"
|
||||
"daily-build": "cross-env NODE_ENV=production webpack",
|
||||
"pre-build": "cross-env NODE_ENV=production webpack",
|
||||
"prod-build": "cross-env NODE_ENV=production webpack"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
@@ -17,6 +17,8 @@
|
||||
"@types/react-dom": "^16.8.2",
|
||||
"@types/react-router-dom": "^4.3.1",
|
||||
"antd": "^3.16.1",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"cross-env": "^7.0.2",
|
||||
"css-loader": "^2.1.0",
|
||||
"echarts": "^4.2.1",
|
||||
"file-loader": "^5.0.2",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>kafka-manager</artifactId>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>kafka-manager-console</artifactId>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IClusterData } from 'types/base-type';
|
||||
|
||||
const TabPane = Tabs.TabPane;
|
||||
|
||||
const detailUrl ='/admin/cluster_detail?clusterId=';
|
||||
const detailUrl = '/admin/cluster_detail?clusterId=';
|
||||
|
||||
const collectionColumns: Array<ColumnProps<IClusterData>> = [
|
||||
{
|
||||
@@ -24,7 +24,8 @@ const collectionColumns: Array<ColumnProps<IClusterData>> = [
|
||||
key: 'clusterName',
|
||||
sorter: (a: IClusterData, b: IClusterData) => a.clusterName.charCodeAt(0) - b.clusterName.charCodeAt(0),
|
||||
render: (text, record) => {
|
||||
return <a href={`${detailUrl}${record.clusterId}`}>{record.clusterName}</a>;
|
||||
const url = `${detailUrl}${record.clusterId}&clusterName=${record.clusterName}`;
|
||||
return <a href={encodeURI(url)}>{record.clusterName}</a>;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -39,10 +39,10 @@ export class UserManage extends SearchAndFilter {
|
||||
public renderColumns = () => {
|
||||
const role = Object.assign({
|
||||
title: '角色',
|
||||
key: 'role',
|
||||
dataIndex: 'role',
|
||||
key: 'roleName',
|
||||
dataIndex: 'roleName',
|
||||
filters: users.filterRole,
|
||||
onFilter: (value: string, record: any) => record.role.indexOf(value) === 0,
|
||||
onFilter: (value: string, record: any) => record.roleName.indexOf(value) === 0,
|
||||
}, this.renderColumnsFilter('filterVisible'));
|
||||
|
||||
return [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import './index.less';
|
||||
import { Table, Modal, notification, PaginationConfig, Button } from 'component/antd';
|
||||
import { Table, Modal, notification, PaginationConfig, Button, Spin } from 'component/antd';
|
||||
import { broker, IBroker, IBrokerNetworkInfo, IBrokerPartition } from 'store/broker';
|
||||
import { observer } from 'mobx-react';
|
||||
import { StatusGraghCom } from 'component/flow-table';
|
||||
@@ -49,10 +49,19 @@ export class BrokerList extends SearchAndFilter {
|
||||
|
||||
const status = Object.assign({
|
||||
title: '已同步',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
filters: [{ text: '是', value: '是' }, { text: '否', value: '否' }],
|
||||
onFilter: (value: string, record: IBrokerPartition) => record.status === value,
|
||||
dataIndex: 'underReplicatedPartitionCount',
|
||||
key: 'underReplicatedPartitionCount',
|
||||
filters: [{ text: '是', value: '1' }, { text: '否', value: '0' }],
|
||||
onFilter: (value: string, record: IBrokerPartition) => {
|
||||
// underReplicatedPartitionCount > 0 表示未同步完成
|
||||
const syncStatus = record.underReplicatedPartitionCount ? '0' : '1';
|
||||
return syncStatus === value;
|
||||
},
|
||||
render: (text: number) => (
|
||||
<>
|
||||
<span style={{ marginRight: 8 }}>{text ? '否' : '是'}</span>
|
||||
</>
|
||||
),
|
||||
}, this.renderColumnsFilter('filterVisible'));
|
||||
|
||||
return [{
|
||||
@@ -80,7 +89,8 @@ export class BrokerList extends SearchAndFilter {
|
||||
title: '未同步副本数量',
|
||||
dataIndex: 'notUnderReplicatedPartitionCount',
|
||||
key: 'notUnderReplicatedPartitionCount',
|
||||
sorter: (a: IBrokerPartition, b: IBrokerPartition) => a.notUnderReplicatedPartitionCount - b.notUnderReplicatedPartitionCount,
|
||||
sorter: (a: IBrokerPartition, b: IBrokerPartition) =>
|
||||
a.notUnderReplicatedPartitionCount - b.notUnderReplicatedPartitionCount,
|
||||
},
|
||||
status,
|
||||
region,
|
||||
@@ -205,7 +215,7 @@ export class BrokerList extends SearchAndFilter {
|
||||
const dataPartitions = this.state.searchId !== '' ?
|
||||
broker.partitions.filter((d) => d.brokerId === +this.state.searchId) : broker.partitions;
|
||||
return (
|
||||
<>
|
||||
<Spin spinning={broker.loading}>
|
||||
<div className="k-row">
|
||||
<ul className="k-tab">
|
||||
<li>Broker概览</li>
|
||||
@@ -239,7 +249,7 @@ export class BrokerList extends SearchAndFilter {
|
||||
pagination={pagination}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
</Spin>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,14 +49,14 @@ export class SearchAndFilter extends React.Component<any, IState> {
|
||||
}
|
||||
|
||||
public handleVisble = (type: string) => {
|
||||
if (this.timer) clearTimeout(this.timer);
|
||||
setTimeout(() => {
|
||||
if (this.timer) window.clearTimeout(this.timer);
|
||||
window.setTimeout(() => {
|
||||
this.setState({ [type]: true });
|
||||
});
|
||||
}
|
||||
|
||||
public handleUnVisble = (type: string) => {
|
||||
this.timer = setTimeout(() => {
|
||||
this.timer = window.setTimeout(() => {
|
||||
this.setState({ [type]: false });
|
||||
}, 100);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class ResetOffset extends React.Component<any> {
|
||||
consume.offsetPartition(Object.assign({ timestamp: +moment(timestamp).format('x') }, topic.currentGroup))
|
||||
.then(() => {
|
||||
message.success('重置时间成功');
|
||||
setTimeout(() => {
|
||||
window.setTimeout(() => {
|
||||
location.reload();
|
||||
}, 200);
|
||||
});
|
||||
@@ -28,7 +28,7 @@ class ResetOffset extends React.Component<any> {
|
||||
public submitPartiton = () => {
|
||||
consume.offsetPartition(topic.currentGroup, 1).then(() => {
|
||||
message.success('重置分区成功');
|
||||
setTimeout(() => {
|
||||
window.setTimeout(() => {
|
||||
location.reload();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
@@ -45,14 +45,19 @@ class LeaderRebalance extends React.Component<any> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
const url = Url();
|
||||
this.clusterName = decodeURI(atob(url.search.clusterName));
|
||||
if (url.search.clusterName) {
|
||||
this.clusterName = decodeURI(url.search.clusterName);
|
||||
}
|
||||
this.clusterId = Number(url.search.clusterId);
|
||||
}
|
||||
|
||||
public handleSubmit = (e: React.MouseEvent<any, MouseEvent>) => {
|
||||
e.preventDefault();
|
||||
this.setState({ loading: true });
|
||||
this.props.form.validateFieldsAndScroll((err: any, values: any) => {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
this.setState({ loading: true });
|
||||
this.brokerId = Number(values.brokerId);
|
||||
addRebalance({ brokerId: this.brokerId, clusterId: this.clusterId, dimension: 0 }).then(() => {
|
||||
cluster.getRebalance(this.clusterId).then(() => {
|
||||
|
||||
@@ -28,7 +28,7 @@ class Task extends React.Component<any> {
|
||||
values.partitionIdList = typeof partitionIdList === 'string' ? values.partitionIdList.split(',') : [];
|
||||
if (this.getDisabled()) {
|
||||
const { taskId } = operation.taskDetail;
|
||||
modifyTask({ throttle, taskId, action: 'modify' }).then(() => {
|
||||
modifyTask({ throttle: values.throttle, taskId, action: 'modify' }).then(() => {
|
||||
notification.success({ message: '修改成功' });
|
||||
operation.getTask();
|
||||
modal.close();
|
||||
|
||||
@@ -36,7 +36,7 @@ class Topic extends React.Component<any> {
|
||||
this.setState({ loading: true });
|
||||
createTopic(values).then(data => {
|
||||
notification.success({ message: '申请Topic成功' });
|
||||
setTimeout(() => location.assign('/user/my_order'), 500);
|
||||
window.setTimeout(() => location.assign('/user/my_order'), 500);
|
||||
modal.close();
|
||||
}, (err) => {
|
||||
this.setState({ loading: false });
|
||||
|
||||
@@ -35,6 +35,7 @@ export interface IBrokerPartition extends IBroker {
|
||||
leaderCount: number;
|
||||
partitionCount: number;
|
||||
notUnderReplicatedPartitionCount: number;
|
||||
underReplicatedPartitionCount?: number;
|
||||
regionName: string;
|
||||
bytesInPerSec: number;
|
||||
}
|
||||
@@ -74,6 +75,9 @@ interface IBrokerOption {
|
||||
}
|
||||
|
||||
class Broker {
|
||||
@observable
|
||||
public loading: boolean = false;
|
||||
|
||||
@observable
|
||||
public brokerBaseInfo: IBrokerBaseInfo = {} as IBrokerBaseInfo;
|
||||
|
||||
@@ -119,6 +123,11 @@ class Broker {
|
||||
@observable
|
||||
public BrokerOptions: IValueLabel[] = [{ value: null, label: '请选择Broker' }];
|
||||
|
||||
@action.bound
|
||||
public setLoading(value: boolean) {
|
||||
this.loading = value;
|
||||
}
|
||||
|
||||
@action.bound
|
||||
public setBrokerBaseInfo(data: IBrokerBaseInfo) {
|
||||
data.startTime = moment(data.startTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
@@ -216,7 +225,8 @@ class Broker {
|
||||
}
|
||||
|
||||
public getBrokerList(clusterId: number) {
|
||||
getBrokerList(clusterId).then(this.setBrokerList);
|
||||
this.setLoading(true);
|
||||
getBrokerList(clusterId).then(this.setBrokerList).finally(() => this.setLoading(false));
|
||||
}
|
||||
|
||||
public getBrokerNetwork(clusterId: number) {
|
||||
@@ -224,7 +234,8 @@ class Broker {
|
||||
}
|
||||
|
||||
public getBrokerPartition(clusterId: number) {
|
||||
getBrokerPartition(clusterId).then(this.setBrokerPartition);
|
||||
this.setLoading(true);
|
||||
getBrokerPartition(clusterId).then(this.setBrokerPartition).finally(() => this.setLoading(false));
|
||||
}
|
||||
|
||||
public getOneBrokerNetwork(clusterId: number, brokerId: number) {
|
||||
|
||||
@@ -111,7 +111,7 @@ class Cluster {
|
||||
return getRebalanceStatus(clusterId).then((type) => {
|
||||
this.setLeaderStatus(type);
|
||||
if (type === 'RUNNING') {
|
||||
setTimeout(() => {
|
||||
window.setTimeout(() => {
|
||||
this.getRebalance(clusterId);
|
||||
}, 1000 * 2);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export class Users {
|
||||
@action.bound
|
||||
public setUserData(data: []) {
|
||||
this.userData = data.map((d: any) => {
|
||||
d.role = this.roleMap[d.role];
|
||||
d.roleName = this.roleMap[d.role];
|
||||
return d;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const TerserJSPlugin = require('terser-webpack-plugin');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
const outPath = `${__dirname}/dist`;
|
||||
@@ -20,7 +21,7 @@ const plugins = [
|
||||
if (isProd) {
|
||||
plugins.push(new MiniCssExtractPlugin({
|
||||
filename: `${filename}.css`,
|
||||
}));
|
||||
}), new CleanWebpackPlugin());
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<artifactId>kafka-manager-dao</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>kafka-manager</artifactId>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
@@ -43,5 +43,9 @@
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
<version>2.5.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -18,6 +18,9 @@ public class AccountDaoImpl implements AccountDao {
|
||||
@Autowired
|
||||
private SqlSessionTemplate sqlSession;
|
||||
|
||||
@Autowired
|
||||
private KafkaManagerProperties kafkaManagerProperties;
|
||||
|
||||
public void setSqlSession(SqlSessionTemplate sqlSession) {
|
||||
this.sqlSession = sqlSession;
|
||||
}
|
||||
@@ -25,7 +28,7 @@ public class AccountDaoImpl implements AccountDao {
|
||||
@Override
|
||||
public int addNewAccount(AccountDO accountDO) {
|
||||
accountDO.setStatus(DBStatusEnum.NORMAL.getStatus());
|
||||
return sqlSession.insert("AccountDao.insert", accountDO);
|
||||
return updateAccount(accountDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -35,6 +38,9 @@ public class AccountDaoImpl implements AccountDao {
|
||||
|
||||
@Override
|
||||
public int updateAccount(AccountDO accountDO) {
|
||||
if (kafkaManagerProperties.hasPG()) {
|
||||
return sqlSession.insert("AccountDao.insertOnPG", accountDO);
|
||||
}
|
||||
return sqlSession.insert("AccountDao.insert", accountDO);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,18 @@ public class BrokerDaoImpl implements BrokerDao {
|
||||
@Autowired
|
||||
private SqlSessionTemplate sqlSession;
|
||||
|
||||
@Autowired
|
||||
private KafkaManagerProperties kafkaManagerProperties;
|
||||
|
||||
public void setSqlSession(SqlSessionTemplate sqlSession) {
|
||||
this.sqlSession = sqlSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int replace(BrokerDO brokerInfoDO) {
|
||||
if (kafkaManagerProperties.hasPG()) {
|
||||
return sqlSession.insert("BrokerDao.replaceOnPG", brokerInfoDO);
|
||||
}
|
||||
return sqlSession.insert("BrokerDao.replace", brokerInfoDO);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xiaojukeji.kafka.manager.dao.impl;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties("spring.datasource.kafka-manager")
|
||||
public class KafkaManagerProperties {
|
||||
private String jdbcUrl;
|
||||
|
||||
public String getJdbcUrl() {
|
||||
return jdbcUrl;
|
||||
}
|
||||
|
||||
public void setJdbcUrl(String jdbcUrl) {
|
||||
this.jdbcUrl = jdbcUrl;
|
||||
}
|
||||
|
||||
public boolean hasPG() {
|
||||
return jdbcUrl.startsWith("jdbc:postgres");
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,18 @@ public class RegionDaoImpl implements RegionDao {
|
||||
@Autowired
|
||||
private SqlSessionTemplate sqlSession;
|
||||
|
||||
@Autowired
|
||||
private KafkaManagerProperties kafkaManagerProperties;
|
||||
|
||||
public void setSqlSession(SqlSessionTemplate sqlSession) {
|
||||
this.sqlSession = sqlSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insert(RegionDO regionDO) {
|
||||
if (kafkaManagerProperties.hasPG()) {
|
||||
return sqlSession.insert("RegionDao.insertOnPG", regionDO);
|
||||
}
|
||||
return sqlSession.insert("RegionDao.insert", regionDO);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,18 @@ public class TopicDaoImpl implements TopicDao {
|
||||
@Autowired
|
||||
private SqlSessionTemplate sqlSession;
|
||||
|
||||
@Autowired
|
||||
private KafkaManagerProperties kafkaManagerProperties;
|
||||
|
||||
public void setSqlSession(SqlSessionTemplate sqlSession) {
|
||||
this.sqlSession = sqlSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int replace(TopicDO topicDO) {
|
||||
if (kafkaManagerProperties.hasPG()) {
|
||||
return sqlSession.insert("TopicDao.replaceOnPG", topicDO);
|
||||
}
|
||||
return sqlSession.insert("TopicDao.replace", topicDO);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,18 @@ public class TopicFavoriteDaoImpl implements TopicFavoriteDao {
|
||||
@Autowired
|
||||
private TransactionTemplate transactionTemplate;
|
||||
|
||||
@Autowired
|
||||
private KafkaManagerProperties kafkaManagerProperties;
|
||||
|
||||
public void setSqlSession(SqlSessionTemplate sqlSession) {
|
||||
this.sqlSession = sqlSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int batchAdd(List<TopicFavoriteDO> topicFavoriteDOList) {
|
||||
if (kafkaManagerProperties.hasPG()) {
|
||||
return sqlSession.insert("TopicFavoriteDao.batchAddOnPG", topicFavoriteDOList);
|
||||
}
|
||||
return sqlSession.insert("TopicFavoriteDao.batchAdd", topicFavoriteDOList);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,18 @@
|
||||
]]>
|
||||
</insert>
|
||||
|
||||
<insert id="insertOnPG" parameterType="com.xiaojukeji.kafka.manager.common.entity.po.AccountDO">
|
||||
<![CDATA[
|
||||
insert into account
|
||||
(username, password, role, status)
|
||||
values
|
||||
(#{username}, #{password}, #{role}, #{status})
|
||||
on conflict (username) do update set password = excluded.password,
|
||||
role = excluded.role,
|
||||
status = excluded.status
|
||||
]]>
|
||||
</insert>
|
||||
|
||||
<delete id="deleteByName" parameterType="java.lang.String">
|
||||
DELETE FROM account WHERE username = #{username}
|
||||
</delete>
|
||||
|
||||
@@ -20,6 +20,16 @@
|
||||
(#{clusterId}, #{brokerId}, #{host}, #{port}, #{timestamp}, #{status})
|
||||
</insert>
|
||||
|
||||
<insert id="replaceOnPG" parameterType="BrokerDO">
|
||||
insert into broker
|
||||
(cluster_id, broker_id, host, port, timestamp, status)
|
||||
values (#{clusterId}, #{brokerId}, #{host}, #{port}, #{timestamp}, #{status})
|
||||
on conflict (cluster_id, broker_id) do update set host = excluded.host,
|
||||
port = excluded.port,
|
||||
timestamp = excluded.timestamp,
|
||||
status = excluded.status
|
||||
</insert>
|
||||
|
||||
<delete id="deleteById" parameterType="java.util.Map">
|
||||
DELETE FROM broker WHERE cluster_id = #{clusterId} AND broker_id = #{brokerId}
|
||||
</delete>
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
<result column="cluster_name" property="clusterName" />
|
||||
<result column="topic_name" property="topicName" />
|
||||
<result column="applicant" property="applicant" />
|
||||
<result column="partition_num" property="partitionNum" />
|
||||
<result column="broker_list" property="brokerList" />
|
||||
<result column="peak_bytes_in" property="peakBytesIn" />
|
||||
<result column="description" property="description" />
|
||||
<result column="order_status" property="orderStatus" />
|
||||
@@ -38,6 +40,16 @@
|
||||
cluster_name=#{clusterName},
|
||||
topic_name=#{topicName},
|
||||
applicant=#{applicant},
|
||||
<trim>
|
||||
<if test="partitionNum!=null">
|
||||
partition_num=#{partitionNum},
|
||||
</if>
|
||||
</trim>
|
||||
<trim>
|
||||
<if test="brokerList!=null">
|
||||
broker_list=#{brokerList},
|
||||
</if>
|
||||
</trim>
|
||||
peak_bytes_in=#{peakBytesIn},
|
||||
description=#{description},
|
||||
order_status=#{orderStatus},
|
||||
|
||||
@@ -21,6 +21,15 @@
|
||||
(#{regionName}, #{clusterId}, #{brokerList}, #{description}, #{operator})
|
||||
</insert>
|
||||
|
||||
<insert id="insertOnPG" parameterType="com.xiaojukeji.kafka.manager.common.entity.po.RegionDO">
|
||||
insert into region
|
||||
(region_name, cluster_id, broker_list, description, operator)
|
||||
values (#{regionName}, #{clusterId}, #{brokerList}, #{description}, #{operator})
|
||||
on conflict (region_name, cluster_id) do update set broker_list = excluded.broker_list,
|
||||
description = excluded.description,
|
||||
operator = excluded.operator
|
||||
</insert>
|
||||
|
||||
<delete id="deleteById" parameterType="java.lang.Long">
|
||||
DELETE FROM region WHERE id = #{id}
|
||||
</delete>
|
||||
|
||||
@@ -19,6 +19,15 @@
|
||||
(#{clusterId}, #{topicName}, #{principals}, #{description}, #{status})
|
||||
</insert>
|
||||
|
||||
<insert id="replaceOnPG" parameterType="com.xiaojukeji.kafka.manager.common.entity.po.TopicDO">
|
||||
insert into topic
|
||||
(cluster_id, topic_name, principals, description, status)
|
||||
values (#{clusterId}, #{topicName}, #{principals}, #{description}, #{status})
|
||||
on conflict (cluster_id, topic_name) do update set principals = excluded.principals,
|
||||
description = excluded.description,
|
||||
status = excluded.status
|
||||
</insert>
|
||||
|
||||
<delete id="deleteById" parameterType="java.lang.Long">
|
||||
DELETE FROM topic WHERE id = #{id}
|
||||
</delete>
|
||||
|
||||
@@ -21,6 +21,15 @@
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<insert id="batchAddOnPG" parameterType="java.util.List">
|
||||
insert into topic_favorite (cluster_id, topic_name, username)
|
||||
values
|
||||
<foreach item="TopicFavoriteDO" index="index" collection="list" separator=",">
|
||||
(#{TopicFavoriteDO.clusterId}, #{TopicFavoriteDO.topicName}, #{TopicFavoriteDO.username})
|
||||
</foreach>
|
||||
on conflict (cluster_id, topic_name, username) do update set gmt_modify = now();
|
||||
</insert>
|
||||
|
||||
<delete id="deleteById" parameterType="java.lang.Long">
|
||||
DELETE FROM topic_favorite WHERE id=#{id}
|
||||
</delete>
|
||||
|
||||
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
@@ -4,8 +4,8 @@ USE `kafka_manager`;
|
||||
|
||||
CREATE TABLE `account` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`username` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户名',
|
||||
`password` varchar(256) NOT NULL DEFAULT '' COMMENT '密码',
|
||||
`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户名',
|
||||
`password` varchar(128) NOT NULL DEFAULT '' COMMENT '密码',
|
||||
`role` int(16) NOT NULL DEFAULT '0' COMMENT '角色类型, 0:普通用户',
|
||||
`status` int(16) NOT NULL DEFAULT '0' COMMENT '0标识使用中,-1标识已废弃',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
@@ -33,7 +33,7 @@ CREATE TABLE `alarm_rule` (
|
||||
|
||||
CREATE TABLE `broker` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`cluster_id` bigint(128) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerID',
|
||||
`host` varchar(128) NOT NULL DEFAULT '' COMMENT 'Broker主机名',
|
||||
`port` int(32) NOT NULL DEFAULT '-1' COMMENT 'Broker端口',
|
||||
@@ -48,7 +48,7 @@ CREATE TABLE `broker` (
|
||||
|
||||
CREATE TABLE `broker_metrics` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`cluster_id` bigint(11) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerID',
|
||||
`bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流入',
|
||||
`bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流出',
|
||||
@@ -93,7 +93,7 @@ CREATE TABLE `cluster` (
|
||||
|
||||
CREATE TABLE `cluster_metrics` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`cluster_id` bigint(11) NOT NULL DEFAULT '0' COMMENT '集群ID',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群ID',
|
||||
`topic_num` int(11) NOT NULL DEFAULT '0' COMMENT 'Topic数',
|
||||
`partition_num` int(11) NOT NULL DEFAULT '0' COMMENT '分区数',
|
||||
`broker_num` int(11) NOT NULL DEFAULT '0' COMMENT 'Broker数',
|
||||
@@ -121,8 +121,8 @@ CREATE TABLE `controller` (
|
||||
|
||||
CREATE TABLE `migration_task` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`cluster_id` bigint(128) NOT NULL DEFAULT '0' COMMENT '集群ID',
|
||||
`topic_name` varchar(256) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群ID',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`reassignment_json` text COMMENT '任务参数',
|
||||
`real_throttle` bigint(20) NOT NULL DEFAULT '0' COMMENT '实际限流值(B/s)',
|
||||
`operator` varchar(128) NOT NULL DEFAULT '' COMMENT '操作人',
|
||||
@@ -135,8 +135,8 @@ CREATE TABLE `migration_task` (
|
||||
|
||||
CREATE TABLE `operation_history` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`cluster_id` bigint(128) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`operator` varchar(128) NOT NULL DEFAULT '' COMMENT '操作人',
|
||||
`operation` varchar(256) NOT NULL DEFAULT '' COMMENT '操作描述',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
@@ -147,8 +147,10 @@ CREATE TABLE `operation_history` (
|
||||
CREATE TABLE `order_partition` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`cluster_name` varchar(256) NOT NULL DEFAULT '' COMMENT '集群名称',
|
||||
`topic_name` varchar(256) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`broker_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'Broker列表, 逗号分割',
|
||||
`partition_num` int(11) NOT NULL DEFAULT 0 COMMENT '新增分区数',
|
||||
`applicant` varchar(128) NOT NULL DEFAULT '' COMMENT '申请人',
|
||||
`peak_bytes_in` bigint(20) NOT NULL DEFAULT '0' COMMENT '峰值流量',
|
||||
`description` text COMMENT '备注信息',
|
||||
@@ -164,8 +166,8 @@ CREATE TABLE `order_partition` (
|
||||
CREATE TABLE `order_topic` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`cluster_name` varchar(256) NOT NULL DEFAULT '' COMMENT '集群名称',
|
||||
`topic_name` varchar(256) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`retention_time` bigint(20) NOT NULL DEFAULT '-1' COMMENT '保留时间(ms)',
|
||||
`partition_num` int(16) NOT NULL DEFAULT '-1' COMMENT '分区数',
|
||||
`replica_num` int(16) NOT NULL DEFAULT '-1' COMMENT '副本数',
|
||||
@@ -187,7 +189,7 @@ CREATE TABLE `order_topic` (
|
||||
CREATE TABLE `region` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`region_name` varchar(256) NOT NULL DEFAULT '' COMMENT 'Region名称',
|
||||
`region_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'Region名称',
|
||||
`broker_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'Broker列表',
|
||||
`level` int(16) NOT NULL DEFAULT '0' COMMENT 'Region重要等级, 0级普通, 1极重要,2级极重要',
|
||||
`operator` varchar(45) NOT NULL DEFAULT '' COMMENT '操作人',
|
||||
@@ -201,8 +203,8 @@ CREATE TABLE `region` (
|
||||
|
||||
CREATE TABLE `topic` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`cluster_id` bigint(128) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`applicant` varchar(256) NOT NULL DEFAULT '' COMMENT '申请人',
|
||||
`principals` varchar(256) NOT NULL DEFAULT '' COMMENT '负责人',
|
||||
`description` text COMMENT '备注信息',
|
||||
@@ -216,9 +218,9 @@ CREATE TABLE `topic` (
|
||||
|
||||
CREATE TABLE `topic_favorite` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
|
||||
`username` varchar(128) NOT NULL DEFAULT '' COMMENT '用户名',
|
||||
`username` varchar(64) NOT NULL DEFAULT '' COMMENT '用户名',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(512) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`status` int(16) NOT NULL DEFAULT '0' COMMENT '删除标记, 0表示未删除, -1表示删除',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
@@ -228,8 +230,8 @@ CREATE TABLE `topic_favorite` (
|
||||
|
||||
CREATE TABLE `topic_metrics` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`cluster_id` bigint(11) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(256) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒进入消息条数',
|
||||
`bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流入',
|
||||
`bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流出',
|
||||
325
doc/create_postgresql_table.sql
Normal file
@@ -0,0 +1,325 @@
|
||||
-- CREATE DATABASE kafka_manager;
|
||||
-- \c kafka_manager;
|
||||
SET TIME ZONE 'Asia/Chongqing';
|
||||
SET CLIENT_ENCODING TO 'UTF-8';
|
||||
|
||||
CREATE OR REPLACE FUNCTION on_update_timestamp() RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
new.gmt_modify = current_timestamp;
|
||||
return new;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 账号表
|
||||
CREATE TABLE account
|
||||
(
|
||||
id bigserial NOT NULL, -- 'ID',
|
||||
username varchar(64) NOT NULL UNIQUE DEFAULT '', -- '用户名',
|
||||
password varchar(128) NOT NULL DEFAULT '', -- '密码',
|
||||
role int NOT NULL DEFAULT 0, -- '角色类型, 0:普通用户',
|
||||
status int NOT NULL DEFAULT 0, -- '0标识使用中,-1标识已废弃',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间',
|
||||
CONSTRAINT account_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE UNIQUE INDEX account_uniq_username ON account (username);
|
||||
INSERT INTO account(username, password, role)
|
||||
VALUES ('admin', '21232f297a57a5a743894a0e4a801fc3', 2);
|
||||
CREATE TRIGGER account_trig_gmt_modify
|
||||
BEFORE UPDATE
|
||||
ON account
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_update_timestamp();
|
||||
|
||||
-- 告警规则表
|
||||
CREATE TABLE alarm_rule
|
||||
(
|
||||
id bigserial, -- '自增ID',
|
||||
alarm_name varchar(128) NOT NULL DEFAULT '', -- '告警名字',
|
||||
strategy_expressions text, -- '表达式',
|
||||
strategy_filters text, -- '过滤条件',
|
||||
strategy_actions text, -- '响应',
|
||||
principals varchar(512) NOT NULL DEFAULT '', -- '负责人',
|
||||
status int2 NOT NULL DEFAULT 1, -- '-1:逻辑删除, 0:关闭, 1:正常',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间',
|
||||
CONSTRAINT alarm_rule_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE UNIQUE INDEX alarm_rule_uniq_alarm_name ON alarm_rule (alarm_name);
|
||||
CREATE TRIGGER alarm_rule_trig_gmt_modify
|
||||
BEFORE UPDATE
|
||||
ON alarm_rule
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_update_timestamp();
|
||||
|
||||
-- Broker信息表
|
||||
CREATE TABLE broker
|
||||
(
|
||||
id bigserial, -- 'id',
|
||||
cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID',
|
||||
broker_id int NOT NULL DEFAULT '-1', -- 'BrokerID',
|
||||
host varchar(128) NOT NULL DEFAULT '', -- 'Broker主机名',
|
||||
port int NOT NULL DEFAULT '-1', -- 'Broker端口',
|
||||
timestamp bigint NOT NULL DEFAULT '-1', -- '启动时间',
|
||||
status int NOT NULL DEFAULT '0', -- '状态0有效,-1无效',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间',
|
||||
CONSTRAINT broker_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE UNIQUE INDEX broker_uniq_cluster_id_broker_id ON broker (cluster_id, broker_id);
|
||||
CREATE TRIGGER broker_trig_gmt_modify
|
||||
BEFORE UPDATE
|
||||
ON broker
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_update_timestamp();
|
||||
|
||||
-- BrokerMetric信息表
|
||||
CREATE TABLE broker_metrics
|
||||
(
|
||||
id bigserial, -- '自增id',
|
||||
cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID',
|
||||
broker_id int NOT NULL DEFAULT '-1', -- 'BrokerID',
|
||||
bytes_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒字节流入',
|
||||
bytes_out decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒字节流出',
|
||||
bytes_rejected decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒被拒绝字节数',
|
||||
messages_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒消息数流入',
|
||||
fail_fetch_request decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒消费失败数',
|
||||
fail_produce_request decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒失败生产数',
|
||||
fetch_consumer_request decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒消费请求数',
|
||||
produce_request decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒生产数',
|
||||
request_handler_idl_percent decimal(53, 2) NOT NULL DEFAULT '0.00', -- '请求处理器繁忙百分比',
|
||||
network_processor_idl_percent decimal(53, 2) NOT NULL DEFAULT '0.00', -- '网络处理器繁忙百分比',
|
||||
request_queue_size bigint NOT NULL DEFAULT '0', -- '请求列表大小',
|
||||
response_queue_size bigint NOT NULL DEFAULT '0', -- '响应列表大小',
|
||||
log_flush_time decimal(53, 2) NOT NULL DEFAULT '0.00', -- '刷日志时间',
|
||||
total_time_produce_mean decimal(53, 2) NOT NULL DEFAULT '0.00', -- 'produce请求处理总时间-平均值',
|
||||
total_time_produce_99th decimal(53, 2) NOT NULL DEFAULT '0.00', -- 'produce请求处理总时间-99分位',
|
||||
total_time_fetch_consumer_mean decimal(53, 2) NOT NULL DEFAULT '0.00', -- 'fetch请求总时间-平均值',
|
||||
total_time_fetch_consumer_99th decimal(53, 2) NOT NULL DEFAULT '0.00', -- 'fetch请求总时间-99分位',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
CONSTRAINT broker_metrics_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE INDEX broker_metrics_idx_cluster_id_broker_id_gmt_create ON broker_metrics (cluster_id, broker_id, gmt_create);
|
||||
|
||||
-- Cluster表
|
||||
CREATE TABLE cluster
|
||||
(
|
||||
id bigserial, -- '集群ID',
|
||||
cluster_name varchar(128) NOT NULL DEFAULT '', -- '集群名称',
|
||||
zookeeper varchar(512) NOT NULL DEFAULT '', -- 'ZK地址',
|
||||
bootstrap_servers varchar(512) NOT NULL DEFAULT '', -- 'Server地址',
|
||||
kafka_version varchar(32) NOT NULL DEFAULT '', -- 'Kafka版本',
|
||||
alarm_flag int2 NOT NULL DEFAULT '0', -- '0:不开启告警, 1开启告警',
|
||||
security_protocol varchar(512) NOT NULL DEFAULT '', -- '安全协议',
|
||||
sasl_mechanism varchar(512) NOT NULL DEFAULT '', -- '安全机制',
|
||||
sasl_jaas_config varchar(512) NOT NULL DEFAULT '', -- 'Jaas配置',
|
||||
status int2 NOT NULL DEFAULT '0', -- '删除标记, 0表示未删除, -1表示删除',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间',
|
||||
CONSTRAINT cluster_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE UNIQUE INDEX cluster_uniq_cluster_name ON cluster (cluster_name);
|
||||
CREATE TRIGGER cluster_trig_gmt_modify
|
||||
BEFORE UPDATE
|
||||
ON cluster
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_update_timestamp();
|
||||
|
||||
-- ClusterMetrics信息
|
||||
CREATE TABLE cluster_metrics
|
||||
(
|
||||
id bigserial, -- '自增id',
|
||||
cluster_id bigint NOT NULL DEFAULT '0', -- '集群ID',
|
||||
topic_num int NOT NULL DEFAULT '0', -- 'Topic数',
|
||||
partition_num int NOT NULL DEFAULT '0', -- '分区数',
|
||||
broker_num int NOT NULL DEFAULT '0', -- 'Broker数',
|
||||
bytes_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒流入(B)',
|
||||
bytes_out decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒流出(B)',
|
||||
bytes_rejected decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒拒绝(B)',
|
||||
messages_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒消息数(条)',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
CONSTRAINT cluster_metrics_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE INDEX cluster_metrics_idx_cluster_id_gmt_create ON cluster_metrics (cluster_id, gmt_create);
|
||||
|
||||
-- Controller历史变更记录表
|
||||
CREATE TABLE controller
|
||||
(
|
||||
id bigserial, -- '自增id',
|
||||
cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID',
|
||||
broker_id int NOT NULL DEFAULT '-1', -- 'BrokerId',
|
||||
host varchar(256) NOT NULL DEFAULT '', -- '主机名',
|
||||
timestamp bigint NOT NULL DEFAULT '-1', -- 'Controller变更时间',
|
||||
version int NOT NULL DEFAULT '-1', -- 'Controller格式版本',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
CONSTRAINT controller_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE UNIQUE INDEX controller_uniq_cluster_id_broker_id_timestamp ON controller (cluster_id, broker_id, timestamp);
|
||||
|
||||
-- Topic迁移信息
|
||||
CREATE TABLE migration_task
|
||||
(
|
||||
id bigserial, -- '自增id',
|
||||
cluster_id bigint NOT NULL DEFAULT '0', -- '集群ID',
|
||||
topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称',
|
||||
reassignment_json text, -- '任务参数',
|
||||
real_throttle bigint NOT NULL DEFAULT '0', -- '实际限流值(B/s)',
|
||||
operator varchar(128) NOT NULL DEFAULT '', -- '操作人',
|
||||
description varchar(256) NOT NULL DEFAULT '', -- '备注说明',
|
||||
status int NOT NULL DEFAULT '0', -- '任务状态',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '任务创建时间',
|
||||
gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '任务修改时间',
|
||||
CONSTRAINT migration_task_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE TRIGGER migration_task_trig_gmt_modify
|
||||
BEFORE UPDATE
|
||||
ON migration_task
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_update_timestamp();
|
||||
|
||||
CREATE TABLE operation_history
|
||||
(
|
||||
id bigserial, -- 'id',
|
||||
cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID',
|
||||
topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称',
|
||||
operator varchar(128) NOT NULL DEFAULT '', -- '操作人',
|
||||
operation varchar(256) NOT NULL DEFAULT '', -- '操作描述',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
--='操作记录表';
|
||||
|
||||
-- 分区申请工单
|
||||
CREATE TABLE order_partition
|
||||
(
|
||||
id bigserial, -- 'id',
|
||||
cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID',
|
||||
cluster_name varchar(128) NOT NULL DEFAULT '', -- '集群名称',
|
||||
topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称',
|
||||
applicant varchar(128) NOT NULL DEFAULT '', -- '申请人',
|
||||
partition_num int NOT NULL DEFAULT '0', -- '分区数',
|
||||
broker_list varchar(128) NOT NULL DEFAULT '', -- 'Broker列表',
|
||||
peak_bytes_in bigint NOT NULL DEFAULT '0', -- '峰值流量',
|
||||
description text, -- '备注信息',
|
||||
order_status int NOT NULL DEFAULT '0', -- '工单状态',
|
||||
approver varchar(128) NOT NULL DEFAULT '', -- '审批人',
|
||||
opinion varchar(256) NOT NULL DEFAULT '', -- '审批意见',
|
||||
status int NOT NULL DEFAULT '0', -- '状态,0标识有效,-1无效',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间',
|
||||
CONSTRAINT order_partition_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE TRIGGER order_partition_trig_gmt_modify
|
||||
BEFORE UPDATE
|
||||
ON order_partition
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_update_timestamp();
|
||||
|
||||
-- Topic申请工单
|
||||
CREATE TABLE order_topic
|
||||
(
|
||||
id bigserial, -- 'ID',
|
||||
cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID',
|
||||
cluster_name varchar(128) NOT NULL DEFAULT '', -- '集群名称',
|
||||
topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称',
|
||||
retention_time bigint NOT NULL DEFAULT '-1', -- '保留时间(ms)',
|
||||
partition_num int NOT NULL DEFAULT '-1', -- '分区数',
|
||||
replica_num int NOT NULL DEFAULT '-1', -- '副本数',
|
||||
regions varchar(128) NOT NULL DEFAULT '', -- 'RegionId列表',
|
||||
brokers varchar(128) NOT NULL DEFAULT '', -- 'Broker列表',
|
||||
peak_bytes_in bigint NOT NULL DEFAULT '0', -- '峰值流入流量(KB)',
|
||||
applicant varchar(128) NOT NULL DEFAULT '', -- '申请人',
|
||||
principals varchar(256) NOT NULL DEFAULT '', -- '负责人',
|
||||
description text, -- '备注信息',
|
||||
order_status int NOT NULL DEFAULT '0', -- '工单状态',
|
||||
approver varchar(128) NOT NULL DEFAULT '', -- '审批人',
|
||||
opinion varchar(256) NOT NULL DEFAULT '', -- '审批意见',
|
||||
status int NOT NULL DEFAULT '0', -- '状态,0标识有效,-1无效',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间',
|
||||
CONSTRAINT order_topic_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE TRIGGER order_topic_trig_gmt_modify
|
||||
BEFORE UPDATE
|
||||
ON order_topic
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_update_timestamp();
|
||||
|
||||
-- Region信息表
|
||||
CREATE TABLE region
|
||||
(
|
||||
id bigserial, -- 'id',
|
||||
cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID',
|
||||
region_name varchar(128) NOT NULL DEFAULT '', -- 'Region名称',
|
||||
broker_list varchar(256) NOT NULL DEFAULT '', -- 'Broker列表',
|
||||
level int NOT NULL DEFAULT '0', -- 'Region重要等级, 0级普通, 1极重要,2级极重要',
|
||||
operator varchar(45) NOT NULL DEFAULT '', -- '操作人',
|
||||
description text, -- '备注说明',
|
||||
status int NOT NULL DEFAULT '0', -- '状态,0正常,-1废弃,1容量已满',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间',
|
||||
CONSTRAINT region_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE UNIQUE INDEX region_uniq_cluster_id_region_name ON region (cluster_id, region_name);
|
||||
CREATE TRIGGER region_trig_gmt_modify
|
||||
BEFORE UPDATE
|
||||
ON region
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_update_timestamp();
|
||||
|
||||
-- Topic信息表
|
||||
CREATE TABLE topic
|
||||
(
|
||||
id bigserial, -- 'ID',
|
||||
cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID',
|
||||
topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称',
|
||||
applicant varchar(256) NOT NULL DEFAULT '', -- '申请人',
|
||||
principals varchar(256) NOT NULL DEFAULT '', -- '负责人',
|
||||
description text, -- '备注信息',
|
||||
status int NOT NULL DEFAULT '0', -- '0标识使用中,-1标识已废弃',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间',
|
||||
CONSTRAINT topic_pk PRIMARY KEY (id)
|
||||
); --='';
|
||||
CREATE UNIQUE INDEX topic_uniq_cluster_id_topic_name ON topic (cluster_id, topic_name);
|
||||
CREATE TRIGGER topic_trig_gmt_modify
|
||||
BEFORE UPDATE
|
||||
ON topic
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_update_timestamp();
|
||||
|
||||
-- 用户收藏的Topic表
|
||||
CREATE TABLE topic_favorite
|
||||
(
|
||||
id bigserial, -- '自增Id',
|
||||
username varchar(64) NOT NULL DEFAULT '', -- '用户名',
|
||||
cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID',
|
||||
topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称',
|
||||
status int NOT NULL DEFAULT '0', -- '删除标记, 0表示未删除, -1表示删除',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
gmt_modify timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '修改时间',
|
||||
CONSTRAINT topic_favorite_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE UNIQUE INDEX topic_favorite_uniq_username_cluster_id_topic_name ON topic_favorite (username, cluster_id, topic_name);
|
||||
CREATE TRIGGER topic_favorite_trig_gmt_modify
|
||||
BEFORE UPDATE
|
||||
ON topic_favorite
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_update_timestamp();
|
||||
|
||||
-- TopicMetrics表
|
||||
CREATE TABLE topic_metrics
|
||||
(
|
||||
id bigserial, -- '自增id',
|
||||
cluster_id bigint NOT NULL DEFAULT '-1', -- '集群ID',
|
||||
topic_name varchar(192) NOT NULL DEFAULT '', -- 'Topic名称',
|
||||
messages_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒进入消息条数',
|
||||
bytes_in decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒字节流入',
|
||||
bytes_out decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒字节流出',
|
||||
bytes_rejected decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒拒绝字节数',
|
||||
total_produce_requests decimal(53, 2) NOT NULL DEFAULT '0.00', -- '每秒请求数',
|
||||
gmt_create timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- '创建时间',
|
||||
CONSTRAINT topic_metrics_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE INDEX topic_metrics_idx_cluster_id_topic_name_gmt_create ON topic_metrics (cluster_id, topic_name, gmt_create);
|
||||
32
docker-compose.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
version: '2'
|
||||
services:
|
||||
mysqldbserver:
|
||||
container_name: mysqldbserver
|
||||
image: mysql:5.7
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/mysql/Dockerfile
|
||||
ports:
|
||||
- "3306:3306"
|
||||
command: [
|
||||
'mysqld',
|
||||
'--character-set-server=utf8',
|
||||
'--collation-server=utf8_general_ci',
|
||||
'--default-time-zone=+8:00'
|
||||
]
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: 12345678
|
||||
MYSQL_DATABASE: kafka_manager
|
||||
MYSQL_USER: admin
|
||||
MYSQL_PASSWORD: 12345678
|
||||
restart: always
|
||||
kafka-manager-web:
|
||||
container_name: kafka-manager-web
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8080:8080"
|
||||
links:
|
||||
- mysqldbserver
|
||||
restart: always
|
||||
7
docker/kafka-manager/Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM java:8
|
||||
MAINTAINER xuzhengxi
|
||||
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
|
||||
ADD ../../web/target/kafka-manager-web-1.1.0-SNAPSHOT.jar kafka-manager-web.jar
|
||||
ADD ./application.yml application.yml
|
||||
ENTRYPOINT ["java","-jar","/kafka-manager-web.jar","--spring.config.location=./application.yml"]
|
||||
EXPOSE 8080
|
||||
32
docker/kafka-manager/application-standalone.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
server:
|
||||
port: 8080
|
||||
tomcat:
|
||||
accept-count: 100
|
||||
max-connections: 1000
|
||||
max-threads: 20
|
||||
min-spare-threads: 20
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: kafkamanager
|
||||
datasource:
|
||||
kafka-manager:
|
||||
jdbc-url: jdbc:mysql://mysqldbserver:3306/kafka_manager?characterEncoding=UTF-8&serverTimezone=GMT%2B8
|
||||
username: admin
|
||||
password: 12345678
|
||||
driver-class-name: org.mariadb.jdbc.Driver
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
profiles:
|
||||
active: dev
|
||||
|
||||
logging:
|
||||
config: classpath:logback-spring.xml
|
||||
|
||||
# kafka监控
|
||||
kafka-monitor:
|
||||
enabled: true
|
||||
notify-kafka:
|
||||
cluster-id: 95
|
||||
topic-name: kmo_monitor
|
||||
32
docker/kafka-manager/application.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
server:
|
||||
port: 8080
|
||||
tomcat:
|
||||
accept-count: 100
|
||||
max-connections: 1000
|
||||
max-threads: 20
|
||||
min-spare-threads: 20
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: kafkamanager
|
||||
datasource:
|
||||
kafka-manager:
|
||||
jdbc-url: jdbc:mysql://mysqldbserver:3306/kafka_manager?characterEncoding=UTF-8&serverTimezone=GMT%2B8
|
||||
username: admin
|
||||
password: 12345678
|
||||
driver-class-name: org.mariadb.jdbc.Driver
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
profiles:
|
||||
active: dev
|
||||
|
||||
logging:
|
||||
config: classpath:logback-spring.xml
|
||||
|
||||
# kafka监控
|
||||
kafka-monitor:
|
||||
enabled: true
|
||||
notify-kafka:
|
||||
cluster-id: 95
|
||||
topic-name: kmo_monitor
|
||||
3
docker/mysql/Dockerfile
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM mysql:5.7
|
||||
MAINTAINER xuzhengxi
|
||||
COPY ./docker/mysql/create_mysql_table.sql /docker-entrypoint-initdb.d/
|
||||
243
docker/mysql/create_mysql_table.sql
Normal file
@@ -0,0 +1,243 @@
|
||||
CREATE DATABASE IF NOT EXISTS `kafka_manager`;
|
||||
|
||||
USE `kafka_manager`;
|
||||
|
||||
CREATE TABLE `account` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户名',
|
||||
`password` varchar(128) NOT NULL DEFAULT '' COMMENT '密码',
|
||||
`role` int(16) NOT NULL DEFAULT '0' COMMENT '角色类型, 0:普通用户',
|
||||
`status` int(16) NOT NULL DEFAULT '0' COMMENT '0标识使用中,-1标识已废弃',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_username` (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='账号表';
|
||||
INSERT INTO account(username, password, role) VALUES ('admin', '21232f297a57a5a743894a0e4a801fc3', 2);
|
||||
|
||||
|
||||
CREATE TABLE `alarm_rule` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
|
||||
`alarm_name` varchar(128) NOT NULL DEFAULT '' COMMENT '告警名字',
|
||||
`strategy_expressions` text COMMENT '表达式',
|
||||
`strategy_filters` text COMMENT '过滤条件',
|
||||
`strategy_actions` text COMMENT '响应',
|
||||
`principals` varchar(512) NOT NULL DEFAULT '' COMMENT '负责人',
|
||||
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '-1:逻辑删除, 0:关闭, 1:正常',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_alarm_name` (`alarm_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='告警规则表';
|
||||
|
||||
|
||||
CREATE TABLE `broker` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerID',
|
||||
`host` varchar(128) NOT NULL DEFAULT '' COMMENT 'Broker主机名',
|
||||
`port` int(32) NOT NULL DEFAULT '-1' COMMENT 'Broker端口',
|
||||
`timestamp` bigint(128) NOT NULL DEFAULT '-1' COMMENT '启动时间',
|
||||
`status` int(11) NOT NULL DEFAULT '0' COMMENT '状态0有效,-1无效',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_cluster_id_broker_id` (`cluster_id`,`broker_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Broker信息表';
|
||||
|
||||
|
||||
CREATE TABLE `broker_metrics` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerID',
|
||||
`bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流入',
|
||||
`bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流出',
|
||||
`bytes_rejected` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒被拒绝字节数',
|
||||
`messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消息数流入',
|
||||
`fail_fetch_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消费失败数',
|
||||
`fail_produce_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒失败生产数',
|
||||
`fetch_consumer_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消费请求数',
|
||||
`produce_request` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒生产数',
|
||||
`request_handler_idl_percent` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '请求处理器繁忙百分比',
|
||||
`network_processor_idl_percent` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '网络处理器繁忙百分比',
|
||||
`request_queue_size` bigint(20) NOT NULL DEFAULT '0' COMMENT '请求列表大小',
|
||||
`response_queue_size` bigint(20) NOT NULL DEFAULT '0' COMMENT '响应列表大小',
|
||||
`log_flush_time` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '刷日志时间',
|
||||
`total_time_produce_mean` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'produce请求处理总时间-平均值',
|
||||
`total_time_produce_99th` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'produce请求处理总时间-99分位',
|
||||
`total_time_fetch_consumer_mean` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'fetch请求总时间-平均值',
|
||||
`total_time_fetch_consumer_99th` double(53,2) NOT NULL DEFAULT '0.00' COMMENT 'fetch请求总时间-99分位',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_cluster_id_broker_id_gmt_create` (`cluster_id`,`broker_id`,`gmt_create`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='BrokerMetric信息表';
|
||||
|
||||
|
||||
CREATE TABLE `cluster` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '集群ID',
|
||||
`cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称',
|
||||
`zookeeper` varchar(512) NOT NULL DEFAULT '' COMMENT 'ZK地址',
|
||||
`bootstrap_servers` varchar(512) NOT NULL DEFAULT '' COMMENT 'Server地址',
|
||||
`kafka_version` varchar(32) NOT NULL DEFAULT '' COMMENT 'Kafka版本',
|
||||
`alarm_flag` int(4) NOT NULL DEFAULT '0' COMMENT '0:不开启告警, 1开启告警',
|
||||
`security_protocol` varchar(512) NOT NULL DEFAULT '' COMMENT '安全协议',
|
||||
`sasl_mechanism` varchar(512) NOT NULL DEFAULT '' COMMENT '安全机制',
|
||||
`sasl_jaas_config` varchar(512) NOT NULL DEFAULT '' COMMENT 'Jaas配置',
|
||||
`status` int(4) NOT NULL DEFAULT '0' COMMENT '删除标记, 0表示未删除, -1表示删除',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_cluster_name` (`cluster_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Cluster表';
|
||||
|
||||
|
||||
CREATE TABLE `cluster_metrics` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群ID',
|
||||
`topic_num` int(11) NOT NULL DEFAULT '0' COMMENT 'Topic数',
|
||||
`partition_num` int(11) NOT NULL DEFAULT '0' COMMENT '分区数',
|
||||
`broker_num` int(11) NOT NULL DEFAULT '0' COMMENT 'Broker数',
|
||||
`bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒流入(B)',
|
||||
`bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒流出(B)',
|
||||
`bytes_rejected` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒拒绝(B)',
|
||||
`messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒消息数(条)',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_cluster_id_gmt_create` (`cluster_id`,`gmt_create`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ClusterMetrics信息';
|
||||
|
||||
|
||||
CREATE TABLE `controller` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT 'BrokerId',
|
||||
`host` varchar(256) NOT NULL DEFAULT '' COMMENT '主机名',
|
||||
`timestamp` bigint(20) NOT NULL DEFAULT '-1' COMMENT 'Controller变更时间',
|
||||
`version` int(11) NOT NULL DEFAULT '-1' COMMENT 'Controller格式版本',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_cluster_id_broker_id_timestamp` (`cluster_id`,`broker_id`,`timestamp`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Controller历史变更记录表';
|
||||
|
||||
CREATE TABLE `migration_task` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群ID',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`reassignment_json` text COMMENT '任务参数',
|
||||
`real_throttle` bigint(20) NOT NULL DEFAULT '0' COMMENT '实际限流值(B/s)',
|
||||
`operator` varchar(128) NOT NULL DEFAULT '' COMMENT '操作人',
|
||||
`description` varchar(256) NOT NULL DEFAULT '' COMMENT '备注说明',
|
||||
`status` int(11) NOT NULL DEFAULT '0' COMMENT '任务状态',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic迁移信息';
|
||||
|
||||
CREATE TABLE `operation_history` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`operator` varchar(128) NOT NULL DEFAULT '' COMMENT '操作人',
|
||||
`operation` varchar(256) NOT NULL DEFAULT '' COMMENT '操作描述',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='操作记录表';
|
||||
|
||||
|
||||
CREATE TABLE `order_partition` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`broker_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'Broker列表, 逗号分割',
|
||||
`partition_num` int(11) NOT NULL DEFAULT 0 COMMENT '新增分区数',
|
||||
`applicant` varchar(128) NOT NULL DEFAULT '' COMMENT '申请人',
|
||||
`peak_bytes_in` bigint(20) NOT NULL DEFAULT '0' COMMENT '峰值流量',
|
||||
`description` text COMMENT '备注信息',
|
||||
`order_status` int(16) NOT NULL DEFAULT '0' COMMENT '工单状态',
|
||||
`approver` varchar(128) NOT NULL DEFAULT '' COMMENT '审批人',
|
||||
`opinion` varchar(256) NOT NULL DEFAULT '' COMMENT '审批意见',
|
||||
`status` int(11) NOT NULL DEFAULT '0' COMMENT '状态,0标识有效,-1无效',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='分区申请工单';
|
||||
|
||||
CREATE TABLE `order_topic` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`cluster_name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`retention_time` bigint(20) NOT NULL DEFAULT '-1' COMMENT '保留时间(ms)',
|
||||
`partition_num` int(16) NOT NULL DEFAULT '-1' COMMENT '分区数',
|
||||
`replica_num` int(16) NOT NULL DEFAULT '-1' COMMENT '副本数',
|
||||
`regions` varchar(128) NOT NULL DEFAULT '' COMMENT 'RegionId列表',
|
||||
`brokers` varchar(128) NOT NULL DEFAULT '' COMMENT 'Broker列表',
|
||||
`peak_bytes_in` bigint(20) NOT NULL DEFAULT '0' COMMENT '峰值流入流量(KB)',
|
||||
`applicant` varchar(128) NOT NULL DEFAULT '' COMMENT '申请人',
|
||||
`principals` varchar(256) NOT NULL DEFAULT '' COMMENT '负责人',
|
||||
`description` text COMMENT '备注信息',
|
||||
`order_status` int(16) NOT NULL DEFAULT '0' COMMENT '工单状态',
|
||||
`approver` varchar(128) NOT NULL DEFAULT '' COMMENT '审批人',
|
||||
`opinion` varchar(256) NOT NULL DEFAULT '' COMMENT '审批意见',
|
||||
`status` int(16) NOT NULL DEFAULT '0' COMMENT '状态,0标识有效,-1无效',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic申请工单';
|
||||
|
||||
CREATE TABLE `region` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`region_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'Region名称',
|
||||
`broker_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'Broker列表',
|
||||
`level` int(16) NOT NULL DEFAULT '0' COMMENT 'Region重要等级, 0级普通, 1极重要,2级极重要',
|
||||
`operator` varchar(45) NOT NULL DEFAULT '' COMMENT '操作人',
|
||||
`description` text COMMENT '备注说明',
|
||||
`status` int(11) NOT NULL DEFAULT '0' COMMENT '状态,0正常,-1废弃,1容量已满',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_cluster_id_region_name` (`cluster_id`,`region_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Region信息表';
|
||||
|
||||
CREATE TABLE `topic` (
|
||||
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`applicant` varchar(256) NOT NULL DEFAULT '' COMMENT '申请人',
|
||||
`principals` varchar(256) NOT NULL DEFAULT '' COMMENT '负责人',
|
||||
`description` text COMMENT '备注信息',
|
||||
`status` int(16) NOT NULL DEFAULT '0' COMMENT '0标识使用中,-1标识已废弃',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_cluster_id_topic_name` (`cluster_id`,`topic_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic信息表';
|
||||
|
||||
|
||||
CREATE TABLE `topic_favorite` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
|
||||
`username` varchar(64) NOT NULL DEFAULT '' COMMENT '用户名',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`status` int(16) NOT NULL DEFAULT '0' COMMENT '删除标记, 0表示未删除, -1表示删除',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_username_cluster_id_topic_name` (`username`,`cluster_id`,`topic_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户收藏的Topic表';
|
||||
|
||||
CREATE TABLE `topic_metrics` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID',
|
||||
`topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称',
|
||||
`messages_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒进入消息条数',
|
||||
`bytes_in` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流入',
|
||||
`bytes_out` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒字节流出',
|
||||
`bytes_rejected` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒拒绝字节数',
|
||||
`total_produce_requests` double(53,2) NOT NULL DEFAULT '0.00' COMMENT '每秒请求数',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_cluster_id_topic_name_gmt_create` (`cluster_id`,`topic_name`,`gmt_create`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='TopicMetrics表';
|
||||
@@ -1,63 +0,0 @@
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
**一站式`Apache Kafka`集群指标监控与运维管控平台**
|
||||
|
||||
---
|
||||
|
||||
# 安装手册
|
||||
|
||||
|
||||
## 环境依赖
|
||||
|
||||
- `Maven`(后端打包依赖)
|
||||
- `node 10+`(前端打包依赖)
|
||||
- `Java 8+`(运行环境需要)
|
||||
- `MySQL`(数据存储)
|
||||
|
||||
---
|
||||
|
||||
## 环境初始化
|
||||
|
||||
执行[create_mysql_table.sql](./create_mysql_table.sql)中的SQL命令,从而创建所需的MySQL库及表,默认创建的库名是`kafka_manager`。
|
||||
|
||||
```
|
||||
# 示例:
|
||||
mysql -uXXXX -pXXX -h XXX.XXX.XXX.XXX -PXXXX < ./create_mysql_table.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 打包
|
||||
|
||||
```bash
|
||||
# 前端工程包
|
||||
cd kafka-manager-opensource/console
|
||||
npm install
|
||||
npm run prod-build
|
||||
mv dist/* ../web/src/main/resources/templates
|
||||
|
||||
# 后端工程包
|
||||
cd ..
|
||||
mvn install
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 启动
|
||||
|
||||
```
|
||||
# application.yml 是配置文件
|
||||
|
||||
cp web/src/main/resources/application.yml web/target/
|
||||
cd web/target/
|
||||
nohup java -jar kafka-manager-web-1.0.0-SNAPSHOT.jar --spring.config.location=./application.yml > /dev/null 2>&1 &
|
||||
```
|
||||
|
||||
## 使用
|
||||
|
||||
本地启动的话,访问`http://localhost:8080`,输入帐号及密码进行登录。更多参考:[kafka-manager使用手册](./user_cn_guide.md)
|
||||
|
||||
9
pom.xml
@@ -6,17 +6,16 @@
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<artifactId>kafka-manager</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.1.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<kafka-manager.revision>1.0.0-SNAPSHOT</kafka-manager.revision>
|
||||
<kafka-manager.revision>1.1.0-SNAPSHOT</kafka-manager.revision>
|
||||
<jackson.version>2.9.0</jackson.version>
|
||||
|
||||
<!-- maven properties -->
|
||||
@@ -78,12 +77,12 @@
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.58</version>
|
||||
<version>1.2.68</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.zookeeper</groupId>
|
||||
<artifactId>zookeeper</artifactId>
|
||||
<version>3.4.6</version>
|
||||
<version>3.4.14</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<artifactId>kafka-manager-service</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>kafka-manager</artifactId>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
@@ -31,7 +31,7 @@
|
||||
<dependency>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<artifactId>kafka-manager-dao</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- spring -->
|
||||
|
||||
@@ -2,12 +2,12 @@ package com.xiaojukeji.kafka.manager.service.collector;
|
||||
|
||||
import com.xiaojukeji.kafka.manager.common.constant.Constant;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.ConsumerMetrics;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.zookeeper.PartitionState;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.dto.consumer.ConsumerDTO;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.po.ClusterDO;
|
||||
import com.xiaojukeji.kafka.manager.service.cache.ClusterMetadataManager;
|
||||
import com.xiaojukeji.kafka.manager.service.cache.KafkaMetricsCache;
|
||||
import com.xiaojukeji.kafka.manager.service.service.ConsumerService;
|
||||
import org.apache.kafka.common.TopicPartition;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -34,8 +34,8 @@ public class CollectConsumerMetricsTask extends BaseCollectTask {
|
||||
if (clusterDO == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, List<PartitionState>> topicNamePartitionStateListMap = new HashMap<>();
|
||||
List<ConsumerDTO> consumerDTOList = consumerService.getMonitoredConsumerList(clusterDO, topicNamePartitionStateListMap);
|
||||
Map<TopicPartition, Long> allPartitionOffsetMap = new HashMap<>();
|
||||
List<ConsumerDTO> consumerDTOList = consumerService.getMonitoredConsumerList(clusterDO, allPartitionOffsetMap);
|
||||
|
||||
List<ConsumerMetrics> consumerMetricsList = convert2ConsumerMetrics(consumerDTOList);
|
||||
KafkaMetricsCache.putConsumerMetricsToCache(clusterId, consumerMetricsList);
|
||||
@@ -47,23 +47,27 @@ public class CollectConsumerMetricsTask extends BaseCollectTask {
|
||||
private List<ConsumerMetrics> convert2ConsumerMetrics(List<ConsumerDTO> consumerDTOList) {
|
||||
List<ConsumerMetrics> consumerMetricsList = new ArrayList<>();
|
||||
for (ConsumerDTO consumerDTO : consumerDTOList) {
|
||||
Map<String, List<PartitionState>> topicNamePartitionStateListMap = consumerDTO.getTopicPartitionMap();
|
||||
for(Map.Entry<String, List<PartitionState>> entry : topicNamePartitionStateListMap.entrySet()){
|
||||
String topicName = entry.getKey();
|
||||
List<PartitionState> partitionStateList = entry.getValue();
|
||||
ConsumerMetrics consumerMetrics = new ConsumerMetrics();
|
||||
consumerMetrics.setClusterId(clusterId);
|
||||
consumerMetrics.setConsumerGroup(consumerDTO.getConsumerGroup());
|
||||
consumerMetrics.setLocation(consumerDTO.getLocation());
|
||||
consumerMetrics.setTopicName(topicName);
|
||||
long sumLag = 0;
|
||||
for (PartitionState partitionState : partitionStateList) {
|
||||
Map.Entry<Long, Long> offsetEntry = new AbstractMap.SimpleEntry<>(partitionState.getOffset(), partitionState.getConsumeOffset());
|
||||
sumLag += (offsetEntry.getKey() - offsetEntry.getValue() > 0 ? offsetEntry.getKey() - offsetEntry.getValue(): 0);
|
||||
}
|
||||
consumerMetrics.setSumLag(sumLag);
|
||||
consumerMetricsList.add(consumerMetrics);
|
||||
if (consumerDTO.getPartitionOffsetMap() == null || consumerDTO.getConsumerOffsetMap() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ConsumerMetrics consumerMetrics = new ConsumerMetrics();
|
||||
consumerMetrics.setClusterId(consumerDTO.getClusterId());
|
||||
consumerMetrics.setConsumerGroup(consumerDTO.getConsumerGroup());
|
||||
consumerMetrics.setLocation(consumerDTO.getLocation());
|
||||
consumerMetrics.setTopicName(consumerDTO.getTopicName());
|
||||
|
||||
long sumLag = 0;
|
||||
for(Map.Entry<Integer, Long> entry : consumerDTO.getPartitionOffsetMap().entrySet()){
|
||||
Long partitionOffset = entry.getValue();
|
||||
Long consumerOffset = consumerDTO.getConsumerOffsetMap().get(entry.getKey());
|
||||
if (partitionOffset == null || consumerOffset == null) {
|
||||
continue;
|
||||
}
|
||||
sumLag += Math.max(partitionOffset - consumerOffset, 0);
|
||||
}
|
||||
consumerMetrics.setSumLag(sumLag);
|
||||
consumerMetricsList.add(consumerMetrics);
|
||||
}
|
||||
return consumerMetricsList;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.xiaojukeji.kafka.manager.common.entity.dto.consumer.ConsumerGroupDTO;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.dto.PartitionOffsetDTO;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.dto.consumer.ConsumeDetailDTO;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.po.ClusterDO;
|
||||
import org.apache.kafka.common.TopicPartition;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -57,7 +58,7 @@ public interface ConsumerService {
|
||||
* @return
|
||||
*/
|
||||
List<ConsumerDTO> getMonitoredConsumerList(ClusterDO clusterDO,
|
||||
Map<String, List<PartitionState>> topicNamePartitionStateListMap);
|
||||
Map<TopicPartition, Long> partitionOffsetMap);
|
||||
|
||||
/**
|
||||
* 重置offset
|
||||
|
||||
@@ -45,7 +45,7 @@ public interface OrderService {
|
||||
* @date 19/6/23
|
||||
* @return Result
|
||||
*/
|
||||
Result modifyOrderPartition(OrderPartitionDO orderPartitionDO, String operator);
|
||||
Result modifyOrderPartition(OrderPartitionDO orderPartitionDO, String operator, boolean admin);
|
||||
|
||||
/**
|
||||
* 查询Topic工单
|
||||
|
||||
@@ -76,6 +76,7 @@ public class AdminTopicServiceImpl implements AdminTopicService {
|
||||
OperationHistoryDO operationHistoryDO = OperationHistoryDO.newInstance(topicDO.getClusterId(), topicDO.getTopicName(), operator, OperationEnum.CREATE_TOPIC.message);
|
||||
operationHistoryDao.insert(operationHistoryDO);
|
||||
topicDao.replace(topicDO);
|
||||
|
||||
} catch (Exception e) {
|
||||
return AdminTopicStatusEnum.REPLACE_DB_FAILED;
|
||||
}
|
||||
@@ -188,4 +189,5 @@ public class AdminTopicServiceImpl implements AdminTopicService {
|
||||
}
|
||||
return AdminTopicStatusEnum.SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.xiaojukeji.kafka.manager.dao.ClusterDao;
|
||||
import com.xiaojukeji.kafka.manager.dao.ClusterMetricsDao;
|
||||
import com.xiaojukeji.kafka.manager.dao.ControllerDao;
|
||||
import com.xiaojukeji.kafka.manager.service.cache.ClusterMetadataManager;
|
||||
import com.xiaojukeji.kafka.manager.service.schedule.ScheduleCollectDataManager;
|
||||
import com.xiaojukeji.kafka.manager.service.service.ClusterService;
|
||||
import org.apache.zookeeper.ZooKeeper;
|
||||
import org.slf4j.Logger;
|
||||
@@ -37,6 +38,9 @@ public class ClusterServiceImpl implements ClusterService {
|
||||
@Autowired
|
||||
private ClusterMetadataManager clusterMetadataManager;
|
||||
|
||||
@Autowired
|
||||
private ScheduleCollectDataManager scheduleCollectDataManager;
|
||||
|
||||
@Autowired
|
||||
private ControllerDao controllerDao;
|
||||
|
||||
@@ -57,6 +61,7 @@ public class ClusterServiceImpl implements ClusterService {
|
||||
if (!status) {
|
||||
return new Result(StatusCode.OPERATION_ERROR, "add zookeeper watch failed");
|
||||
}
|
||||
scheduleCollectDataManager.start(clusterDO);
|
||||
|
||||
if (clusterDO.getAlarmFlag() == null || clusterDO.getAlarmFlag() <= 0) {
|
||||
return new Result();
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.xiaojukeji.kafka.manager.service.service.impl;
|
||||
|
||||
import com.xiaojukeji.kafka.manager.common.constant.OffsetStoreLocation;
|
||||
import com.xiaojukeji.kafka.manager.common.constant.StatusCode;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.zookeeper.PartitionState;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.Result;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.dto.consumer.ConsumeDetailDTO;
|
||||
import com.xiaojukeji.kafka.manager.common.entity.po.ClusterDO;
|
||||
@@ -18,7 +17,6 @@ import com.xiaojukeji.kafka.manager.service.cache.ConsumerMetadataCache;
|
||||
import com.xiaojukeji.kafka.manager.service.cache.KafkaClientCache;
|
||||
import com.xiaojukeji.kafka.manager.service.service.ConsumerService;
|
||||
import com.xiaojukeji.kafka.manager.service.service.TopicService;
|
||||
import com.xiaojukeji.kafka.manager.service.service.ZookeeperService;
|
||||
import com.xiaojukeji.kafka.manager.common.utils.zk.ZkPathUtil;
|
||||
import kafka.admin.AdminClient;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
@@ -49,9 +47,6 @@ public class ConsumerServiceImpl implements ConsumerService {
|
||||
@Autowired
|
||||
private TopicService topicService;
|
||||
|
||||
@Autowired
|
||||
private ZookeeperService zkService;
|
||||
|
||||
private final ExecutorService consumerListThreadPool = Executors.newFixedThreadPool(50, new DefaultThreadFactory("ConsumerPool"));
|
||||
|
||||
@Override
|
||||
@@ -135,20 +130,20 @@ public class ConsumerServiceImpl implements ConsumerService {
|
||||
|
||||
@Override
|
||||
public List<ConsumerDTO> getMonitoredConsumerList(final ClusterDO clusterDO,
|
||||
final Map<String, List<PartitionState>> partitionStateListMap) {
|
||||
final Map<TopicPartition, Long> allPartitionOffsetMap) {
|
||||
List<ConsumerGroupDTO> consumerGroupDTOList = getConsumerGroupList(clusterDO.getId());
|
||||
if (consumerGroupDTOList == null || consumerGroupDTOList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
FutureTask<ConsumerDTO>[] taskList = new FutureTask[consumerGroupDTOList.size()];
|
||||
FutureTask<List<ConsumerDTO>>[] taskList = new FutureTask[consumerGroupDTOList.size()];
|
||||
for (int i = 0; i < consumerGroupDTOList.size(); i++) {
|
||||
final ConsumerGroupDTO consumerGroupDTO = consumerGroupDTOList.get(i);
|
||||
taskList[i] = new FutureTask<>(new Callable<ConsumerDTO>() {
|
||||
taskList[i] = new FutureTask<>(new Callable<List<ConsumerDTO>>() {
|
||||
@Override
|
||||
public ConsumerDTO call() throws Exception {
|
||||
public List<ConsumerDTO> call() throws Exception {
|
||||
try {
|
||||
return getMonitoredConsumer(clusterDO, consumerGroupDTO, partitionStateListMap);
|
||||
return getMonitoredConsumer(clusterDO, consumerGroupDTO, allPartitionOffsetMap);
|
||||
} catch (Exception e) {
|
||||
logger.error("get monitored consumer error, group:{}", consumerGroupDTO.getConsumerGroup(), e);
|
||||
}
|
||||
@@ -159,31 +154,70 @@ public class ConsumerServiceImpl implements ConsumerService {
|
||||
}
|
||||
|
||||
List<ConsumerDTO> consumerList = new ArrayList<>();
|
||||
for (FutureTask<ConsumerDTO> task : taskList) {
|
||||
ConsumerDTO consumer = null;
|
||||
for (FutureTask<List<ConsumerDTO>> task : taskList) {
|
||||
List<ConsumerDTO> dtoList = null;
|
||||
try {
|
||||
consumer = task.get();
|
||||
dtoList = task.get();
|
||||
} catch (Exception e) {
|
||||
logger.error("getMonitoredConsumerList@ConsumeServiceImpl, ", e);
|
||||
}
|
||||
if (consumer == null) {
|
||||
if (dtoList == null) {
|
||||
continue;
|
||||
}
|
||||
consumerList.add(consumer);
|
||||
consumerList.addAll(dtoList);
|
||||
}
|
||||
return consumerList;
|
||||
}
|
||||
|
||||
private ConsumerDTO getMonitoredConsumer(ClusterDO cluster, ConsumerGroupDTO consumerGroupDTO, Map<String, List<PartitionState>> globalTopicNamePartitionStateListMap) {
|
||||
// 获取当前consumerGroup下的所有的topic的partitionState信息
|
||||
Map<String, List<PartitionState>> topicNamePartitionStateListMap = getConsumerGroupPartitionStateList(cluster, consumerGroupDTO, globalTopicNamePartitionStateListMap);
|
||||
private List<ConsumerDTO> getMonitoredConsumer(ClusterDO clusterDO,
|
||||
ConsumerGroupDTO consumerGroupDTO,
|
||||
Map<TopicPartition, Long> allPartitionOffsetMap) {
|
||||
List<ConsumerDTO> dtoList = new ArrayList<>();
|
||||
|
||||
//将没有对应consumer的partition信息统一放到一个consumer中
|
||||
ConsumerDTO consumerDTO = new ConsumerDTO();
|
||||
consumerDTO.setConsumerGroup(consumerGroupDTO.getConsumerGroup());
|
||||
consumerDTO.setLocation(consumerGroupDTO.getOffsetStoreLocation().name());
|
||||
consumerDTO.setTopicPartitionMap(topicNamePartitionStateListMap);
|
||||
return consumerDTO;
|
||||
List<String> topicNameList = ConsumerMetadataCache.getConsumerGroupConsumedTopicList(
|
||||
clusterDO.getId(),
|
||||
consumerGroupDTO.getOffsetStoreLocation().getLocation(),
|
||||
consumerGroupDTO.getConsumerGroup()
|
||||
);
|
||||
for (String topicName : topicNameList) {
|
||||
TopicMetadata metadata = ClusterMetadataManager.getTopicMetaData(clusterDO.getId(), topicName);
|
||||
if (metadata == null || metadata.getPartitionNum() <= 0) {
|
||||
continue;
|
||||
}
|
||||
if (!allPartitionOffsetMap.containsKey(new TopicPartition(topicName, 0))) {
|
||||
Map<TopicPartition, Long> offsetMap = topicService.getTopicPartitionOffset(clusterDO, topicName);
|
||||
if (offsetMap == null) {
|
||||
offsetMap = new HashMap<>();
|
||||
}
|
||||
allPartitionOffsetMap.putAll(offsetMap);
|
||||
}
|
||||
|
||||
Map<Integer, Long> consumerOffsetMap = null;
|
||||
if (consumerGroupDTO.getOffsetStoreLocation().equals(OffsetStoreLocation.ZOOKEEPER)) {
|
||||
consumerOffsetMap = getTopicConsumerOffsetInZK(clusterDO, metadata, consumerGroupDTO);
|
||||
} else if (consumerGroupDTO.getOffsetStoreLocation().equals(OffsetStoreLocation.BROKER)) {
|
||||
consumerOffsetMap = getTopicConsumerOffsetInBroker(clusterDO, topicName, consumerGroupDTO);
|
||||
}
|
||||
|
||||
Map<Integer, Long> partitionOffsetMap = new HashMap<>();
|
||||
for (int partitionId = 0; partitionId < metadata.getPartitionNum(); ++partitionId) {
|
||||
Long offset = allPartitionOffsetMap.get(new TopicPartition(topicName, partitionId));
|
||||
if (offset == null) {
|
||||
continue;
|
||||
}
|
||||
partitionOffsetMap.put(partitionId, offset);
|
||||
}
|
||||
|
||||
ConsumerDTO consumerDTO = new ConsumerDTO();
|
||||
consumerDTO.setClusterId(clusterDO.getId());
|
||||
consumerDTO.setTopicName(topicName);
|
||||
consumerDTO.setConsumerGroup(consumerGroupDTO.getConsumerGroup());
|
||||
consumerDTO.setLocation(consumerGroupDTO.getOffsetStoreLocation().getLocation());
|
||||
consumerDTO.setPartitionOffsetMap(partitionOffsetMap);
|
||||
consumerDTO.setConsumerOffsetMap(consumerOffsetMap);
|
||||
dtoList.add(consumerDTO);
|
||||
}
|
||||
return dtoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -264,52 +298,15 @@ public class ConsumerServiceImpl implements ConsumerService {
|
||||
kafkaConsumer.commitSync();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取属于该集群和consumerGroup下的所有topic的信息
|
||||
*/
|
||||
private Map<String, List<PartitionState>> getConsumerGroupPartitionStateList(ClusterDO clusterDO,
|
||||
ConsumerGroupDTO consumerGroupDTO,
|
||||
Map<String, List<PartitionState>> globalTopicNamePartitionStateListMap) {
|
||||
Map<String, List<PartitionState>> topicNamePartitionStateListMap = new HashMap<>(2);
|
||||
private Map<Integer, Long> getTopicConsumerOffsetInZK(ClusterDO clusterDO,
|
||||
TopicMetadata topicMetadata,
|
||||
ConsumerGroupDTO consumerGroupDTO) {
|
||||
Map<Integer, Long> offsetMap = new HashMap<>();
|
||||
|
||||
List<String> topicNameList = ConsumerMetadataCache.getConsumerGroupConsumedTopicList(clusterDO.getId(),consumerGroupDTO.getOffsetStoreLocation().getLocation(), consumerGroupDTO.getConsumerGroup());
|
||||
for (String topicName : topicNameList) {
|
||||
if (!ClusterMetadataManager.isTopicExist(clusterDO.getId(), topicName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<PartitionState> partitionStateList = globalTopicNamePartitionStateListMap.get(topicName);
|
||||
if (partitionStateList == null) {
|
||||
try {
|
||||
partitionStateList = zkService.getTopicPartitionState(clusterDO.getId(), topicName);
|
||||
} catch (Exception e) {
|
||||
logger.error("get topic partition state failed, clusterId:{} topicName:{}.", clusterDO.getId(), topicName, e);
|
||||
}
|
||||
if (partitionStateList == null) {
|
||||
continue;
|
||||
}
|
||||
globalTopicNamePartitionStateListMap.put(topicName, partitionStateList);
|
||||
}
|
||||
List<PartitionState> consumerGroupPartitionStateList = new ArrayList<>();
|
||||
for (PartitionState partitionState: partitionStateList) {
|
||||
consumerGroupPartitionStateList.add((PartitionState) partitionState.clone());
|
||||
}
|
||||
|
||||
if (consumerGroupDTO.getOffsetStoreLocation().equals(OffsetStoreLocation.ZOOKEEPER)) {
|
||||
updateTopicConsumerOffsetInZK(clusterDO, topicName, consumerGroupDTO, consumerGroupPartitionStateList);
|
||||
} else if (consumerGroupDTO.getOffsetStoreLocation().equals(OffsetStoreLocation.BROKER)) {
|
||||
updateTopicConsumerOffsetInBroker(clusterDO, topicName, consumerGroupDTO, consumerGroupPartitionStateList);
|
||||
}
|
||||
topicNamePartitionStateListMap.put(topicName, consumerGroupPartitionStateList);
|
||||
}
|
||||
return topicNamePartitionStateListMap;
|
||||
}
|
||||
|
||||
private void updateTopicConsumerOffsetInZK(ClusterDO cluster, String topicName, ConsumerGroupDTO consumerGroupDTO, List<PartitionState> partitionStateList) {
|
||||
ZkConfigImpl zkConfig = ClusterMetadataManager.getZKConfig(cluster.getId());
|
||||
for (PartitionState partitionState : partitionStateList) {
|
||||
ZkConfigImpl zkConfig = ClusterMetadataManager.getZKConfig(clusterDO.getId());
|
||||
for (int partitionId = 0; partitionId < topicMetadata.getPartitionNum(); ++partitionId) {
|
||||
//offset存储于zk中
|
||||
String consumerGroupOffsetLocation = ZkPathUtil.getConsumerGroupOffsetTopicPartitionNode(consumerGroupDTO.getConsumerGroup(), topicName, partitionState.getPartitionId());
|
||||
String consumerGroupOffsetLocation = ZkPathUtil.getConsumerGroupOffsetTopicPartitionNode(consumerGroupDTO.getConsumerGroup(), topicMetadata.getTopic(), partitionId);
|
||||
String offset = null;
|
||||
try {
|
||||
Stat stat = zkConfig.getNodeStat(consumerGroupOffsetLocation);
|
||||
@@ -317,39 +314,32 @@ public class ConsumerServiceImpl implements ConsumerService {
|
||||
continue;
|
||||
}
|
||||
offset = zkConfig.get(consumerGroupOffsetLocation);
|
||||
offsetMap.put(partitionId, Long.valueOf(offset));
|
||||
} catch (ConfigException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String consumerId = null;
|
||||
try {
|
||||
consumerId = zkConfig.get(ZkPathUtil.getConsumerGroupOwnersTopicPartitionNode(consumerGroupDTO.getConsumerGroup(), topicName, partitionState.getPartitionId()));
|
||||
} catch (ConfigException e) {
|
||||
// logger.error("get consumerId error in updateTopicConsumerOffsetInZK cluster:{} topic:{} consumerGroup:{}", cluster.getClusterName(), topicName, consumerGroupDTO.getConsumerGroup());
|
||||
}
|
||||
partitionState.setConsumerGroup(consumerGroupDTO.getConsumerGroup());
|
||||
updatePartitionStateOffset(partitionState, offset, consumerId);
|
||||
}
|
||||
return offsetMap;
|
||||
}
|
||||
|
||||
private void updateTopicConsumerOffsetInBroker(ClusterDO cluster, String topicName, ConsumerGroupDTO consumerGroupDTO, List<PartitionState> partitionStateList) {
|
||||
Map<Integer, String> offsetsFromBroker = getOffsetByGroupAndTopicFromBroker(cluster, consumerGroupDTO.getConsumerGroup(), topicName);
|
||||
private Map<Integer, Long> getTopicConsumerOffsetInBroker(ClusterDO clusterDO,
|
||||
String topicName,
|
||||
ConsumerGroupDTO consumerGroupDTO) {
|
||||
Map<Integer, String> offsetsFromBroker = getOffsetByGroupAndTopicFromBroker(clusterDO, consumerGroupDTO.getConsumerGroup(), topicName);
|
||||
if (offsetsFromBroker == null || offsetsFromBroker.isEmpty()) {
|
||||
return;
|
||||
return new HashMap<>(0);
|
||||
}
|
||||
|
||||
for (PartitionState partitionState : partitionStateList) {
|
||||
int partitionId = partitionState.getPartitionId();
|
||||
updatePartitionStateOffset(partitionState, offsetsFromBroker.get(partitionId), null);
|
||||
Map<Integer, Long> offsetMap = new HashMap<>(offsetsFromBroker.size());
|
||||
for (Map.Entry<Integer, String> entry: offsetsFromBroker.entrySet()) {
|
||||
try {
|
||||
offsetMap.put(entry.getKey(), Long.valueOf(entry.getValue()));
|
||||
} catch (Exception e) {
|
||||
logger.error("get topic consumer offset failed, clusterId:{} topicName:{} consumerGroup:{}."
|
||||
, clusterDO.getId(), topicName, consumerGroupDTO.getConsumerGroup());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePartitionStateOffset(PartitionState partitionState, String offset, String consumerId) {
|
||||
partitionState.setConsumeOffset(0);
|
||||
if (!StringUtils.isEmpty(offset)) {
|
||||
partitionState.setConsumeOffset(Long.parseLong(offset));
|
||||
}
|
||||
partitionState.setConsumerGroup(consumerId);
|
||||
return offsetMap;
|
||||
}
|
||||
|
||||
private Map<Integer, String> getConsumeIdMap(Long clusterId, String topicName, String consumerGroup) {
|
||||
|
||||
@@ -72,6 +72,9 @@ public class JmxServiceImpl implements JmxService {
|
||||
List<Attribute> attributeValueList = null;
|
||||
try {
|
||||
attributeValueList = connection.getAttributes(new ObjectName(mbean.getObjectName()), properties).asList();
|
||||
} catch (InstanceNotFoundException e) {
|
||||
logger.warn("getSpecifiedBrokerMetricsFromJmx@JmxServiceImpl, get metrics fail, objectName:{}.", mbean.getObjectName(), e);
|
||||
continue;
|
||||
} catch (Exception e) {
|
||||
logger.error("getSpecifiedBrokerMetricsFromJmx@JmxServiceImpl, get metrics fail, objectName:{}.", mbean.getObjectName(), e);
|
||||
continue;
|
||||
|
||||
@@ -51,7 +51,7 @@ public class OrderServiceImpl implements OrderService {
|
||||
if (orderPartitionDO != null) {
|
||||
orderPartitionDO.setOrderStatus(OrderStatusEnum.CANCELLED.getCode());
|
||||
}
|
||||
return modifyOrderPartition(orderPartitionDO, operator);
|
||||
return modifyOrderPartition(orderPartitionDO, operator, false);
|
||||
}
|
||||
return new Result(StatusCode.PARAM_ERROR, "order type illegal");
|
||||
}
|
||||
@@ -74,10 +74,10 @@ public class OrderServiceImpl implements OrderService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result modifyOrderPartition(OrderPartitionDO newOrderPartitionDO, String operator) {
|
||||
public Result modifyOrderPartition(OrderPartitionDO newOrderPartitionDO, String operator, boolean admin) {
|
||||
if (newOrderPartitionDO == null) {
|
||||
return new Result(StatusCode.PARAM_ERROR, "param illegal, order not exist");
|
||||
} else if (!newOrderPartitionDO.getApplicant().equals(operator)) {
|
||||
} else if (!admin && !newOrderPartitionDO.getApplicant().equals(operator)) {
|
||||
return new Result(StatusCode.PARAM_ERROR, "without authority to cancel the order");
|
||||
}
|
||||
OrderPartitionDO oldOrderPartitionDO = orderPartitionDao.getById(newOrderPartitionDO.getId());
|
||||
|
||||
@@ -345,7 +345,7 @@ public class TopicServiceImpl implements TopicService {
|
||||
} else {
|
||||
topicMetrics = jmxService.getSpecifiedTopicMetricsFromJmx(clusterId, topicName, TopicMetrics.getFieldNameList(MetricsType.TOPIC_FLOW_DETAIL), true);
|
||||
topicOverviewDTO.setBytesInPerSec(topicMetrics.getBytesInPerSec());
|
||||
topicOverviewDTO.setProduceRequestPerSec(topicMetrics.getTotalProduceRequestsPerSec());
|
||||
topicOverviewDTO.setProduceRequestPerSec(topicMetrics.getBytesOutPerSec());
|
||||
}
|
||||
return topicOverviewDTO;
|
||||
}
|
||||
|
||||
16
web/bin/shutdown.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd `dirname $0`/../lib
|
||||
lib_dir=`pwd`
|
||||
|
||||
pid=`ps ax | grep -i 'kafka-manager-web' | grep ${lib_dir} | grep java | grep -v grep | awk '{print $1}'`
|
||||
if [ -z "$pid" ] ; then
|
||||
echo "No kafka-manager-web running."
|
||||
exit -1;
|
||||
fi
|
||||
|
||||
echo "The kafka-manager-web(${pid}) is running..."
|
||||
|
||||
kill ${pid}
|
||||
|
||||
echo "Send shutdown request to kafka-manager-web(${pid}) OK"
|
||||
46
web/bin/startup.sh
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
error_exit ()
|
||||
{
|
||||
echo "ERROR: $1 !!"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better!"
|
||||
|
||||
fi
|
||||
|
||||
export WEB_SERVER="kafka-manager-web-*"
|
||||
export JAVA_HOME
|
||||
export JAVA="$JAVA_HOME/bin/java"
|
||||
export BASE_DIR=`cd $(dirname $0)/..; pwd`
|
||||
export DEFAULT_SEARCH_LOCATIONS="classpath:/,classpath:/config/,file:./,file:./config/"
|
||||
export CUSTOM_SEARCH_LOCATIONS=${DEFAULT_SEARCH_LOCATIONS},file:${BASE_DIR}/conf/
|
||||
|
||||
#===========================================================================================
|
||||
# JVM Configuration
|
||||
#===========================================================================================
|
||||
|
||||
JAVA_OPT="${JAVA_OPT} -server -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
|
||||
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof"
|
||||
JAVA_OPT="${JAVA_OPT} -Xloggc:${BASE_DIR}/logs/gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
|
||||
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/lib/${WEB_SERVER}.jar"
|
||||
JAVA_OPT="${JAVA_OPT} --spring.config.location=${CUSTOM_SEARCH_LOCATIONS}"
|
||||
JAVA_OPT="${JAVA_OPT} --logging.config=${BASE_DIR}/conf/logback-spring.xml"
|
||||
JAVA_OPT="${JAVA_OPT} --server.max-http-header-size=524288"
|
||||
|
||||
if [ ! -d "${BASE_DIR}/logs" ]; then
|
||||
mkdir ${BASE_DIR}/logs
|
||||
fi
|
||||
|
||||
echo "$JAVA ${JAVA_OPT}"
|
||||
|
||||
# check the start.out log output file
|
||||
if [ ! -f "${BASE_DIR}/logs/start.out" ]; then
|
||||
touch "${BASE_DIR}/logs/start.out"
|
||||
fi
|
||||
# start
|
||||
echo "$JAVA ${JAVA_OPT}" > ${BASE_DIR}/logs/start.out 2>&1 &
|
||||
nohup $JAVA ${JAVA_OPT} >> ${BASE_DIR}/logs/start.out 2>&1 &
|
||||
echo "kafka-manager is starting,you can check the ${BASE_DIR}/logs/start.out"
|
||||
32
web/conf/application.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
server:
|
||||
port: 8080
|
||||
tomcat:
|
||||
accept-count: 100
|
||||
max-connections: 1000
|
||||
max-threads: 20
|
||||
min-spare-threads: 20
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: kafkamanager
|
||||
datasource:
|
||||
kafka-manager:
|
||||
jdbc-url: jdbc:mysql://localhost:3306/kafka_manager?characterEncoding=UTF-8&serverTimezone=GMT%2B8
|
||||
username: admin
|
||||
password: admin
|
||||
driver-class-name: org.mariadb.jdbc.Driver
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
profiles:
|
||||
active: dev
|
||||
|
||||
logging:
|
||||
config: classpath:logback-spring.xml
|
||||
|
||||
# kafka监控
|
||||
kafka-monitor:
|
||||
enabled: true
|
||||
notify-kafka:
|
||||
cluster-id: 95
|
||||
topic-name: kmo_monitor
|
||||
25
web/pom.xml
@@ -4,14 +4,13 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>kafka-manager-web</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>kafka-manager</artifactId>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath />
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
@@ -111,6 +110,26 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<finalName>kafka-manager-${project.version}</finalName>
|
||||
<descriptors>
|
||||
<descriptor>./src/main/resources/assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
<tarLongFileMode>posix</tarLongFileMode>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -176,7 +176,7 @@ public class OrderController {
|
||||
TopicDO topicInfoDO = OrderConverter.convert2TopicInfoDO(orderTopicDO);
|
||||
List<Integer> brokerIdList = regionService.getFullBrokerId(clusterDO.getId(), reqObj.getRegionIdList(), reqObj.getBrokerIdList());
|
||||
Properties topicConfig = new Properties();
|
||||
topicConfig.setProperty("retention.ms", String.valueOf(reqObj.getRetentionTime()));
|
||||
topicConfig.setProperty("retention.ms", String.valueOf(reqObj.getRetentionTime() * 60 * 60 * 1000));
|
||||
try {
|
||||
TopicMetadata topicMetadata = new TopicMetadata();
|
||||
topicMetadata.setTopic(orderTopicDO.getTopicName());
|
||||
@@ -325,14 +325,16 @@ public class OrderController {
|
||||
orderPartitionDO.setApprover(username);
|
||||
orderPartitionDO.setOpinion(reqObj.getApprovalOpinions());
|
||||
orderPartitionDO.setOrderStatus(reqObj.getOrderStatus());
|
||||
result = orderService.modifyOrderPartition(orderPartitionDO, username);
|
||||
result = orderService.modifyOrderPartition(orderPartitionDO, username, true);
|
||||
if (!StatusCode.SUCCESS.equals(result.getCode())) {
|
||||
return new Result(StatusCode.OPERATION_ERROR, "create topic success, but update order status failed, err:" + result.getMessage());
|
||||
return new Result(StatusCode.OPERATION_ERROR, "expand topic success, but update order status failed, err:" + result.getMessage());
|
||||
}
|
||||
return new Result();
|
||||
}
|
||||
|
||||
private Result expandTopic(ClusterDO clusterDO, OrderPartitionExecModel reqObj, OrderPartitionDO orderPartitionDO) {
|
||||
private Result expandTopic(ClusterDO clusterDO,
|
||||
OrderPartitionExecModel reqObj,
|
||||
OrderPartitionDO orderPartitionDO) {
|
||||
List<Integer> brokerIdList = regionService.getFullBrokerId(clusterDO.getId(), reqObj.getRegionIdList(), reqObj.getBrokerIdList());
|
||||
try {
|
||||
TopicMetadata topicMetadata = new TopicMetadata();
|
||||
@@ -343,6 +345,8 @@ public class OrderController {
|
||||
if (!AdminTopicStatusEnum.SUCCESS.equals(adminTopicStatusEnum)) {
|
||||
return new Result(StatusCode.OPERATION_ERROR, adminTopicStatusEnum.getMessage());
|
||||
}
|
||||
orderPartitionDO.setPartitionNum(reqObj.getPartitionNum());
|
||||
orderPartitionDO.setBrokerList(ListUtils.intList2String(brokerIdList));
|
||||
} catch (Exception e) {
|
||||
logger.error("expandTopic@OrderController, create failed, req:{}.", reqObj);
|
||||
return new Result(StatusCode.OPERATION_ERROR, Constant.KAFKA_MANAGER_INNER_ERROR);
|
||||
|
||||
@@ -78,6 +78,7 @@ public class BrokerModelConverter {
|
||||
Double bytesInPerSec = brokerOverallDTO.getBytesInPerSec() / 1024.0 / 1024.0;
|
||||
brokerOverviewVO.setBytesInPerSec(Math.round(bytesInPerSec * 100) / 100.0);
|
||||
}
|
||||
brokerOverviewVO.setUnderReplicatedPartitionCount(brokerOverallDTO.getUnderReplicatedPartitions());
|
||||
brokerOverviewVO.setLeaderCount(brokerOverallDTO.getLeaderCount());
|
||||
if (brokerOverallDTO.getPartitionCount() != null && brokerOverallDTO.getUnderReplicatedPartitions() != null) {
|
||||
brokerOverviewVO.setNotUnderReplicatedPartitionCount(brokerOverallDTO.getPartitionCount() - brokerOverallDTO.getUnderReplicatedPartitions());
|
||||
|
||||
@@ -86,7 +86,8 @@ public class OrderConverter {
|
||||
|
||||
public static OrderPartitionVO convert2OrderPartitionVO(OrderPartitionDO orderPartitionDO,
|
||||
TopicMetadata topicMetadata,
|
||||
Long maxAvgBytes, List<RegionDO> regionDOList) {
|
||||
Long maxAvgBytes,
|
||||
List<RegionDO> regionDOList) {
|
||||
if (orderPartitionDO == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -100,8 +101,12 @@ public class OrderConverter {
|
||||
if (topicMetadata == null) {
|
||||
return orderPartitionVO;
|
||||
}
|
||||
orderPartitionVO.setPartitionNum(topicMetadata.getPartitionNum());
|
||||
|
||||
orderPartitionVO.setPartitionNum(null);
|
||||
orderPartitionVO.setBrokerIdList(new ArrayList<>(topicMetadata.getBrokerIdSet()));
|
||||
if (OrderStatusEnum.PASSED.getCode().equals(orderPartitionDO.getOrderStatus())) {
|
||||
orderPartitionVO.setPartitionNum(orderPartitionDO.getPartitionNum());
|
||||
}
|
||||
|
||||
if (regionDOList == null || regionDOList.isEmpty()) {
|
||||
orderPartitionVO.setRegionNameList(new ArrayList<>());
|
||||
|
||||
@@ -30,9 +30,13 @@ public class BrokerOverallVO {
|
||||
@ApiModelProperty(value = "分区数")
|
||||
private Integer partitionCount;
|
||||
|
||||
@ApiModelProperty(value = "未同步分区数")
|
||||
@Deprecated
|
||||
@ApiModelProperty(value = "同步分区数")
|
||||
private Integer notUnderReplicatedPartitionCount;
|
||||
|
||||
@ApiModelProperty(value = "未同步分区数")
|
||||
private Integer underReplicatedPartitionCount;
|
||||
|
||||
@ApiModelProperty(value = "leader数")
|
||||
private Integer leaderCount;
|
||||
|
||||
@@ -103,6 +107,14 @@ public class BrokerOverallVO {
|
||||
this.notUnderReplicatedPartitionCount = notUnderReplicatedPartitionCount;
|
||||
}
|
||||
|
||||
public Integer getUnderReplicatedPartitionCount() {
|
||||
return underReplicatedPartitionCount;
|
||||
}
|
||||
|
||||
public void setUnderReplicatedPartitionCount(Integer underReplicatedPartitionCount) {
|
||||
this.underReplicatedPartitionCount = underReplicatedPartitionCount;
|
||||
}
|
||||
|
||||
public Integer getLeaderCount() {
|
||||
return leaderCount;
|
||||
}
|
||||
@@ -130,6 +142,7 @@ public class BrokerOverallVO {
|
||||
", bytesInPerSec=" + bytesInPerSec +
|
||||
", partitionCount=" + partitionCount +
|
||||
", notUnderReplicatedPartitionCount=" + notUnderReplicatedPartitionCount +
|
||||
", underReplicatedPartitionCount=" + underReplicatedPartitionCount +
|
||||
", leaderCount=" + leaderCount +
|
||||
", regionName='" + regionName + '\'' +
|
||||
'}';
|
||||
|
||||
33
web/src/main/resources/application-pg.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
server:
|
||||
port: 8080
|
||||
tomcat:
|
||||
accept-count: 100
|
||||
max-connections: 1000
|
||||
max-threads: 20
|
||||
min-spare-threads: 20
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: kafkamanager
|
||||
datasource:
|
||||
kafka-manager:
|
||||
driver-class-name: org.postgresql.Driver
|
||||
jdbc-url: jdbc:postgresql://localhost:5432/kafka_manager?reWriteBatchedInserts=true
|
||||
username: admin
|
||||
password: admin
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
hikari:
|
||||
connection-init-sql: "SET TIME ZONE 'Asia/Chongqing';SET CLIENT_ENCODING TO 'UTF-8';"
|
||||
connection-test-query: "select 1;"
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
logging:
|
||||
config: classpath:logback-spring.xml
|
||||
|
||||
# kafka监控
|
||||
kafka-monitor:
|
||||
enabled: true
|
||||
notify-kafka:
|
||||
cluster-id: 95
|
||||
topic-name: kmo_monitor
|
||||
@@ -11,16 +11,13 @@ spring:
|
||||
name: kafkamanager
|
||||
datasource:
|
||||
kafka-manager:
|
||||
driver-class-name: org.mariadb.jdbc.Driver
|
||||
jdbc-url: jdbc:mysql://localhost:3306/kafka_manager?characterEncoding=UTF-8&serverTimezone=GMT%2B8
|
||||
username: admin
|
||||
password: admin
|
||||
driver-class-name: org.mariadb.jdbc.Driver
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
profiles:
|
||||
active: dev
|
||||
|
||||
logging:
|
||||
config: classpath:logback-spring.xml
|
||||
|
||||
|
||||
34
web/src/main/resources/assembly.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
|
||||
<id>bin</id>
|
||||
<formats>
|
||||
<format>dir</format>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<includes>
|
||||
<include>./bin/*</include>
|
||||
</includes>
|
||||
<fileMode>0755</fileMode>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>./src/main/resources/</directory>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
<includes>
|
||||
<include>application.yml</include>
|
||||
<include>logback-spring.xml</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}</directory>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
|
||||
</fileSets>
|
||||
</assembly>
|
||||