├── .dockerIgnore ├── .eslintrc.json ├── .gitignore ├── Dockerfile ├── README.md ├── __tests__ └── enzyme.js ├── client ├── App.jsx ├── components │ ├── BarChart.jsx │ ├── DataGenerator.jsx │ ├── DoughnutChart.jsx │ ├── LineChart.jsx │ ├── Nav.jsx │ ├── PolarChart.jsx │ ├── airtable.jsx │ ├── subcharts.jsx │ └── terminal.jsx ├── images │ ├── airtable-logo.png │ ├── kafkaESK-demo4.gif │ ├── kafkaesk-logo-readme.png │ └── kafkaesk-logo.png ├── index.html ├── index.js └── styles │ ├── DataGenerator.scss │ ├── airtable.scss │ ├── app.scss │ ├── lineChart.scss │ ├── mainchart.scss │ ├── nav.scss │ └── subcharts.scss ├── dist ├── index.html ├── index_bundle.js └── index_bundle.js.map ├── package-lock.json ├── package.json ├── server ├── cmd │ ├── consumer.sh │ ├── ksql │ │ ├── error_data.json │ │ └── statements.sql │ └── producer.sh └── server.js └── webpack.config.js /.dockerIgnore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "plugin:react/recommended", 9 | "airbnb" 10 | ], 11 | "parserOptions": { 12 | "ecmaFeatures": { 13 | "jsx": true 14 | }, 15 | "ecmaVersion": 12, 16 | "sourceType": "module" 17 | }, 18 | "plugins": [ 19 | "react" 20 | ], 21 | "rules": { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | /.pnp 4 | .pnp.js 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12.19 2 | WORKDIR /usr/src/app 3 | COPY . /usr/src/app 4 | RUN npm install 5 | RUN npm run create 6 | EXPOSE 3333 8080 7 | #ENTRYPOINT npm start 8 | CMD ["npm", "start"] 9 | # ENTRYPOINT ["node", "server/server.js"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ![](client/images/kafkaesk-logo-readme.png) 4 | 5 |
6 | 7 | ## **About:** 8 | KafkaESK, currently in Beta, is an event-driven monitoring tool that can consume messages from Apache Kafka clusters and display the aggregated data on a dashboard for analysis and maintenance.
Used in a pipeline that includes **Apache Kafka Connect** (for writing sources and sinks that either ingests the entire database and stream table updates to Kafka topics or continuously delivers data from the topics into external systems) and **ksqlDB** (for stream processing that enables executing continuous computations over an unbounded stream of events), KafkaESK can incrementally update in real-time as events arrive.
9 | This powerful tool can be used to digest live data from IoT/smart sensor technology, machine performance, and even website activity such as clickstreams. 10 |
11 | 12 | ### Stretch Features Include: 13 | - User ability to dynamically customize data charts directly on the dashboard 14 | - Integrating a terminal into the dashboard GUI that will allow interaction with the ksqlDB CLI to: 15 | - craft materialized views over streams 16 | - receive real-time push updates 17 | - pull current state on demand 18 | - transform, filter, aggregate, and join collections 19 | - push and pull queries 20 | - Caching of previously ran queries 21 | - Time machine capability 22 | 23 | ## **Prerequisites:** 24 | - Docker version 1.11 or later is [installed and running](https://docs.docker.com/engine/install/). 25 | - At the time of release, KafkaESK operates in conjunction with the Confluent Platform(version 6.0.0). Use these installation methods to quickly get a Confluent Platform development environment up and running on your local machine. 26 | 27 | - [Quick Start for Apache Kafka using Confluent Platform (Local)](https://docs.confluent.io/platform/current/quickstart/ce-quickstart.html#ce-quickstart) 28 | - [Quick Start for Apache Kafka using Confluent Platform (Docker)](https://docs.confluent.io/platform/current/quickstart/ce-docker-quickstart.html#ce-docker-quickstart) 29 | - [Git](https://git-scm.com/downloads) 30 | - Internet connectivity 31 | 32 | ## **Demo:** 33 | For demonstration purposes, mock data is used to simulate a live stream of HTTP requests that end in error from user clicks. The KafkaESK tool will track this activity and render the incoming messages on multiple graphs. 34 |
35 |
36 | 37 |
38 | 39 | ![](client/images/kafkaESK-demo4.gif) 40 | 41 |
42 |
43 | 1. Run the following command while inside the cloned repo directory: 44 | 45 | ```bash 46 | docker run -d -p 8080:8080 -p 3333:3333 --name kafka kafkaesk 47 | ``` 48 | 49 | 2. Open a terminal and launch the Confluent Platform using the Confluent CLI `confluent local services start` command. This command starts all of the Confluent Platform components, including Kafka, ZooKeeper, Schema Registry, HTTP REST Proxy for Kafka, Kafka Connect, ksqlDB, and Control Center. 50 | 51 | ```bash 52 | confluent local services start 53 | ``` 54 | Your output should resemble: 55 | 56 | ```bash 57 | Starting Zookeeper 58 | Zookeeper is [UP] 59 | Starting Kafka 60 | Kafka is [UP] 61 | Starting Schema Registry 62 | Schema Registry is [UP] 63 | Starting Kafka REST 64 | Kafka REST is [UP] 65 | Starting Connect 66 | Connect is [UP] 67 | Starting KSQL Server 68 | KSQL Server is [UP] 69 | Starting Control Center 70 | Control Center is [UP] 71 | ``` 72 | 3. Run the following command to start the ksqlDB CLI and connect to a ksqlDB server: 73 | ```bash 74 | ksql 75 | ``` 76 | - After the ksqlDB CLI starts, your terminal should resemble the following: 77 | ```bash 78 | =========================================== 79 | = _ _ ____ ____ = 80 | = | | _____ __ _| | _ \| __ ) = 81 | = | |/ / __|/ _` | | | | | _ \ = 82 | = | <\__ \ (_| | | |_| | |_) | = 83 | = |_|\_\___/\__, |_|____/|____/ = 84 | = |_| = 85 | = Event Streaming Database purpose-built = 86 | = for stream processing apps = 87 | =========================================== 88 | 89 | Copyright 2017-2020 Confluent Inc. 90 | 91 | CLI v6.0.0, Server v6.0.0 located at http://localhost:8088 92 | 93 | Having trouble? Type 'help' (case-insensitive) for a rundown of how things work! 94 | 95 | ksql> 96 | ``` 97 | - Open the `statements.ksql` file in a code editor and walk through each section via the ksqlDB CLI. 98 | - Copy and paste each statement into ksqlDB and run. Ensure each is successful. 99 | 100 | 4. In a fresh terminal, run the producer script: 101 | - Make sure you are in the KafkaESK directory, then run the script in your terminal: 102 | ```bash 103 | ./producer.sh 104 | ``` 105 | Troubleshoot: If you don't have permission to run the above command, run this command first: 106 | ```bash 107 | chmod +x ./producer.sh 108 | ``` 109 | - Alternatively, you can copy and paste the contents of the `producer.sh` file into the terminal and run it: 110 | ```bash 111 | kafka-producer-perf-test \ 112 | --topic CLICKSTREAM_CODES \ 113 | --throughput 2 \ 114 | --producer-props bootstrap.servers=localhost:9092 \ 115 | --payload-file server/cmd/ksql/error_data.json \ 116 | --num-records 1000 & 117 | ``` 118 | 1. Run the start script: 119 | ``` bash 120 | npm start 121 | ``` 122 | 123 | ## **Connect from an External Source:** 124 | Create connections from within ksqlDB by utilizing the Apache Kafka built-in framework, [Kafka Connect](https://docs.confluent.io/platform/current/connect/index.html), to integrate systems by both pulling data into Kafka and pushing it downstream. 125 |
126 | 127 | Resources: 128 | 129 | - [Why Kafka Connect?](https://confluent.buzzsprout.com/186154/1265780-why-kafka-connect-ft-robin-moffatt) 130 | - An externally hosted list of connectors is maintained by Confluent at the [Confluent Hub](https://www.confluent.io/hub/). 131 | - Checkout other integration tools within the Kafka [ecosystem](https://cwiki.apache.org/confluence/display/KAFKA/Ecosystem). 132 | 133 | ### **How to Customize:** 134 | Then, do complex property graph analysis by cleansing and preparing the data with ksqlDB and stream it to KafkaESK. You can also calculate rolling aggregates by building tables from the streams directly in ksqlDB. 135 |
136 | 137 | Cleansing and Preparing within KafkaESK Checklist: 138 | - [ ] edit the producer script 139 | - [ ] edit the consumer script 140 | - [ ] replace `error_data.json` with any static/mock data to test 141 | - [ ] edit `statements.sql` to reflect your streams and tables 142 | - [ ] in `server.js`, replace all variable names, group IDs, and topic names within the socket connection. This way, the Kafka Consumer can consume the intended messages. 143 | 144 | ```javascript 145 | const consumer = kafka.consumer({ 146 | groupId: "test-group", 147 | fromBeginning: true, 148 | }); 149 | consumer_404.connect(); 150 | consumer_404.subscribe({ topic: "your-topic" }); 151 | consumer_404.run({ 152 | eachMessage: async ({ topic, partition, message }) => { 153 | socket.broadcast.emit("your-topic", message.value.toString()); 154 | }, 155 | }); 156 | ``` 157 | - [ ] in each component that live in the `client` directory, replace within the socket event listeners the correct event name. (The event name can be referenced from `server.js`. They should be the corresponding topic names.) 158 | 159 | ```javascript 160 | socket.on('your-topic', (data) => { 161 | }) 162 | ``` 163 | 164 | ## **Contributors:** 165 | 166 | Ai Mi Bui | Brooke Luro | Chelsea Harris | Spencer Flohr 167 | 168 | ### **How to Contribute:** 169 | We are happy to have contributions, whether for trivial cleanups or big new features! 170 | ### Reporting an Issue: 171 | Reporting potential issues are more than welcome as a significant contribution to the project. All bugs, tasks, or enhancements are tracked as [GitHub issues](https://github.com/oslabs-beta/kafkaESK/issues). Issues that may be a good start for first-time contributors are labeled with "good first issue".

172 | If you have a question or simply are not sure if it is really an issue or not, please [contact us]() first before creating a new ticket. 173 | ### Becoming a Committer: 174 | We are always interested in adding new contributors. What we look for is a series of contributions, good taste, and an ongoing interest in the project. KafkaESK considers the following guidelines for promoting new committers: 175 | - Made significant contributions in areas such as design, code, and/or documentation. The following are some examples (list not exclusive): 176 | - Fixed critical bugs (including performance improvements). 177 | - Made major tech-debt cleanup. 178 | - Made major documentation improvements. 179 | 180 | ## License 181 | MIT License 182 | -------------------------------------------------------------------------------- /__tests__/enzyme.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { configure, shallow } from 'enzyme'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import LineChart from '../client/components/LineChart'; 5 | import DoughnutChart from '../client/components/DoughnutChart'; 6 | import BarChart from '../client/components/BarChart'; 7 | import PolarChart from '../client/components/PolarChart'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | configure({ disableLifecycleMethods: true }); 11 | 12 | describe('React unit tests', () => { 13 | let wrapper; 14 | 15 | describe('LineChart', () => { 16 | beforeAll(() => { 17 | wrapper = shallow(); 18 | }); 19 | 20 | it('Renders component within a
tag', () => { 21 | expect(wrapper.type()).toEqual('div'); 22 | }); 23 | 24 | it('Renders a canvas element for the line chart', () => { 25 | expect(wrapper.find('canvas')); 26 | }); 27 | }); 28 | 29 | describe('DoughnutChart', () => { 30 | beforeAll(() => { 31 | wrapper = shallow(); 32 | }); 33 | 34 | it('Renders a canvas element for the doughnut chart', () => { 35 | expect(wrapper.find('canvas')); 36 | }); 37 | }); 38 | 39 | describe('PolarChart', () => { 40 | beforeAll(() => { 41 | wrapper = shallow(); 42 | }); 43 | 44 | it('Renders a canvas element for the polar chart', () => { 45 | expect(wrapper.find('canvas')); 46 | }); 47 | }); 48 | 49 | describe('BarChart', () => { 50 | beforeAll(() => { 51 | wrapper = shallow(); 52 | }); 53 | 54 | it('Renders a canvas element for the line chart', () => { 55 | expect(wrapper.find('canvas')); 56 | }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /client/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Nav from './components/Nav.jsx'; 3 | import LineChart from './components/LineChart.jsx'; 4 | import AirtableIntegration from './components/airtable.jsx'; 5 | import SubCharts from './components/subcharts.jsx'; 6 | import './styles/app.scss'; 7 | 8 | // eslint-disable-next-line react/prefer-stateless-function 9 | class App extends Component { 10 | constructor(props) { 11 | super(props); 12 | } 13 | 14 | render() { 15 | return ( 16 |
17 |
18 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 |
30 | ); 31 | } 32 | } 33 | export default App; 34 | -------------------------------------------------------------------------------- /client/components/BarChart.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable lines-between-class-members */ 2 | /* eslint-disable react/destructuring-assignment */ 3 | import React from 'react'; 4 | import { Bar } from 'react-chartjs-2'; 5 | import '../styles/mainchart.scss'; 6 | 7 | class BarChart extends React.Component { 8 | constructor(props) { 9 | super(props); 10 | this.state = { 11 | // eslint-disable-next-line react/no-unused-state 12 | datasets: [ 13 | { 14 | label: '404', 15 | backgroundColor: 'rgb(189,211,88)', 16 | data: [], 17 | }, 18 | { 19 | label: '405', 20 | backgroundColor: 'rgb(255,255,255)', 21 | data: [], 22 | }, 23 | { 24 | label: '406', 25 | backgroundColor: 'rgb(27, 176, 117)', 26 | data: [], 27 | }, 28 | { 29 | label: '407', 30 | backgroundColor: 'rgb(153,151,153)', 31 | data: [], 32 | }, 33 | ], 34 | }; 35 | } 36 | 37 | componentDidMount() { 38 | const socket = io.connect('http://localhost:3333'); 39 | // Connects 404 Error Consumer 40 | socket.on('404_ERRORS_PER_MIN', (data) => { 41 | // parse incoming data 42 | const message = JSON.parse(data); 43 | 44 | // store the current state array in a variable 45 | const currDataSets = this.state.datasets; 46 | 47 | // create a new data variable, spread current array into new array 48 | const updatedDataSets = [...currDataSets]; 49 | 50 | // push incoming count to data array at index 0 51 | updatedDataSets[0].data = [message.COUNT]; 52 | 53 | // set the state with the updated variable 54 | this.setState({ datasets: updatedDataSets }); 55 | }); 56 | 57 | // Connects 405 Error Consumer 58 | socket.on('405_ERRORS_PER_MIN', (data) => { 59 | // parse incoming data 60 | const message = JSON.parse(data); 61 | 62 | // store the current state array in a variable 63 | const currDataSets = this.state.datasets; 64 | 65 | // create a new data variable, spread current array into new array 66 | const updatedDataSets = [...currDataSets]; 67 | 68 | // push incoming count to data array at index 1 69 | updatedDataSets[1].data = [message.COUNT]; 70 | 71 | // set the state with the updated variable 72 | this.setState({ datasets: updatedDataSets }); 73 | }); 74 | 75 | // Connects 406 Error Consumer 76 | socket.on('406_ERRORS_PER_MIN', (data) => { 77 | // parse incoming data 78 | const message = JSON.parse(data); 79 | 80 | // store the current state array in a variable 81 | const currDataSets = this.state.datasets; 82 | 83 | // create a new data variable, spread current array into new array 84 | const updatedDataSets = [...currDataSets]; 85 | 86 | // push incoming data to new data variable 87 | updatedDataSets[2].data = [message.COUNT]; 88 | 89 | // set the state with the updated variable 90 | this.setState({ datasets: updatedDataSets }); 91 | }); 92 | 93 | // Connects 407 Error Consumer 94 | socket.on('407_ERRORS_PER_MIN', (data) => { 95 | // parse incoming data 96 | const message = JSON.parse(data); 97 | 98 | // store the current state array in a variable 99 | const currDataSets = this.state.datasets; 100 | 101 | // create a new data variable, spread current array into new array 102 | const updatedDataSets = [...currDataSets]; 103 | 104 | // push incoming data to new data variable 105 | updatedDataSets[3].data = [message.COUNT]; 106 | 107 | // set the state with the updated variable 108 | this.setState({ datasets: updatedDataSets }); 109 | }); 110 | } 111 | render() { 112 | return ; 113 | } 114 | } 115 | 116 | export default BarChart; 117 | -------------------------------------------------------------------------------- /client/components/DataGenerator.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable class-methods-use-this */ 2 | import React, { Component } from 'react'; 3 | import '../styles/DataGenerator.scss'; 4 | // create a form 5 | // takes inputs to generate topics, producers, consumers, etc. 6 | class DataGenerator extends Component { 7 | constructor(props) { 8 | super(props); 9 | this.state = { 10 | command: '', 11 | }; 12 | this.handleChange = this.handleChange.bind(this); 13 | this.handleSubmit = this.handleSubmit.bind(this); 14 | } 15 | 16 | // updates the state of command string based on form input 17 | handleChange(event) { 18 | this.setState({ [event.target.name]: event.target.value }); 19 | } 20 | 21 | // should send ksql command string to server to be run in terminal 22 | handleSubmit(event) { 23 | event.preventDefault(); 24 | } 25 | 26 | render() { 27 | return ( 28 |
29 |

KSQL CLI

30 | 31 | 38 | 41 | 44 |
45 | ); 46 | } 47 | } 48 | 49 | export default DataGenerator; 50 | -------------------------------------------------------------------------------- /client/components/DoughnutChart.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Doughnut } from 'react-chartjs-2'; 3 | import '../styles/mainchart.scss'; 4 | 5 | // doughnut data array corresponds to single total for each label 6 | class DoughnutChart extends Component { 7 | constructor(props) { 8 | super(props); 9 | // state holds labels for each error type and single data point for each current count(datasets:[{data:[]}]) 10 | this.state = { 11 | labels: ['404', '405', '406', '407'], 12 | datasets: [ 13 | { 14 | label: 'Errors', 15 | backgroundColor: ['#BDD358', '#FFFFFF', '#1BB075', '#999799'], 16 | borderColor: 'transparent', 17 | data: [undefined, undefined, undefined, undefined], 18 | }, 19 | ], 20 | }; 21 | } 22 | 23 | componentDidMount() { 24 | const socket = io.connect('http://localhost:3333'); 25 | // Connects 404 Error Consumer 26 | socket.on('404_ERRORS_PER_MIN', (data) => { 27 | // parse incoming data 28 | const message = JSON.parse(data); 29 | 30 | // store the current datasets array in a variable 31 | const currDataSets = this.state.datasets; // array 32 | 33 | // create a new data variable, spread current datasets into new array 34 | const updatedDataSets = [...currDataSets]; 35 | 36 | updatedDataSets[0].data[0] = message.COUNT; 37 | 38 | // variable for storing updated version of state 39 | const newChartData = { 40 | ...this.state, 41 | datasets: updatedDataSets[0][data][0], 42 | }; 43 | 44 | // set the state of chartData to updated version 45 | this.setState({ datasets: newChartData }); 46 | }); 47 | // Connects 404 Error Consumer 48 | socket.on('405_ERRORS_PER_MIN', (data) => { 49 | const message = JSON.parse(data); 50 | 51 | // store the current datasets array in a variable 52 | const currDataSets = this.state.datasets; // array 53 | 54 | // create a new data variable, spread current datasets into new array 55 | const updatedDataSets = [...currDataSets]; 56 | 57 | updatedDataSets[0].data[1] = message.COUNT; 58 | 59 | // variable for storing updated version of state 60 | const newChartData = { 61 | ...this.state, 62 | datasets: updatedDataSets[0][data][1], 63 | }; 64 | 65 | // set the state of chartData to updated version 66 | this.setState({ datasets: newChartData }); 67 | }); 68 | 69 | // Connects 406 Error Consumer 70 | socket.on('406_ERRORS_PER_MIN', (data) => { 71 | // parse incoming data 72 | const message = JSON.parse(data); 73 | 74 | // store the current datasets array in a variable 75 | const currDataSets = this.state.datasets; // array 76 | 77 | // create a new data variable, spread current datasets into new array 78 | const updatedDataSets = [...currDataSets]; 79 | 80 | updatedDataSets[0].data[2] = message.COUNT; 81 | 82 | // variable for storing updated version of state 83 | const newChartData = { 84 | ...this.state, 85 | datasets: updatedDataSets[0][data][2], 86 | }; 87 | 88 | // set the state of chartData to updated version 89 | this.setState({ datasets: newChartData }); 90 | }); 91 | 92 | // Connects 407 Error Consumer 93 | socket.on('407_ERRORS_PER_MIN', (data) => { 94 | // parse incoming data 95 | const message = JSON.parse(data); 96 | 97 | // store the current datasets array in a variable 98 | const currDataSets = this.state.datasets; // array 99 | 100 | // create a new data variable, spread current datasets into new array 101 | const updatedDataSets = [...currDataSets]; 102 | 103 | updatedDataSets[0].data[3] = message.COUNT; 104 | 105 | // variable for storing updated version of state 106 | const newChartData = { 107 | ...this.state, 108 | datasets: updatedDataSets[0][data][3], 109 | }; 110 | 111 | // set the state of chartData to updated version 112 | this.setState({ datasets: newChartData }); 113 | }); 114 | } 115 | 116 | render() { 117 | return ; 118 | } 119 | } 120 | export default DoughnutChart; 121 | -------------------------------------------------------------------------------- /client/components/LineChart.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Line } from 'react-chartjs-2'; 3 | import '../styles/lineChart.scss'; 4 | 5 | class LineChart extends Component { 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | error: null, 10 | isLoaded: false, 11 | allFilteredData: [], 12 | // eslint-disable-next-line react/no-unused-state 13 | chartData: { 14 | labels: [], 15 | datasets: [ 16 | { 17 | label: '404', 18 | fill: false, 19 | lineTension: 0.1, 20 | backgroundColor: 'rgba(225,0,0,0.4)', 21 | borderColor: 'rgb(189,211,88)', 22 | borderCapStyle: 'square', 23 | borderDash: [], 24 | borderDashOffset: 0.0, 25 | borderJoinStyle: 'miter', 26 | pointBackgroundColor: 'white', 27 | pointBorderWidth: 1, 28 | pointHoverRadius: 8, 29 | pointHoverBackgroundColor: 'yellow', 30 | pointHoverBorderColor: 'brown', 31 | pointHoverBorderWidth: 2, 32 | pointRadius: 4, 33 | pointHitRadius: 10, 34 | data: [], 35 | spanGaps: true, 36 | }, 37 | { 38 | label: '405', 39 | fill: false, 40 | lineTension: 0.1, 41 | borderColor: 'rgb(255,255,255)', 42 | borderCapStyle: 'butt', 43 | borderDash: [], 44 | borderDashOffset: 0.0, 45 | borderJoinStyle: 'miter', 46 | pointBackgroundColor: 'white', 47 | pointBorderWidth: 1, 48 | pointHoverRadius: 8, 49 | pointHoverBackgroundColor: 'brown', 50 | pointHoverBorderColor: 'yellow', 51 | pointHoverBorderWidth: 2, 52 | pointRadius: 4, 53 | pointHitRadius: 10, 54 | data: [], 55 | spanGaps: false, 56 | }, 57 | { 58 | label: '406', 59 | fill: false, 60 | lineTension: 0.1, 61 | borderColor: 'rgb(27,176,117)', 62 | borderCapStyle: 'butt', 63 | borderDash: [], 64 | borderDashOffset: 0.0, 65 | borderJoinStyle: 'miter', 66 | pointBackgroundColor: 'white', 67 | pointBorderWidth: 1, 68 | pointHoverRadius: 8, 69 | pointHoverBackgroundColor: 'brown', 70 | pointHoverBorderColor: 'yellow', 71 | pointHoverBorderWidth: 2, 72 | pointRadius: 4, 73 | pointHitRadius: 10, 74 | data: [], 75 | spanGaps: false, 76 | }, 77 | { 78 | label: '407', 79 | fill: false, 80 | lineTension: 0.1, 81 | borderColor: 'rgb(153,151,153)', 82 | borderCapStyle: 'butt', 83 | borderDash: [], 84 | borderDashOffset: 0.0, 85 | borderJoinStyle: 'miter', 86 | pointBackgroundColor: 'white', 87 | pointBorderWidth: 1, 88 | pointHoverRadius: 8, 89 | pointHoverBackgroundColor: 'brown', 90 | pointHoverBorderColor: 'yellow', 91 | pointHoverBorderWidth: 2, 92 | pointRadius: 4, 93 | pointHitRadius: 10, 94 | data: [], 95 | spanGaps: false, 96 | }, 97 | ], 98 | }, 99 | }; 100 | } 101 | 102 | componentDidMount() { 103 | const socket = io.connect('http://localhost:3333'); 104 | 105 | // Connects 404 Error Consumer 106 | socket.on('404_ERRORS_PER_MIN', (data) => { 107 | // parse incoming data 108 | const message = JSON.parse(data); 109 | 110 | // store the current datasets array in a variable 111 | const currDataSets = this.state.chartData.datasets; 112 | 113 | // create a new data variable, spread current datasets into new array 114 | const updatedDataSets = [...currDataSets]; 115 | 116 | // the time stamp ("WINDOW_START") of the incoming message is already included in the chartData labels, 117 | if (this.state.chartData.labels.includes(message.WINDOW_START) 118 | // and the incoming COUNT is larger or equal to the last element in the data array, 119 | && message.COUNT >= updatedDataSets[0].data[updatedDataSets[0].data.length - 1]) { 120 | // also if the ticks on the x axis (labels) are more than 10, remove the first element(time) in the labels array 121 | if (this.state.chartData.labels.length > 10) { 122 | this.state.chartData.labels.shift(); 123 | } 124 | // pop the last element(count) off the data array 125 | updatedDataSets[0].data.pop(); 126 | // pop the last element(time) off the labels array 127 | this.state.chartData.labels.pop(); 128 | // push the latest count from the incoming message 129 | updatedDataSets[0].data.push(message.COUNT); 130 | 131 | // variable for storing updated version of state 132 | const newChartData = { 133 | ...this.state.chartData, 134 | datasets: [...updatedDataSets], 135 | labels: this.state.chartData.labels.concat( 136 | // concat the new time from WINDOW_START in the incoming message 137 | message.WINDOW_START, 138 | ), 139 | }; 140 | 141 | // set the state of chartData to updated version 142 | this.setState({ chartData: newChartData }); 143 | 144 | // else the window has ended and a new window starts giving us a new time stamp(a new WINDOW_START time) 145 | } else { 146 | // check to see if the labels are currently greater than 10 147 | if (this.state.chartData.labels.length > 10) { 148 | // if true, shift the earliest label(time) 149 | this.state.chartData.labels.shift(); 150 | } 151 | 152 | // push incoming count to data array at index 0 153 | updatedDataSets[0].data.push(message.COUNT); 154 | 155 | // variable for storing updated version of state 156 | const newChartData = { 157 | ...this.state.chartData, 158 | datasets: [...updatedDataSets], 159 | labels: this.state.chartData.labels.concat( 160 | // new Date().toLocaleTimeString() 161 | message.WINDOW_START, 162 | ), 163 | }; 164 | 165 | // set the state with the updated variable 166 | this.setState({ chartData: newChartData }); 167 | } 168 | }); 169 | 170 | // Connects 405 Error Consumer 171 | socket.on('405_ERRORS_PER_MIN', (data) => { 172 | // parse incoming data 173 | const message = JSON.parse(data); 174 | 175 | // store the current datasets array in a variable 176 | const currDataSets = this.state.chartData.datasets; 177 | 178 | // create a new data variable, spread currDataSets array into new array 179 | const updatedDataSets = [...currDataSets]; 180 | 181 | // the time stamp ("WINDOW_START") of the incoming message is already included in the chartData labels, 182 | if (this.state.chartData.labels.includes(message.WINDOW_START) 183 | // and the incoming COUNT is larger or equal to the last element in the data array, 184 | && message.COUNT >= updatedDataSets[1].data[updatedDataSets[1].data.length - 1]) { 185 | // pop the last element(count) off the data array 186 | updatedDataSets[1].data.pop(); 187 | // pop the last element(time) off the labels array 188 | this.state.chartData.labels.pop(); 189 | // push the latest count from the incoming message 190 | updatedDataSets[1].data.push(message.COUNT); 191 | 192 | // variable for storing updated version of state 193 | const newChartData = { 194 | ...this.state.chartData, 195 | datasets: [...updatedDataSets], 196 | }; 197 | 198 | // set the state with the updated variable 199 | this.setState({ chartData: newChartData }); 200 | } else { 201 | // push incoming count to data array at index 1 202 | updatedDataSets[1].data.push(message.COUNT); 203 | 204 | // variable for storing updated version of state 205 | const newChartData = { 206 | ...this.state.chartData, // object 207 | datasets: [...updatedDataSets], // array 208 | }; 209 | 210 | // set the state with the updated variable 211 | this.setState({ chartData: newChartData }); 212 | } 213 | }); 214 | 215 | // Connects 406 Error Consumer 216 | socket.on('406_ERRORS_PER_MIN', (data) => { 217 | // parse incoming data 218 | const message = JSON.parse(data); 219 | 220 | // store the current datasets array in a variable 221 | const currDataSets = this.state.chartData.datasets; 222 | 223 | // create a new data variable, spread currDataSets array into new array 224 | const updatedDataSets = [...currDataSets]; 225 | 226 | // the time stamp ("WINDOW_START") of the incoming message is already included in the chartData labels, 227 | if (this.state.chartData.labels.includes(message.WINDOW_START) 228 | // and the incoming COUNT is larger or equal to the last element in the data array, 229 | && message.COUNT >= updatedDataSets[2].data[updatedDataSets[2].data.length - 1]) { 230 | // pop the last element(count) off the data array 231 | updatedDataSets[2].data.pop(); 232 | // pop the last element(time) off the labels array 233 | this.state.chartData.labels.pop(); 234 | // push the latest count from the incoming message 235 | updatedDataSets[2].data.push(message.COUNT); 236 | console.log(updatedDataSets[2].data); 237 | const newChartData = { 238 | ...this.state.chartData, // object 239 | datasets: [...updatedDataSets], 240 | }; 241 | 242 | // set the state with the updated variable 243 | this.setState({ chartData: newChartData }); 244 | 245 | // else the window has ended and a new window starts giving us a new time stamp(a new WINDOW_START time) 246 | } else { 247 | // push incoming count to data array at index 2 248 | updatedDataSets[2].data.push(message.COUNT); 249 | 250 | // variable for storing updated version of state 251 | const newChartData = { 252 | ...this.state.chartData, 253 | datasets: [...updatedDataSets], 254 | }; 255 | 256 | // set the state with the updated variable 257 | this.setState({ chartData: newChartData }); 258 | } 259 | }); 260 | 261 | // Connects 407 Error Consumer 262 | socket.on('407_ERRORS_PER_MIN', (data) => { 263 | // parse incoming data 264 | const message = JSON.parse(data); 265 | 266 | // store the current datasets array in a variable 267 | const currDataSets = this.state.chartData.datasets; 268 | 269 | // create a new data variable, spread currDataSets array into new array 270 | const updatedDataSets = [...currDataSets]; 271 | 272 | // the time stamp ("WINDOW_START") of the incoming message is already included in the chartData labels, 273 | if (this.state.chartData.labels.includes(message.WINDOW_START) 274 | // and the incoming COUNT is larger or equal to the last element in the data array, 275 | && message.COUNT >= updatedDataSets[3].data[updatedDataSets[3].data.length - 1]) { 276 | // pop the last element(count) off the data array 277 | updatedDataSets[3].data.pop(); 278 | // pop the last element(time) off the labels array 279 | this.state.chartData.labels.pop(); 280 | // push the latest count from the incoming message 281 | updatedDataSets[3].data.push(message.COUNT); 282 | 283 | const newChartData = { 284 | ...this.state.chartData, // object 285 | datasets: [...updatedDataSets], // array 286 | }; 287 | 288 | // set the state with the updated variable 289 | this.setState({ chartData: newChartData }); 290 | 291 | // else the window has ended and a new window starts giving us a new time stamp(a new WINDOW_START time) 292 | } else { 293 | // push incoming count to data array at index 3 294 | updatedDataSets[3].data.push(message.COUNT); 295 | 296 | // variable for storing updated version of state 297 | const newChartData = { 298 | ...this.state.chartData, 299 | datasets: [...updatedDataSets], 300 | }; 301 | 302 | // set the state with the updated variable 303 | this.setState({ chartData: newChartData }); 304 | } 305 | }); 306 | } 307 | 308 | render() { 309 | return ( 310 |
311 |
312 | 313 |
314 |
 
315 |
316 | ); 317 | } 318 | } 319 | 320 | // class Chart extends Component {} 321 | export default LineChart; 322 | -------------------------------------------------------------------------------- /client/components/Nav.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import '../styles/nav.scss'; 3 | import Logo from '../images/kafkaesk-logo.png'; 4 | 5 | const Nav = (props) => ( 6 | 17 | ); 18 | 19 | // class Nav extends Component { 20 | // constructor(props) { 21 | // super(props); 22 | // } 23 | // render() { 24 | // return ( 25 | // 35 | // ); 36 | // } 37 | // } 38 | 39 | export default Nav; 40 | -------------------------------------------------------------------------------- /client/components/PolarChart.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/destructuring-assignment */ 2 | import React from 'react'; 3 | import { Polar } from 'react-chartjs-2'; 4 | import '../styles/mainchart.scss'; 5 | 6 | class PolarChart extends React.Component { 7 | constructor(props) { 8 | super(props); 9 | this.state = { 10 | data: { 11 | labels: ['404', '405', '406', '407'], 12 | datasets: [ 13 | { 14 | label: '404', 15 | backgroundColor: ['#BDD358', '#FFFFFF', '#1BB075', '#999799'], 16 | borderColor: 'transparent', 17 | data: [undefined, undefined, undefined, undefined], 18 | }, 19 | ], 20 | }, 21 | // eslint-disable-next-line react/no-unused-state 22 | options: { 23 | title: { 24 | display: true, 25 | text: '', 26 | }, 27 | }, 28 | }; 29 | } 30 | 31 | componentDidMount() { 32 | const socket = io.connect('http://localhost:3333'); 33 | 34 | // Connects 404 Error Consumer 35 | socket.on('404_ERRORS_PER_MIN', (data) => { 36 | // parse incoming data 37 | const message = JSON.parse(data); 38 | 39 | // store the current datasets array in a variable 40 | const currDataSets = this.state.data.datasets; // array 41 | 42 | // create a new data variable, spread current datasets into new array 43 | const updatedDataSets = [...currDataSets]; 44 | 45 | updatedDataSets[0].data[0] = message.COUNT; 46 | 47 | // variable for storing updated version of state 48 | const newChartData = { 49 | ...this.state.data, 50 | datasets: updatedDataSets[0][data][0], 51 | }; 52 | 53 | // set the state of chartData to updated version 54 | this.setState({ data: newChartData }); 55 | }); 56 | 57 | // Connects 405 Error Consumer 58 | socket.on('405_ERRORS_PER_MIN', (data) => { 59 | // parse incoming data 60 | const message = JSON.parse(data); 61 | 62 | // store the current datasets array in a variable 63 | const currDataSets = this.state.data.datasets; 64 | 65 | // create a new data variable, spread current datasets into new array 66 | const updatedDataSets = [...currDataSets]; 67 | 68 | updatedDataSets[0].data[1] = message.COUNT; 69 | 70 | // variable for storing updated version of state 71 | const newChartData = { 72 | ...this.state.data, 73 | datasets: updatedDataSets[0][data][1], 74 | }; 75 | 76 | // set the state of chartData to updated version 77 | this.setState({ data: newChartData }); 78 | }); 79 | 80 | // Connects 406 Error Consumer 81 | socket.on('406_ERRORS_PER_MIN', (data) => { 82 | // parse incoming data 83 | const message = JSON.parse(data); 84 | 85 | // store the current datasets array in a variable 86 | const currDataSets = this.state.data.datasets; 87 | 88 | // create a new data variable, spread current datasets into new array 89 | const updatedDataSets = [...currDataSets]; 90 | 91 | updatedDataSets[0].data[2] = message.COUNT; 92 | 93 | // variable for storing updated version of state 94 | const newChartData = { 95 | ...this.state.data, 96 | datasets: updatedDataSets[0][data][2], 97 | }; 98 | 99 | // set the state of chartData to updated version 100 | this.setState({ data: newChartData }); 101 | }); 102 | 103 | // Connects 407 Error Consumer 104 | socket.on('407_ERRORS_PER_MIN', (data) => { 105 | // parse incoming data 106 | const message = JSON.parse(data); 107 | 108 | // store the current datasets array in a variable 109 | const currDataSets = this.state.data.datasets; 110 | 111 | // create a new data variable, spread current datasets into new array 112 | const updatedDataSets = [...currDataSets]; 113 | 114 | updatedDataSets[0].data[3] = message.COUNT; 115 | 116 | // variable for storing updated version of state 117 | const newChartData = { 118 | ...this.state.data, 119 | datasets: updatedDataSets[0][data][3], 120 | }; 121 | 122 | // set the state of chartData to updated version 123 | this.setState({ data: newChartData }); 124 | }); 125 | } 126 | 127 | render() { 128 | return ; 129 | } 130 | } 131 | 132 | export default PolarChart; 133 | -------------------------------------------------------------------------------- /client/components/airtable.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import '../styles/airtable.scss'; 3 | import airtablelogo from '../images/airtable-logo.png'; 4 | import DataGenerator from './DataGenerator.jsx'; 5 | // require and create a new instance of airtable connecting to base with an api key 6 | const Airtable = require('airtable'); 7 | 8 | const base = new Airtable({ apiKey: 'keyrj2qx48S8OCScO' }).base( 9 | 'appSgoXde9kcXPb0Q', 10 | ); 11 | 12 | class AirtableIntegration extends Component { 13 | constructor(props) { 14 | super(props); 15 | this.state = { 16 | Name: '', 17 | Priority: '', 18 | Status: 'Assigned', 19 | Description: '', 20 | 'Error Number': '', 21 | 'Assigned to': '', 22 | }; 23 | this.handleChange = this.handleChange.bind(this); 24 | this.handleSubmit = this.handleSubmit.bind(this); 25 | } 26 | 27 | handleChange(event) { 28 | // updates state based on form input values 29 | this.setState({ [event.target.name]: event.target.value }); 30 | } 31 | 32 | handleSubmit(event) { 33 | event.preventDefault(); 34 | // on form submit creates a new record in airtable 35 | base('Bugs and issues').create( 36 | [ 37 | { 38 | fields: this.state, 39 | }, 40 | ], 41 | (err, records) => { 42 | if (err) { 43 | console.error(err); 44 | return; 45 | } 46 | records.forEach((record) => { 47 | console.log(record.getId()); 48 | }); 49 | }, 50 | ); 51 | this.setState({ 52 | Name: '', 53 | Priority: '', 54 | Status: 'Assigned', 55 | Description: '', 56 | 'Error Number': '', 57 | 'Assigned to': '', 58 | }); 59 | } 60 | 61 | render() { 62 | return ( 63 |
64 |
65 |
66 | 67 |

Assign Cleanup/Troubleshooting

68 |
69 | 70 |
71 |
72 | 85 |
86 |
87 | 88 |
89 | 102 |
103 |
104 | 105 |
106 | 119 |
120 |
121 |
122 | 123 | 131 |
132 |
133 | 134 | 142 |
143 |
144 | 147 | 148 |
149 |
 
150 |
151 | 152 |
153 |
154 | ); 155 | } 156 | } 157 | 158 | export default AirtableIntegration; 159 | -------------------------------------------------------------------------------- /client/components/subcharts.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import DoughnutChart from './DoughnutChart.jsx'; 3 | import BarChart from './BarChart.jsx'; 4 | import PolarChart from './PolarChart.jsx'; 5 | import '../styles/subcharts.scss'; 6 | 7 | const SubCharts = (props) => ( 8 |
9 |
10 | 11 |
12 |
 
13 |
14 | 15 |
16 |
 
17 |
18 | 19 |
20 |
21 | ); 22 | 23 | // class SubCharts extends Component { 24 | // constructor(props) { 25 | // super(props); 26 | // } 27 | 28 | // render() { 29 | // return ( 30 | //
31 | //
32 | // 33 | //
34 | //
 
35 | //
36 | // 37 | //
38 | //
 
39 | //
40 | // 41 | //
42 | //
43 | // ); 44 | // } 45 | // } 46 | 47 | export default SubCharts; 48 | -------------------------------------------------------------------------------- /client/components/terminal.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Terminal from 'terminal-in-react'; 3 | import 'terminal-in-react/lib/css/index.css'; 4 | 5 | // currently not working 6 | // can be integrated in the future 7 | 8 | class Terminal extends Component { 9 | showMsg = () => 'Hello World' 10 | 11 | render() { 12 | return ( 13 |
14 | window.open('google.com', '_blank'), 21 | // showmsg: this.showMsg, 22 | // popup: () => alert('Terminal in React') 23 | // }} 24 | // descriptions={{ 25 | // 'open-google': 'opens google.com', 26 | // showmsg: 'shows a message', 27 | // alert: 'alert', popup: 'alert' 28 | // }} 29 | // msg='You can write anything here. Example - Hello! My name is Foo and I like Bar.' 30 | /> 31 |
32 | ); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /client/images/airtable-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/kafkaESK/8873b72b4acaa3dc2495d6bf46f572ddfb166934/client/images/airtable-logo.png -------------------------------------------------------------------------------- /client/images/kafkaESK-demo4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/kafkaESK/8873b72b4acaa3dc2495d6bf46f572ddfb166934/client/images/kafkaESK-demo4.gif -------------------------------------------------------------------------------- /client/images/kafkaesk-logo-readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/kafkaESK/8873b72b4acaa3dc2495d6bf46f572ddfb166934/client/images/kafkaesk-logo-readme.png -------------------------------------------------------------------------------- /client/images/kafkaesk-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/kafkaESK/8873b72b4acaa3dc2495d6bf46f572ddfb166934/client/images/kafkaesk-logo.png -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | KafkaESK 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /client/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM, { render } from 'react-dom'; 3 | import App from './App.jsx'; 4 | 5 | ReactDOM.render(, document.getElementById('root')); 6 | -------------------------------------------------------------------------------- /client/styles/DataGenerator.scss: -------------------------------------------------------------------------------- 1 | h2 { 2 | font-size: 24px; 3 | color: #ffffff; 4 | } 5 | 6 | #command { 7 | width: 99%; 8 | min-height: 100px; 9 | background-color: #ffffff; 10 | overflow: scroll; 11 | } 12 | 13 | // gradient styling for submit button 14 | #submit-command { 15 | margin-top: 15px; 16 | background: #00af78; 17 | background-image: -webkit-linear-gradient(top, #00af78, #039366); 18 | background-image: -moz-linear-gradient(top, #00af78, #039366); 19 | background-image: -ms-linear-gradient(top, #00af78, #039366); 20 | background-image: -o-linear-gradient(top, #00af78, #039366); 21 | background-image: -webkit-gradient(to bottom, #00af78, #039366); 22 | -webkit-border-radius: 5px; 23 | -moz-border-radius: 5px; 24 | border-radius: 5px; 25 | height: 50px; 26 | line-height: 50px; 27 | color: #ffffff; 28 | font-family: Helvetica; 29 | width: 25%; 30 | font-size: 16px; 31 | font-weight: bold; 32 | border: solid #0a966a 1px; 33 | text-decoration: none; 34 | display: inline-block; 35 | cursor: pointer; 36 | text-align: center; 37 | } 38 | 39 | #submit-command:hover { 40 | border: solid #0a966a 1px; 41 | background: #039366; 42 | background-image: -webkit-linear-gradient(top, #039366, #00af78); 43 | background-image: -moz-linear-gradient(top, #039366, #00af78); 44 | background-image: -ms-linear-gradient(top, #039366, #00af78); 45 | background-image: -o-linear-gradient(top, #039366, #00af78); 46 | background-image: -webkit-gradient(to bottom, #039366, #00af78); 47 | -webkit-border-radius: 5px; 48 | -moz-border-radius: 5px; 49 | border-radius: 5px; 50 | text-decoration: none; 51 | } 52 | #end-command { 53 | margin-top: 15px; 54 | background: #af1a00; 55 | background-image: -webkit-linear-gradient(top, #af1a00, #930d03); 56 | background-image: -moz-linear-gradient(top, #af1a00, #930d03); 57 | background-image: -ms-linear-gradient(top, #af1a00, #930d03); 58 | background-image: -o-linear-gradient(top, #af1a00, #930d03); 59 | background-image: -webkit-gradient(to bottom, #af1a00, #930d03); 60 | -webkit-border-radius: 5px; 61 | -moz-border-radius: 5px; 62 | border-radius: 5px; 63 | height: 50px; 64 | line-height: 50px; 65 | color: #ffffff; 66 | font-family: Helvetica; 67 | width: 25%; 68 | font-size: 16px; 69 | font-weight: bold; 70 | border: solid #960a0a 1px; 71 | text-decoration: none; 72 | display: inline-block; 73 | cursor: pointer; 74 | text-align: center; 75 | margin-left: 10px; 76 | } 77 | -------------------------------------------------------------------------------- /client/styles/airtable.scss: -------------------------------------------------------------------------------- 1 | $primary-color-background: #16171b; 2 | $primary-color-background: #16171b; 3 | //styling for outer div element 4 | #airtablediv { 5 | display: grid; 6 | grid-template-columns: 49% 1% 49%; 7 | grid-template-rows: 1fr; 8 | grid-template-areas: ". . . "; 9 | width: 93%; 10 | color: #ffffff; 11 | opacity: 80%; 12 | border-radius: 2px; 13 | margin-left: 1%; 14 | margin-bottom: 20px; 15 | } 16 | // column 1 styling 17 | #airtableform { 18 | justify-content: center; 19 | border-radius: 2px; 20 | color: red; 21 | padding: 15px 15px 15px 15px; 22 | min-height: 300px; 23 | background-color: #202125; 24 | opacity: 80%; 25 | } 26 | // column 2 styling 27 | #filler { 28 | justify-content: center; 29 | border-radius: 2px; 30 | color: red; 31 | padding: 15px 15px 15px 15px; 32 | min-height: 300px; 33 | background-color: #202125; 34 | opacity: 80%; 35 | } 36 | // styling for drop down menu 37 | #myList { 38 | width: 30%; 39 | background-color: $primary-color-background; 40 | } 41 | .select { 42 | position: relative; 43 | display: inline-block; 44 | margin-bottom: 15px; 45 | width: 100%; 46 | } 47 | .select select { 48 | font-family: "Arial"; 49 | display: inline-block; 50 | width: 100%; 51 | cursor: pointer; 52 | padding: 10px 15px; 53 | outline: 0; 54 | border: 0px solid #000000; 55 | border-radius: 5px; 56 | background: #16171b; 57 | color: #d6d6d6; 58 | appearance: none; 59 | -webkit-appearance: none; 60 | -moz-appearance: none; 61 | } 62 | .select select::-ms-expand { 63 | display: none; 64 | } 65 | // assign rollover styling for drop down elements 66 | .select select:hover, 67 | .select select:focus { 68 | color: #fafafa; 69 | background: #3a3a3a; 70 | } 71 | .select select:disabled { 72 | opacity: 0.5; 73 | pointer-events: none; 74 | } 75 | .select_arrow { 76 | position: absolute; 77 | top: 16px; 78 | right: 15px; 79 | pointer-events: none; 80 | border-style: solid; 81 | border-width: 8px 5px 0px 5px; 82 | border-color: #d6d6d6 transparent transparent transparent; 83 | } 84 | .select select:hover ~ .select_arrow, 85 | .select select:focus ~ .select_arrow { 86 | border-top-color: #ffffff; 87 | } 88 | .select select:disabled ~ .select_arrow { 89 | border-top-color: #cccccc; 90 | } 91 | // sizing and styling of input fields 92 | #bugdescription { 93 | width: 99%; 94 | min-height: 50px; 95 | background-color: #ffffff; 96 | } 97 | #bugName { 98 | width: 99%; 99 | min-height: 20px; 100 | background-color: #ffffff; 101 | } 102 | // gradient styling for submit button 103 | .submit-airtable { 104 | background: #00af78; 105 | background-image: -webkit-linear-gradient(top, #00af78, #039366); 106 | background-image: -moz-linear-gradient(top, #00af78, #039366); 107 | background-image: -ms-linear-gradient(top, #00af78, #039366); 108 | background-image: -o-linear-gradient(top, #00af78, #039366); 109 | background-image: -webkit-gradient(to bottom, #00af78, #039366); 110 | -webkit-border-radius: 5px; 111 | -moz-border-radius: 5px; 112 | border-radius: 5px; 113 | height: 50px; 114 | line-height: 50px; 115 | color: #ffffff; 116 | font-family: Helvetica; 117 | width: 25%; 118 | font-size: 16px; 119 | font-weight: bold; 120 | border: solid #0a966a 1px; 121 | text-decoration: none; 122 | display: inline-block; 123 | cursor: pointer; 124 | text-align: center; 125 | } 126 | 127 | .submit-airtable:hover { 128 | border: solid #0a966a 1px; 129 | background: #039366; 130 | background-image: -webkit-linear-gradient(top, #039366, #00af78); 131 | background-image: -moz-linear-gradient(top, #039366, #00af78); 132 | background-image: -ms-linear-gradient(top, #039366, #00af78); 133 | background-image: -o-linear-gradient(top, #039366, #00af78); 134 | background-image: -webkit-gradient(to bottom, #039366, #00af78); 135 | -webkit-border-radius: 5px; 136 | -moz-border-radius: 5px; 137 | border-radius: 5px; 138 | text-decoration: none; 139 | } 140 | // header copy styling 141 | h2 { 142 | font-size: 24px; 143 | color: #ffffff; 144 | } 145 | // grid layout for header copy and error table icon 146 | #form-header { 147 | display: grid; 148 | grid-template-columns: 8% 90%; 149 | grid-template-rows: 1fr; 150 | gap: 0px 0px; 151 | grid-template-areas: ". ."; 152 | } 153 | #airtable-logo { 154 | width: 40px; 155 | padding-top: 10px; 156 | } 157 | // styling for input names 158 | label { 159 | color: #ffffff !important; 160 | font-size: 14px; 161 | line-height: 18px; 162 | } 163 | -------------------------------------------------------------------------------- /client/styles/app.scss: -------------------------------------------------------------------------------- 1 | $font-stack: "Questrial", sans-serif; 2 | $primary-color: #333; 3 | $primary-color-background: #16171b; 4 | 5 | body { 6 | margin: 0; 7 | font-family: $font-stack; 8 | color: $primary-color; 9 | background-color: $primary-color-background; 10 | } 11 | 12 | #container { 13 | display: flex; 14 | justify-content: center; 15 | padding-top: 20px; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /client/styles/lineChart.scss: -------------------------------------------------------------------------------- 1 | // styling for the main line graph display 2 | #mainchart { 3 | display: grid; 4 | grid-template-columns: 98% 0% 0%; 5 | grid-template-rows: 1fr; 6 | gap: 10px 10px; 7 | grid-template-areas: ". . . "; 8 | width: 90%; 9 | color: #ffffff; 10 | background-color: #202125; 11 | opacity: 80%; 12 | border-radius: 2px; 13 | padding: 15px 15px 15px 15px; 14 | } 15 | // 16 | #log { 17 | margin-top: 20px; 18 | margin-bottom: 20px; 19 | justify-content: center; 20 | border-radius: 2px; 21 | color: red; 22 | padding: 15px 15px 15px 15px; 23 | background-color: #ffffff; 24 | overflow: scroll; 25 | } 26 | -------------------------------------------------------------------------------- /client/styles/mainchart.scss: -------------------------------------------------------------------------------- 1 | // styling for the main line graph display 2 | #mainchart { 3 | display: grid; 4 | grid-template-columns: 98% 0% 0%; 5 | grid-template-rows: 1fr; 6 | gap: 10px 10px; 7 | grid-template-areas: ". . . "; 8 | width: 90%; 9 | color: #ffffff; 10 | background-color: #202125; 11 | opacity: 80%; 12 | border-radius: 2px; 13 | padding: 15px 15px 15px 15px; 14 | } 15 | 16 | #log { 17 | margin-top: 20px; 18 | margin-bottom: 20px; 19 | justify-content: center; 20 | border-radius: 2px; 21 | color: red; 22 | padding: 15px 15px 15px 15px; 23 | background-color: #ffffff; 24 | overflow: scroll; 25 | } 26 | -------------------------------------------------------------------------------- /client/styles/nav.scss: -------------------------------------------------------------------------------- 1 | $primary-color-font: #6e6e6e; 2 | // styling for nav bar elements 3 | nav { 4 | display: grid; 5 | grid-template-columns: min-content 1fr min-content min-content min-content; 6 | grid-template-rows: 1fr; 7 | gap: 10px 10px; 8 | grid-template-areas: ". . . . ."; 9 | width: 90%; 10 | color: $primary-color-font; 11 | border-radius: 2px; 12 | align-items: center; 13 | } 14 | -------------------------------------------------------------------------------- /client/styles/subcharts.scss: -------------------------------------------------------------------------------- 1 | // styling for outer grid containg all the secondary charts 2 | #subcharts { 3 | display: grid; 4 | grid-template-columns: 32.3% 1% 32.3% 1% 32.3%; 5 | grid-template-rows: 1fr; 6 | grid-template-areas: ". . . . . "; 7 | width: 93%; 8 | color: #ffffff; 9 | opacity: 80%; 10 | border-radius: 2px; 11 | margin-left: 1%; 12 | } 13 | // styling for div containing doughnut chart 14 | #chart1 { 15 | justify-content: center; 16 | border-radius: 2px; 17 | color: red; 18 | padding: 15px 15px 15px 15px; 19 | height: 300px; 20 | background-color: #202125; 21 | opacity: 80%; 22 | } 23 | // styling for div containing bar graph 24 | #chart2 { 25 | justify-content: center; 26 | border-radius: 2px; 27 | color: red; 28 | padding: 15px 15px 15px 15px; 29 | height: 300px; 30 | background-color: #202125; 31 | opacity: 80%; 32 | } 33 | // styling for div contaning radar chart 34 | #chart3 { 35 | justify-content: center; 36 | border-radius: 2px; 37 | color: red; 38 | padding: 15px 15px 15px 15px; 39 | height: 300px; 40 | background-color: #202125; 41 | opacity: 80%; 42 | } 43 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | KafkaESK 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kafkaESK", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": ".index.js", 6 | "babel": { 7 | "presets": [ 8 | "@babel/preset-env", 9 | "@babel/preset-react" 10 | ] 11 | }, 12 | "scripts": { 13 | "test": "jest --verbose", 14 | "start": "nodemon ./server/server.js & webpack-dev-server --open --hot --host 0.0.0.0", 15 | "create": "webpack --config ./webpack.config.js" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/chelseaharris137/kafkaESK.git" 20 | }, 21 | "keywords": [], 22 | "author": "", 23 | "license": "ISC", 24 | "bugs": { 25 | "url": "https://github.com/chelseaharris137/kafkaESK/issues" 26 | }, 27 | "homepage": "https://github.com/chelseaharris137/kafkaESK#readme", 28 | "jest": { 29 | "moduleNameMapper": { 30 | "^.+\\.(css|less|scss)$": "babel-jest" 31 | } 32 | }, 33 | "dependencies": { 34 | "airtable": "^0.10.1", 35 | "chart.js": "^2.9.4", 36 | "cors": "^2.8.5", 37 | "enzyme": "^3.11.0", 38 | "enzyme-adapter-react-16": "^1.15.5", 39 | "enzyme-to-json": "^3.6.1", 40 | "express": "^4.17.1", 41 | "jest": "^26.6.3", 42 | "kafkajs": "^1.15.0", 43 | "kafkajs-snappy": "^1.1.0", 44 | "morgan": "^1.10.0", 45 | "node-sass": "^5.0.0", 46 | "react": "^16.14.0", 47 | "react-chartjs-2": "^2.11.1", 48 | "react-dom": "^16.14.0", 49 | "socket.io": "^3.0.4" 50 | }, 51 | "devDependencies": { 52 | "@babel/core": "^7.12.10", 53 | "@babel/preset-env": "^7.12.10", 54 | "@babel/preset-react": "^7.12.10", 55 | "babel-jest": "^26.6.3", 56 | "babel-loader": "^8.2.2", 57 | "css-loader": "^5.0.1", 58 | "eslint": "^7.17.0", 59 | "eslint-config-airbnb": "^18.2.1", 60 | "eslint-plugin-import": "^2.22.1", 61 | "eslint-plugin-jsx-a11y": "^6.4.1", 62 | "eslint-plugin-react": "^7.22.0", 63 | "eslint-plugin-react-hooks": "^4.2.0", 64 | "html-webpack-plugin": "^4.5.0", 65 | "nodemon": "^2.0.6", 66 | "sass": "^1.30.0", 67 | "sass-loader": "^10.1.0", 68 | "style-loader": "^2.0.0", 69 | "url-loader": "^4.1.1", 70 | "webpack": "^4.43.0", 71 | "webpack-cli": "^3.3.12", 72 | "webpack-dev-server": "^3.11.0" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /server/cmd/consumer.sh: -------------------------------------------------------------------------------- 1 | kafka-console-consumer --bootstrap-server localhost:9092 --topic CLICKSTREAM_CODES --from-beginning 2 | -------------------------------------------------------------------------------- /server/cmd/ksql/error_data.json: -------------------------------------------------------------------------------- 1 | {"code":404,"definition":"Page not found"} 2 | {"code":404,"definition":"Page not found"} 3 | {"code":406,"definition":"Not acceptable"} 4 | {"code":406,"definition":"Not acceptable"} 5 | {"code":405,"definition":"Method not allowed"} 6 | {"code":405,"definition":"Method not allowed"} 7 | {"code":404,"definition":"Page not found"} 8 | {"code":406,"definition":"Not acceptable"} 9 | {"code":407,"definition":"Proxy authentication required"} 10 | {"code":405,"definition":"Method not allowed"} 11 | {"code":404,"definition":"Page not found"} 12 | {"code":404,"definition":"Page not found"} 13 | {"code":407,"definition":"Proxy authentication required"} 14 | {"code":407,"definition":"Proxy authentication required"} 15 | {"code":404,"definition":"Page not found"} 16 | {"code":405,"definition":"Method not allowed"} 17 | {"code":407,"definition":"Proxy authentication required"} 18 | {"code":407,"definition":"Proxy authentication required"} 19 | {"code":405,"definition":"Method not allowed"} 20 | {"code":406,"definition":"Not acceptable"} 21 | {"code":405,"definition":"Method not allowed"} 22 | {"code":406,"definition":"Not acceptable"} 23 | {"code":404,"definition":"Page not found"} 24 | {"code":407,"definition":"Proxy authentication required"} 25 | {"code":406,"definition":"Not acceptable"} 26 | {"code":406,"definition":"Not acceptable"} 27 | {"code":406,"definition":"Not acceptable"} 28 | {"code":407,"definition":"Proxy authentication required"} 29 | {"code":407,"definition":"Proxy authentication required"} 30 | {"code":405,"definition":"Method not allowed"} 31 | {"code":405,"definition":"Method not allowed"} 32 | {"code":407,"definition":"Proxy authentication required"} 33 | {"code":404,"definition":"Page not found"} 34 | {"code":406,"definition":"Not acceptable"} 35 | {"code":406,"definition":"Not acceptable"} 36 | {"code":407,"definition":"Proxy authentication required"} 37 | {"code":404,"definition":"Page not found"} 38 | {"code":405,"definition":"Method not allowed"} 39 | {"code":405,"definition":"Method not allowed"} 40 | {"code":404,"definition":"Page not found"} 41 | {"code":406,"definition":"Not acceptable"} 42 | {"code":407,"definition":"Proxy authentication required"} 43 | {"code":407,"definition":"Proxy authentication required"} 44 | {"code":407,"definition":"Proxy authentication required"} 45 | {"code":406,"definition":"Not acceptable"} 46 | {"code":404,"definition":"Page not found"} 47 | {"code":407,"definition":"Proxy authentication required"} 48 | {"code":407,"definition":"Proxy authentication required"} 49 | {"code":407,"definition":"Proxy authentication required"} 50 | {"code":406,"definition":"Not acceptable"} 51 | {"code":406,"definition":"Not acceptable"} 52 | {"code":405,"definition":"Method not allowed"} 53 | {"code":407,"definition":"Proxy authentication required"} 54 | {"code":407,"definition":"Proxy authentication required"} 55 | {"code":405,"definition":"Method not allowed"} 56 | {"code":406,"definition":"Not acceptable"} 57 | {"code":404,"definition":"Page not found"} 58 | {"code":404,"definition":"Page not found"} 59 | {"code":405,"definition":"Method not allowed"} 60 | {"code":406,"definition":"Not acceptable"} 61 | {"code":405,"definition":"Method not allowed"} 62 | {"code":407,"definition":"Proxy authentication required"} 63 | {"code":407,"definition":"Proxy authentication required"} 64 | {"code":407,"definition":"Proxy authentication required"} 65 | {"code":404,"definition":"Page not found"} 66 | {"code":407,"definition":"Proxy authentication required"} 67 | {"code":406,"definition":"Not acceptable"} 68 | {"code":404,"definition":"Page not found"} 69 | {"code":405,"definition":"Method not allowed"} 70 | {"code":407,"definition":"Proxy authentication required"} 71 | {"code":405,"definition":"Method not allowed"} 72 | {"code":405,"definition":"Method not allowed"} 73 | {"code":404,"definition":"Page not found"} 74 | {"code":407,"definition":"Proxy authentication required"} 75 | {"code":406,"definition":"Not acceptable"} 76 | {"code":406,"definition":"Not acceptable"} 77 | {"code":406,"definition":"Not acceptable"} 78 | {"code":407,"definition":"Proxy authentication required"} 79 | {"code":405,"definition":"Method not allowed"} 80 | {"code":405,"definition":"Method not allowed"} 81 | {"code":406,"definition":"Not acceptable"} 82 | {"code":405,"definition":"Method not allowed"} 83 | {"code":406,"definition":"Not acceptable"} 84 | {"code":407,"definition":"Proxy authentication required"} 85 | {"code":404,"definition":"Page not found"} 86 | {"code":405,"definition":"Method not allowed"} 87 | {"code":407,"definition":"Proxy authentication required"} 88 | {"code":404,"definition":"Page not found"} 89 | {"code":407,"definition":"Proxy authentication required"} 90 | {"code":404,"definition":"Page not found"} 91 | {"code":405,"definition":"Method not allowed"} 92 | {"code":405,"definition":"Method not allowed"} 93 | {"code":407,"definition":"Proxy authentication required"} 94 | {"code":406,"definition":"Not acceptable"} 95 | {"code":405,"definition":"Method not allowed"} 96 | {"code":407,"definition":"Proxy authentication required"} 97 | {"code":406,"definition":"Not acceptable"} 98 | {"code":406,"definition":"Not acceptable"} 99 | {"code":407,"definition":"Proxy authentication required"} 100 | {"code":405,"definition":"Method not allowed"} 101 | {"code":407,"definition":"Proxy authentication required"} 102 | {"code":407,"definition":"Proxy authentication required"} 103 | {"code":407,"definition":"Proxy authentication required"} 104 | {"code":407,"definition":"Proxy authentication required"} 105 | {"code":406,"definition":"Not acceptable"} 106 | {"code":405,"definition":"Method not allowed"} 107 | {"code":407,"definition":"Proxy authentication required"} 108 | {"code":407,"definition":"Proxy authentication required"} 109 | {"code":406,"definition":"Not acceptable"} 110 | {"code":404,"definition":"Page not found"} 111 | {"code":405,"definition":"Method not allowed"} 112 | {"code":406,"definition":"Not acceptable"} 113 | {"code":405,"definition":"Method not allowed"} 114 | {"code":406,"definition":"Not acceptable"} 115 | {"code":406,"definition":"Not acceptable"} 116 | {"code":406,"definition":"Not acceptable"} 117 | {"code":404,"definition":"Page not found"} 118 | {"code":405,"definition":"Method not allowed"} 119 | {"code":405,"definition":"Method not allowed"} 120 | {"code":406,"definition":"Not acceptable"} 121 | {"code":404,"definition":"Page not found"} 122 | {"code":407,"definition":"Proxy authentication required"} 123 | {"code":406,"definition":"Not acceptable"} 124 | {"code":407,"definition":"Proxy authentication required"} 125 | {"code":406,"definition":"Not acceptable"} 126 | {"code":406,"definition":"Not acceptable"} 127 | {"code":407,"definition":"Proxy authentication required"} 128 | {"code":405,"definition":"Method not allowed"} 129 | {"code":407,"definition":"Proxy authentication required"} 130 | {"code":406,"definition":"Not acceptable"} 131 | {"code":404,"definition":"Page not found"} 132 | {"code":407,"definition":"Proxy authentication required"} 133 | {"code":405,"definition":"Method not allowed"} 134 | {"code":406,"definition":"Not acceptable"} 135 | {"code":406,"definition":"Not acceptable"} 136 | {"code":407,"definition":"Proxy authentication required"} 137 | {"code":405,"definition":"Method not allowed"} 138 | {"code":404,"definition":"Page not found"} 139 | {"code":406,"definition":"Not acceptable"} 140 | {"code":405,"definition":"Method not allowed"} 141 | {"code":406,"definition":"Not acceptable"} 142 | {"code":405,"definition":"Method not allowed"} 143 | {"code":406,"definition":"Not acceptable"} 144 | {"code":404,"definition":"Page not found"} 145 | {"code":404,"definition":"Page not found"} 146 | {"code":406,"definition":"Not acceptable"} 147 | {"code":405,"definition":"Method not allowed"} 148 | {"code":407,"definition":"Proxy authentication required"} 149 | {"code":406,"definition":"Not acceptable"} 150 | {"code":405,"definition":"Method not allowed"} 151 | {"code":405,"definition":"Method not allowed"} 152 | {"code":404,"definition":"Page not found"} 153 | {"code":404,"definition":"Page not found"} 154 | {"code":405,"definition":"Method not allowed"} 155 | {"code":405,"definition":"Method not allowed"} 156 | {"code":405,"definition":"Method not allowed"} 157 | {"code":404,"definition":"Page not found"} 158 | {"code":405,"definition":"Method not allowed"} 159 | {"code":407,"definition":"Proxy authentication required"} 160 | {"code":404,"definition":"Page not found"} 161 | {"code":405,"definition":"Method not allowed"} 162 | {"code":404,"definition":"Page not found"} 163 | {"code":405,"definition":"Method not allowed"} 164 | {"code":405,"definition":"Method not allowed"} 165 | {"code":405,"definition":"Method not allowed"} 166 | {"code":405,"definition":"Method not allowed"} 167 | {"code":407,"definition":"Proxy authentication required"} 168 | {"code":407,"definition":"Proxy authentication required"} 169 | {"code":404,"definition":"Page not found"} 170 | {"code":407,"definition":"Proxy authentication required"} 171 | {"code":406,"definition":"Not acceptable"} 172 | {"code":405,"definition":"Method not allowed"} 173 | {"code":404,"definition":"Page not found"} 174 | {"code":405,"definition":"Method not allowed"} 175 | {"code":404,"definition":"Page not found"} 176 | {"code":404,"definition":"Page not found"} 177 | {"code":404,"definition":"Page not found"} 178 | {"code":405,"definition":"Method not allowed"} 179 | {"code":407,"definition":"Proxy authentication required"} 180 | {"code":407,"definition":"Proxy authentication required"} 181 | {"code":407,"definition":"Proxy authentication required"} 182 | {"code":404,"definition":"Page not found"} 183 | {"code":405,"definition":"Method not allowed"} 184 | {"code":405,"definition":"Method not allowed"} 185 | {"code":407,"definition":"Proxy authentication required"} 186 | {"code":407,"definition":"Proxy authentication required"} 187 | {"code":406,"definition":"Not acceptable"} 188 | {"code":405,"definition":"Method not allowed"} 189 | {"code":406,"definition":"Not acceptable"} 190 | {"code":407,"definition":"Proxy authentication required"} 191 | {"code":405,"definition":"Method not allowed"} 192 | {"code":405,"definition":"Method not allowed"} 193 | {"code":406,"definition":"Not acceptable"} 194 | {"code":404,"definition":"Page not found"} 195 | {"code":407,"definition":"Proxy authentication required"} 196 | {"code":405,"definition":"Method not allowed"} 197 | {"code":407,"definition":"Proxy authentication required"} 198 | {"code":407,"definition":"Proxy authentication required"} 199 | {"code":407,"definition":"Proxy authentication required"} 200 | {"code":405,"definition":"Method not allowed"} 201 | {"code":404,"definition":"Page not found"} 202 | {"code":404,"definition":"Page not found"} 203 | {"code":404,"definition":"Page not found"} 204 | {"code":404,"definition":"Page not found"} 205 | {"code":405,"definition":"Method not allowed"} 206 | {"code":407,"definition":"Proxy authentication required"} 207 | {"code":407,"definition":"Proxy authentication required"} 208 | {"code":406,"definition":"Not acceptable"} 209 | {"code":405,"definition":"Method not allowed"} 210 | {"code":407,"definition":"Proxy authentication required"} 211 | {"code":405,"definition":"Method not allowed"} 212 | {"code":405,"definition":"Method not allowed"} 213 | {"code":405,"definition":"Method not allowed"} 214 | {"code":404,"definition":"Page not found"} 215 | {"code":405,"definition":"Method not allowed"} 216 | {"code":404,"definition":"Page not found"} 217 | {"code":404,"definition":"Page not found"} 218 | {"code":405,"definition":"Method not allowed"} 219 | {"code":405,"definition":"Method not allowed"} 220 | {"code":406,"definition":"Not acceptable"} 221 | {"code":405,"definition":"Method not allowed"} 222 | {"code":406,"definition":"Not acceptable"} 223 | {"code":407,"definition":"Proxy authentication required"} 224 | {"code":407,"definition":"Proxy authentication required"} 225 | {"code":405,"definition":"Method not allowed"} 226 | {"code":404,"definition":"Page not found"} 227 | {"code":407,"definition":"Proxy authentication required"} 228 | {"code":407,"definition":"Proxy authentication required"} 229 | {"code":407,"definition":"Proxy authentication required"} 230 | {"code":406,"definition":"Not acceptable"} 231 | {"code":404,"definition":"Page not found"} 232 | {"code":405,"definition":"Method not allowed"} 233 | {"code":406,"definition":"Not acceptable"} 234 | {"code":404,"definition":"Page not found"} 235 | {"code":404,"definition":"Page not found"} 236 | {"code":404,"definition":"Page not found"} 237 | {"code":406,"definition":"Not acceptable"} 238 | {"code":406,"definition":"Not acceptable"} 239 | {"code":407,"definition":"Proxy authentication required"} 240 | {"code":406,"definition":"Not acceptable"} 241 | {"code":405,"definition":"Method not allowed"} 242 | {"code":407,"definition":"Proxy authentication required"} 243 | {"code":404,"definition":"Page not found"} 244 | {"code":405,"definition":"Method not allowed"} 245 | {"code":407,"definition":"Proxy authentication required"} 246 | {"code":405,"definition":"Method not allowed"} 247 | {"code":404,"definition":"Page not found"} 248 | {"code":405,"definition":"Method not allowed"} 249 | {"code":407,"definition":"Proxy authentication required"} 250 | {"code":406,"definition":"Not acceptable"} 251 | {"code":404,"definition":"Page not found"} 252 | {"code":407,"definition":"Proxy authentication required"} 253 | {"code":405,"definition":"Method not allowed"} 254 | {"code":406,"definition":"Not acceptable"} 255 | {"code":406,"definition":"Not acceptable"} 256 | {"code":406,"definition":"Not acceptable"} 257 | {"code":406,"definition":"Not acceptable"} 258 | {"code":406,"definition":"Not acceptable"} 259 | {"code":406,"definition":"Not acceptable"} 260 | {"code":407,"definition":"Proxy authentication required"} 261 | {"code":406,"definition":"Not acceptable"} 262 | {"code":406,"definition":"Not acceptable"} 263 | {"code":405,"definition":"Method not allowed"} 264 | {"code":407,"definition":"Proxy authentication required"} 265 | {"code":407,"definition":"Proxy authentication required"} 266 | {"code":407,"definition":"Proxy authentication required"} 267 | {"code":407,"definition":"Proxy authentication required"} 268 | {"code":407,"definition":"Proxy authentication required"} 269 | {"code":404,"definition":"Page not found"} 270 | {"code":405,"definition":"Method not allowed"} 271 | {"code":404,"definition":"Page not found"} 272 | {"code":406,"definition":"Not acceptable"} 273 | {"code":407,"definition":"Proxy authentication required"} 274 | {"code":407,"definition":"Proxy authentication required"} 275 | {"code":407,"definition":"Proxy authentication required"} 276 | {"code":404,"definition":"Page not found"} 277 | {"code":405,"definition":"Method not allowed"} 278 | {"code":404,"definition":"Page not found"} 279 | {"code":406,"definition":"Not acceptable"} 280 | {"code":407,"definition":"Proxy authentication required"} 281 | {"code":407,"definition":"Proxy authentication required"} 282 | {"code":405,"definition":"Method not allowed"} 283 | {"code":406,"definition":"Not acceptable"} 284 | {"code":407,"definition":"Proxy authentication required"} 285 | {"code":407,"definition":"Proxy authentication required"} 286 | {"code":407,"definition":"Proxy authentication required"} 287 | {"code":404,"definition":"Page not found"} 288 | {"code":407,"definition":"Proxy authentication required"} 289 | {"code":406,"definition":"Not acceptable"} 290 | {"code":407,"definition":"Proxy authentication required"} 291 | {"code":405,"definition":"Method not allowed"} 292 | {"code":407,"definition":"Proxy authentication required"} 293 | {"code":404,"definition":"Page not found"} 294 | {"code":407,"definition":"Proxy authentication required"} 295 | {"code":406,"definition":"Not acceptable"} 296 | {"code":404,"definition":"Page not found"} 297 | {"code":405,"definition":"Method not allowed"} 298 | {"code":406,"definition":"Not acceptable"} 299 | {"code":406,"definition":"Not acceptable"} 300 | {"code":405,"definition":"Method not allowed"} 301 | {"code":406,"definition":"Not acceptable"} 302 | {"code":407,"definition":"Proxy authentication required"} 303 | {"code":405,"definition":"Method not allowed"} 304 | {"code":404,"definition":"Page not found"} 305 | {"code":407,"definition":"Proxy authentication required"} 306 | {"code":404,"definition":"Page not found"} 307 | {"code":404,"definition":"Page not found"} 308 | {"code":407,"definition":"Proxy authentication required"} 309 | {"code":405,"definition":"Method not allowed"} 310 | {"code":405,"definition":"Method not allowed"} 311 | {"code":407,"definition":"Proxy authentication required"} 312 | {"code":404,"definition":"Page not found"} 313 | {"code":406,"definition":"Not acceptable"} 314 | {"code":404,"definition":"Page not found"} 315 | {"code":407,"definition":"Proxy authentication required"} 316 | {"code":405,"definition":"Method not allowed"} 317 | {"code":405,"definition":"Method not allowed"} 318 | {"code":404,"definition":"Page not found"} 319 | {"code":404,"definition":"Page not found"} 320 | {"code":405,"definition":"Method not allowed"} 321 | {"code":404,"definition":"Page not found"} 322 | {"code":406,"definition":"Not acceptable"} 323 | {"code":407,"definition":"Proxy authentication required"} 324 | {"code":407,"definition":"Proxy authentication required"} 325 | {"code":407,"definition":"Proxy authentication required"} 326 | {"code":404,"definition":"Page not found"} 327 | {"code":404,"definition":"Page not found"} 328 | {"code":404,"definition":"Page not found"} 329 | {"code":407,"definition":"Proxy authentication required"} 330 | {"code":407,"definition":"Proxy authentication required"} 331 | {"code":407,"definition":"Proxy authentication required"} 332 | {"code":404,"definition":"Page not found"} 333 | {"code":405,"definition":"Method not allowed"} 334 | {"code":405,"definition":"Method not allowed"} 335 | {"code":407,"definition":"Proxy authentication required"} 336 | {"code":405,"definition":"Method not allowed"} 337 | {"code":405,"definition":"Method not allowed"} 338 | {"code":404,"definition":"Page not found"} 339 | {"code":405,"definition":"Method not allowed"} 340 | {"code":406,"definition":"Not acceptable"} 341 | {"code":407,"definition":"Proxy authentication required"} 342 | {"code":405,"definition":"Method not allowed"} 343 | {"code":406,"definition":"Not acceptable"} 344 | {"code":407,"definition":"Proxy authentication required"} 345 | {"code":407,"definition":"Proxy authentication required"} 346 | {"code":407,"definition":"Proxy authentication required"} 347 | {"code":404,"definition":"Page not found"} 348 | {"code":404,"definition":"Page not found"} 349 | {"code":405,"definition":"Method not allowed"} 350 | {"code":404,"definition":"Page not found"} 351 | {"code":405,"definition":"Method not allowed"} 352 | {"code":407,"definition":"Proxy authentication required"} 353 | {"code":406,"definition":"Not acceptable"} 354 | {"code":407,"definition":"Proxy authentication required"} 355 | {"code":407,"definition":"Proxy authentication required"} 356 | {"code":404,"definition":"Page not found"} 357 | {"code":406,"definition":"Not acceptable"} 358 | {"code":404,"definition":"Page not found"} 359 | {"code":407,"definition":"Proxy authentication required"} 360 | {"code":406,"definition":"Not acceptable"} 361 | {"code":405,"definition":"Method not allowed"} 362 | {"code":406,"definition":"Not acceptable"} 363 | {"code":404,"definition":"Page not found"} 364 | {"code":406,"definition":"Not acceptable"} 365 | {"code":406,"definition":"Not acceptable"} 366 | {"code":404,"definition":"Page not found"} 367 | {"code":405,"definition":"Method not allowed"} 368 | {"code":407,"definition":"Proxy authentication required"} 369 | {"code":406,"definition":"Not acceptable"} 370 | {"code":406,"definition":"Not acceptable"} 371 | {"code":404,"definition":"Page not found"} 372 | {"code":406,"definition":"Not acceptable"} 373 | {"code":405,"definition":"Method not allowed"} 374 | {"code":407,"definition":"Proxy authentication required"} 375 | {"code":406,"definition":"Not acceptable"} 376 | {"code":405,"definition":"Method not allowed"} 377 | {"code":407,"definition":"Proxy authentication required"} 378 | {"code":405,"definition":"Method not allowed"} 379 | {"code":407,"definition":"Proxy authentication required"} 380 | {"code":404,"definition":"Page not found"} 381 | {"code":407,"definition":"Proxy authentication required"} 382 | {"code":407,"definition":"Proxy authentication required"} 383 | {"code":404,"definition":"Page not found"} 384 | {"code":404,"definition":"Page not found"} 385 | {"code":406,"definition":"Not acceptable"} 386 | {"code":407,"definition":"Proxy authentication required"} 387 | {"code":407,"definition":"Proxy authentication required"} 388 | {"code":407,"definition":"Proxy authentication required"} 389 | {"code":404,"definition":"Page not found"} 390 | {"code":406,"definition":"Not acceptable"} 391 | {"code":406,"definition":"Not acceptable"} 392 | {"code":406,"definition":"Not acceptable"} 393 | {"code":405,"definition":"Method not allowed"} 394 | {"code":406,"definition":"Not acceptable"} 395 | {"code":405,"definition":"Method not allowed"} 396 | {"code":406,"definition":"Not acceptable"} 397 | {"code":404,"definition":"Page not found"} 398 | {"code":406,"definition":"Not acceptable"} 399 | {"code":405,"definition":"Method not allowed"} 400 | {"code":407,"definition":"Proxy authentication required"} 401 | {"code":406,"definition":"Not acceptable"} 402 | {"code":406,"definition":"Not acceptable"} 403 | {"code":404,"definition":"Page not found"} 404 | {"code":405,"definition":"Method not allowed"} 405 | {"code":406,"definition":"Not acceptable"} 406 | {"code":407,"definition":"Proxy authentication required"} 407 | {"code":405,"definition":"Method not allowed"} 408 | {"code":404,"definition":"Page not found"} 409 | {"code":404,"definition":"Page not found"} 410 | {"code":405,"definition":"Method not allowed"} 411 | {"code":405,"definition":"Method not allowed"} 412 | {"code":406,"definition":"Not acceptable"} 413 | {"code":405,"definition":"Method not allowed"} 414 | {"code":407,"definition":"Proxy authentication required"} 415 | {"code":404,"definition":"Page not found"} 416 | {"code":405,"definition":"Method not allowed"} 417 | {"code":405,"definition":"Method not allowed"} 418 | {"code":405,"definition":"Method not allowed"} 419 | {"code":407,"definition":"Proxy authentication required"} 420 | {"code":405,"definition":"Method not allowed"} 421 | {"code":406,"definition":"Not acceptable"} 422 | {"code":404,"definition":"Page not found"} 423 | {"code":404,"definition":"Page not found"} 424 | {"code":406,"definition":"Not acceptable"} 425 | {"code":404,"definition":"Page not found"} 426 | {"code":406,"definition":"Not acceptable"} 427 | {"code":405,"definition":"Method not allowed"} 428 | {"code":405,"definition":"Method not allowed"} 429 | {"code":406,"definition":"Not acceptable"} 430 | {"code":404,"definition":"Page not found"} 431 | {"code":405,"definition":"Method not allowed"} 432 | {"code":404,"definition":"Page not found"} 433 | {"code":407,"definition":"Proxy authentication required"} 434 | {"code":405,"definition":"Method not allowed"} 435 | {"code":405,"definition":"Method not allowed"} 436 | {"code":406,"definition":"Not acceptable"} 437 | {"code":404,"definition":"Page not found"} 438 | {"code":406,"definition":"Not acceptable"} 439 | {"code":407,"definition":"Proxy authentication required"} 440 | {"code":406,"definition":"Not acceptable"} 441 | {"code":404,"definition":"Page not found"} 442 | {"code":405,"definition":"Method not allowed"} 443 | {"code":407,"definition":"Proxy authentication required"} 444 | {"code":404,"definition":"Page not found"} 445 | {"code":404,"definition":"Page not found"} 446 | {"code":407,"definition":"Proxy authentication required"} 447 | {"code":404,"definition":"Page not found"} 448 | {"code":407,"definition":"Proxy authentication required"} 449 | {"code":405,"definition":"Method not allowed"} 450 | {"code":404,"definition":"Page not found"} 451 | {"code":405,"definition":"Method not allowed"} 452 | {"code":406,"definition":"Not acceptable"} 453 | {"code":406,"definition":"Not acceptable"} 454 | {"code":405,"definition":"Method not allowed"} 455 | {"code":406,"definition":"Not acceptable"} 456 | {"code":407,"definition":"Proxy authentication required"} 457 | {"code":407,"definition":"Proxy authentication required"} 458 | {"code":404,"definition":"Page not found"} 459 | {"code":405,"definition":"Method not allowed"} 460 | {"code":407,"definition":"Proxy authentication required"} 461 | {"code":407,"definition":"Proxy authentication required"} 462 | {"code":407,"definition":"Proxy authentication required"} 463 | {"code":404,"definition":"Page not found"} 464 | {"code":407,"definition":"Proxy authentication required"} 465 | {"code":404,"definition":"Page not found"} 466 | {"code":406,"definition":"Not acceptable"} 467 | {"code":406,"definition":"Not acceptable"} 468 | {"code":407,"definition":"Proxy authentication required"} 469 | {"code":404,"definition":"Page not found"} 470 | {"code":407,"definition":"Proxy authentication required"} 471 | {"code":406,"definition":"Not acceptable"} 472 | {"code":407,"definition":"Proxy authentication required"} 473 | {"code":406,"definition":"Not acceptable"} 474 | {"code":404,"definition":"Page not found"} 475 | {"code":404,"definition":"Page not found"} 476 | {"code":405,"definition":"Method not allowed"} 477 | {"code":404,"definition":"Page not found"} 478 | {"code":404,"definition":"Page not found"} 479 | {"code":405,"definition":"Method not allowed"} 480 | {"code":404,"definition":"Page not found"} 481 | {"code":404,"definition":"Page not found"} 482 | {"code":404,"definition":"Page not found"} 483 | {"code":404,"definition":"Page not found"} 484 | {"code":407,"definition":"Proxy authentication required"} 485 | {"code":404,"definition":"Page not found"} 486 | {"code":404,"definition":"Page not found"} 487 | {"code":407,"definition":"Proxy authentication required"} 488 | {"code":404,"definition":"Page not found"} 489 | {"code":407,"definition":"Proxy authentication required"} 490 | {"code":407,"definition":"Proxy authentication required"} 491 | {"code":404,"definition":"Page not found"} 492 | {"code":405,"definition":"Method not allowed"} 493 | {"code":405,"definition":"Method not allowed"} 494 | {"code":404,"definition":"Page not found"} 495 | {"code":405,"definition":"Method not allowed"} 496 | {"code":404,"definition":"Page not found"} 497 | {"code":406,"definition":"Not acceptable"} 498 | {"code":406,"definition":"Not acceptable"} 499 | {"code":405,"definition":"Method not allowed"} 500 | {"code":405,"definition":"Method not allowed"} 501 | {"code":406,"definition":"Not acceptable"} 502 | {"code":405,"definition":"Method not allowed"} 503 | {"code":407,"definition":"Proxy authentication required"} 504 | {"code":405,"definition":"Method not allowed"} 505 | {"code":406,"definition":"Not acceptable"} 506 | {"code":406,"definition":"Not acceptable"} 507 | {"code":405,"definition":"Method not allowed"} 508 | {"code":406,"definition":"Not acceptable"} 509 | {"code":406,"definition":"Not acceptable"} 510 | {"code":406,"definition":"Not acceptable"} 511 | {"code":404,"definition":"Page not found"} 512 | {"code":404,"definition":"Page not found"} 513 | {"code":404,"definition":"Page not found"} 514 | {"code":407,"definition":"Proxy authentication required"} 515 | {"code":405,"definition":"Method not allowed"} 516 | {"code":405,"definition":"Method not allowed"} 517 | {"code":407,"definition":"Proxy authentication required"} 518 | {"code":407,"definition":"Proxy authentication required"} 519 | {"code":406,"definition":"Not acceptable"} 520 | {"code":407,"definition":"Proxy authentication required"} 521 | {"code":404,"definition":"Page not found"} 522 | {"code":407,"definition":"Proxy authentication required"} 523 | {"code":407,"definition":"Proxy authentication required"} 524 | {"code":407,"definition":"Proxy authentication required"} 525 | {"code":407,"definition":"Proxy authentication required"} 526 | {"code":404,"definition":"Page not found"} 527 | {"code":404,"definition":"Page not found"} 528 | {"code":407,"definition":"Proxy authentication required"} 529 | {"code":406,"definition":"Not acceptable"} 530 | {"code":406,"definition":"Not acceptable"} 531 | {"code":406,"definition":"Not acceptable"} 532 | {"code":406,"definition":"Not acceptable"} 533 | {"code":406,"definition":"Not acceptable"} 534 | {"code":404,"definition":"Page not found"} 535 | {"code":406,"definition":"Not acceptable"} 536 | {"code":406,"definition":"Not acceptable"} 537 | {"code":406,"definition":"Not acceptable"} 538 | {"code":406,"definition":"Not acceptable"} 539 | {"code":406,"definition":"Not acceptable"} 540 | {"code":405,"definition":"Method not allowed"} 541 | {"code":404,"definition":"Page not found"} 542 | {"code":405,"definition":"Method not allowed"} 543 | {"code":405,"definition":"Method not allowed"} 544 | {"code":407,"definition":"Proxy authentication required"} 545 | {"code":406,"definition":"Not acceptable"} 546 | {"code":407,"definition":"Proxy authentication required"} 547 | {"code":406,"definition":"Not acceptable"} 548 | {"code":404,"definition":"Page not found"} 549 | {"code":404,"definition":"Page not found"} 550 | {"code":406,"definition":"Not acceptable"} 551 | {"code":404,"definition":"Page not found"} 552 | {"code":404,"definition":"Page not found"} 553 | {"code":405,"definition":"Method not allowed"} 554 | {"code":406,"definition":"Not acceptable"} 555 | {"code":405,"definition":"Method not allowed"} 556 | {"code":407,"definition":"Proxy authentication required"} 557 | {"code":405,"definition":"Method not allowed"} 558 | {"code":404,"definition":"Page not found"} 559 | {"code":406,"definition":"Not acceptable"} 560 | {"code":404,"definition":"Page not found"} 561 | {"code":405,"definition":"Method not allowed"} 562 | {"code":405,"definition":"Method not allowed"} 563 | {"code":404,"definition":"Page not found"} 564 | {"code":406,"definition":"Not acceptable"} 565 | {"code":406,"definition":"Not acceptable"} 566 | {"code":405,"definition":"Method not allowed"} 567 | {"code":405,"definition":"Method not allowed"} 568 | {"code":405,"definition":"Method not allowed"} 569 | {"code":406,"definition":"Not acceptable"} 570 | {"code":406,"definition":"Not acceptable"} 571 | {"code":406,"definition":"Not acceptable"} 572 | {"code":407,"definition":"Proxy authentication required"} 573 | {"code":407,"definition":"Proxy authentication required"} 574 | {"code":404,"definition":"Page not found"} 575 | {"code":405,"definition":"Method not allowed"} 576 | {"code":405,"definition":"Method not allowed"} 577 | {"code":405,"definition":"Method not allowed"} 578 | {"code":406,"definition":"Not acceptable"} 579 | {"code":404,"definition":"Page not found"} 580 | {"code":407,"definition":"Proxy authentication required"} 581 | {"code":404,"definition":"Page not found"} 582 | {"code":406,"definition":"Not acceptable"} 583 | {"code":407,"definition":"Proxy authentication required"} 584 | {"code":405,"definition":"Method not allowed"} 585 | {"code":405,"definition":"Method not allowed"} 586 | {"code":406,"definition":"Not acceptable"} 587 | {"code":404,"definition":"Page not found"} 588 | {"code":407,"definition":"Proxy authentication required"} 589 | {"code":404,"definition":"Page not found"} 590 | {"code":404,"definition":"Page not found"} 591 | {"code":404,"definition":"Page not found"} 592 | {"code":404,"definition":"Page not found"} 593 | {"code":404,"definition":"Page not found"} 594 | {"code":405,"definition":"Method not allowed"} 595 | {"code":407,"definition":"Proxy authentication required"} 596 | {"code":405,"definition":"Method not allowed"} 597 | {"code":406,"definition":"Not acceptable"} 598 | {"code":405,"definition":"Method not allowed"} 599 | {"code":407,"definition":"Proxy authentication required"} 600 | {"code":406,"definition":"Not acceptable"} 601 | {"code":407,"definition":"Proxy authentication required"} 602 | {"code":407,"definition":"Proxy authentication required"} 603 | {"code":407,"definition":"Proxy authentication required"} 604 | {"code":405,"definition":"Method not allowed"} 605 | {"code":405,"definition":"Method not allowed"} 606 | {"code":407,"definition":"Proxy authentication required"} 607 | {"code":406,"definition":"Not acceptable"} 608 | {"code":405,"definition":"Method not allowed"} 609 | {"code":407,"definition":"Proxy authentication required"} 610 | {"code":406,"definition":"Not acceptable"} 611 | {"code":404,"definition":"Page not found"} 612 | {"code":407,"definition":"Proxy authentication required"} 613 | {"code":405,"definition":"Method not allowed"} 614 | {"code":404,"definition":"Page not found"} 615 | {"code":405,"definition":"Method not allowed"} 616 | {"code":407,"definition":"Proxy authentication required"} 617 | {"code":406,"definition":"Not acceptable"} 618 | {"code":406,"definition":"Not acceptable"} 619 | {"code":405,"definition":"Method not allowed"} 620 | {"code":405,"definition":"Method not allowed"} 621 | {"code":404,"definition":"Page not found"} 622 | {"code":405,"definition":"Method not allowed"} 623 | {"code":405,"definition":"Method not allowed"} 624 | {"code":407,"definition":"Proxy authentication required"} 625 | {"code":407,"definition":"Proxy authentication required"} 626 | {"code":407,"definition":"Proxy authentication required"} 627 | {"code":407,"definition":"Proxy authentication required"} 628 | {"code":406,"definition":"Not acceptable"} 629 | {"code":405,"definition":"Method not allowed"} 630 | {"code":404,"definition":"Page not found"} 631 | {"code":405,"definition":"Method not allowed"} 632 | {"code":405,"definition":"Method not allowed"} 633 | {"code":405,"definition":"Method not allowed"} 634 | {"code":407,"definition":"Proxy authentication required"} 635 | {"code":406,"definition":"Not acceptable"} 636 | {"code":404,"definition":"Page not found"} 637 | {"code":407,"definition":"Proxy authentication required"} 638 | {"code":405,"definition":"Method not allowed"} 639 | {"code":407,"definition":"Proxy authentication required"} 640 | {"code":405,"definition":"Method not allowed"} 641 | {"code":406,"definition":"Not acceptable"} 642 | {"code":406,"definition":"Not acceptable"} 643 | {"code":404,"definition":"Page not found"} 644 | {"code":405,"definition":"Method not allowed"} 645 | {"code":407,"definition":"Proxy authentication required"} 646 | {"code":406,"definition":"Not acceptable"} 647 | {"code":404,"definition":"Page not found"} 648 | {"code":405,"definition":"Method not allowed"} 649 | {"code":406,"definition":"Not acceptable"} 650 | {"code":405,"definition":"Method not allowed"} 651 | {"code":407,"definition":"Proxy authentication required"} 652 | {"code":405,"definition":"Method not allowed"} 653 | {"code":406,"definition":"Not acceptable"} 654 | {"code":406,"definition":"Not acceptable"} 655 | {"code":404,"definition":"Page not found"} 656 | {"code":404,"definition":"Page not found"} 657 | {"code":404,"definition":"Page not found"} 658 | {"code":407,"definition":"Proxy authentication required"} 659 | {"code":405,"definition":"Method not allowed"} 660 | {"code":407,"definition":"Proxy authentication required"} 661 | {"code":406,"definition":"Not acceptable"} 662 | {"code":406,"definition":"Not acceptable"} 663 | {"code":405,"definition":"Method not allowed"} 664 | {"code":405,"definition":"Method not allowed"} 665 | {"code":404,"definition":"Page not found"} 666 | {"code":406,"definition":"Not acceptable"} 667 | {"code":407,"definition":"Proxy authentication required"} 668 | {"code":406,"definition":"Not acceptable"} 669 | {"code":406,"definition":"Not acceptable"} 670 | {"code":406,"definition":"Not acceptable"} 671 | {"code":406,"definition":"Not acceptable"} 672 | {"code":405,"definition":"Method not allowed"} 673 | {"code":407,"definition":"Proxy authentication required"} 674 | {"code":404,"definition":"Page not found"} 675 | {"code":407,"definition":"Proxy authentication required"} 676 | {"code":405,"definition":"Method not allowed"} 677 | {"code":407,"definition":"Proxy authentication required"} 678 | {"code":406,"definition":"Not acceptable"} 679 | {"code":404,"definition":"Page not found"} 680 | {"code":406,"definition":"Not acceptable"} 681 | {"code":407,"definition":"Proxy authentication required"} 682 | {"code":406,"definition":"Not acceptable"} 683 | {"code":405,"definition":"Method not allowed"} 684 | {"code":405,"definition":"Method not allowed"} 685 | {"code":404,"definition":"Page not found"} 686 | {"code":406,"definition":"Not acceptable"} 687 | {"code":407,"definition":"Proxy authentication required"} 688 | {"code":407,"definition":"Proxy authentication required"} 689 | {"code":404,"definition":"Page not found"} 690 | {"code":406,"definition":"Not acceptable"} 691 | {"code":404,"definition":"Page not found"} 692 | {"code":406,"definition":"Not acceptable"} 693 | {"code":406,"definition":"Not acceptable"} 694 | {"code":404,"definition":"Page not found"} 695 | {"code":404,"definition":"Page not found"} 696 | {"code":404,"definition":"Page not found"} 697 | {"code":405,"definition":"Method not allowed"} 698 | {"code":405,"definition":"Method not allowed"} 699 | {"code":404,"definition":"Page not found"} 700 | {"code":405,"definition":"Method not allowed"} 701 | {"code":404,"definition":"Page not found"} 702 | {"code":404,"definition":"Page not found"} 703 | {"code":406,"definition":"Not acceptable"} 704 | {"code":404,"definition":"Page not found"} 705 | {"code":407,"definition":"Proxy authentication required"} 706 | {"code":406,"definition":"Not acceptable"} 707 | {"code":406,"definition":"Not acceptable"} 708 | {"code":404,"definition":"Page not found"} 709 | {"code":407,"definition":"Proxy authentication required"} 710 | {"code":406,"definition":"Not acceptable"} 711 | {"code":404,"definition":"Page not found"} 712 | {"code":407,"definition":"Proxy authentication required"} 713 | {"code":405,"definition":"Method not allowed"} 714 | {"code":406,"definition":"Not acceptable"} 715 | {"code":404,"definition":"Page not found"} 716 | {"code":404,"definition":"Page not found"} 717 | {"code":407,"definition":"Proxy authentication required"} 718 | {"code":405,"definition":"Method not allowed"} 719 | {"code":405,"definition":"Method not allowed"} 720 | {"code":407,"definition":"Proxy authentication required"} 721 | {"code":406,"definition":"Not acceptable"} 722 | {"code":404,"definition":"Page not found"} 723 | {"code":407,"definition":"Proxy authentication required"} 724 | {"code":405,"definition":"Method not allowed"} 725 | {"code":407,"definition":"Proxy authentication required"} 726 | {"code":406,"definition":"Not acceptable"} 727 | {"code":405,"definition":"Method not allowed"} 728 | {"code":407,"definition":"Proxy authentication required"} 729 | {"code":404,"definition":"Page not found"} 730 | {"code":404,"definition":"Page not found"} 731 | {"code":405,"definition":"Method not allowed"} 732 | {"code":404,"definition":"Page not found"} 733 | {"code":407,"definition":"Proxy authentication required"} 734 | {"code":404,"definition":"Page not found"} 735 | {"code":406,"definition":"Not acceptable"} 736 | {"code":405,"definition":"Method not allowed"} 737 | {"code":407,"definition":"Proxy authentication required"} 738 | {"code":407,"definition":"Proxy authentication required"} 739 | {"code":407,"definition":"Proxy authentication required"} 740 | {"code":404,"definition":"Page not found"} 741 | {"code":405,"definition":"Method not allowed"} 742 | {"code":404,"definition":"Page not found"} 743 | {"code":404,"definition":"Page not found"} 744 | {"code":404,"definition":"Page not found"} 745 | {"code":404,"definition":"Page not found"} 746 | {"code":407,"definition":"Proxy authentication required"} 747 | {"code":404,"definition":"Page not found"} 748 | {"code":405,"definition":"Method not allowed"} 749 | {"code":404,"definition":"Page not found"} 750 | {"code":407,"definition":"Proxy authentication required"} 751 | {"code":407,"definition":"Proxy authentication required"} 752 | {"code":407,"definition":"Proxy authentication required"} 753 | {"code":407,"definition":"Proxy authentication required"} 754 | {"code":405,"definition":"Method not allowed"} 755 | {"code":407,"definition":"Proxy authentication required"} 756 | {"code":404,"definition":"Page not found"} 757 | {"code":404,"definition":"Page not found"} 758 | {"code":406,"definition":"Not acceptable"} 759 | {"code":404,"definition":"Page not found"} 760 | {"code":406,"definition":"Not acceptable"} 761 | {"code":406,"definition":"Not acceptable"} 762 | {"code":406,"definition":"Not acceptable"} 763 | {"code":406,"definition":"Not acceptable"} 764 | {"code":404,"definition":"Page not found"} 765 | {"code":404,"definition":"Page not found"} 766 | {"code":407,"definition":"Proxy authentication required"} 767 | {"code":407,"definition":"Proxy authentication required"} 768 | {"code":406,"definition":"Not acceptable"} 769 | {"code":404,"definition":"Page not found"} 770 | {"code":404,"definition":"Page not found"} 771 | {"code":404,"definition":"Page not found"} 772 | {"code":405,"definition":"Method not allowed"} 773 | {"code":405,"definition":"Method not allowed"} 774 | {"code":404,"definition":"Page not found"} 775 | {"code":404,"definition":"Page not found"} 776 | {"code":406,"definition":"Not acceptable"} 777 | {"code":407,"definition":"Proxy authentication required"} 778 | {"code":404,"definition":"Page not found"} 779 | {"code":405,"definition":"Method not allowed"} 780 | {"code":404,"definition":"Page not found"} 781 | {"code":407,"definition":"Proxy authentication required"} 782 | {"code":406,"definition":"Not acceptable"} 783 | {"code":407,"definition":"Proxy authentication required"} 784 | {"code":407,"definition":"Proxy authentication required"} 785 | {"code":407,"definition":"Proxy authentication required"} 786 | {"code":404,"definition":"Page not found"} 787 | {"code":406,"definition":"Not acceptable"} 788 | {"code":405,"definition":"Method not allowed"} 789 | {"code":406,"definition":"Not acceptable"} 790 | {"code":404,"definition":"Page not found"} 791 | {"code":405,"definition":"Method not allowed"} 792 | {"code":406,"definition":"Not acceptable"} 793 | {"code":404,"definition":"Page not found"} 794 | {"code":407,"definition":"Proxy authentication required"} 795 | {"code":407,"definition":"Proxy authentication required"} 796 | {"code":406,"definition":"Not acceptable"} 797 | {"code":405,"definition":"Method not allowed"} 798 | {"code":405,"definition":"Method not allowed"} 799 | {"code":404,"definition":"Page not found"} 800 | {"code":404,"definition":"Page not found"} 801 | {"code":404,"definition":"Page not found"} 802 | {"code":406,"definition":"Not acceptable"} 803 | {"code":407,"definition":"Proxy authentication required"} 804 | {"code":406,"definition":"Not acceptable"} 805 | {"code":405,"definition":"Method not allowed"} 806 | {"code":405,"definition":"Method not allowed"} 807 | {"code":404,"definition":"Page not found"} 808 | {"code":404,"definition":"Page not found"} 809 | {"code":405,"definition":"Method not allowed"} 810 | {"code":406,"definition":"Not acceptable"} 811 | {"code":407,"definition":"Proxy authentication required"} 812 | {"code":407,"definition":"Proxy authentication required"} 813 | {"code":407,"definition":"Proxy authentication required"} 814 | {"code":405,"definition":"Method not allowed"} 815 | {"code":406,"definition":"Not acceptable"} 816 | {"code":405,"definition":"Method not allowed"} 817 | {"code":405,"definition":"Method not allowed"} 818 | {"code":407,"definition":"Proxy authentication required"} 819 | {"code":404,"definition":"Page not found"} 820 | {"code":404,"definition":"Page not found"} 821 | {"code":405,"definition":"Method not allowed"} 822 | {"code":407,"definition":"Proxy authentication required"} 823 | {"code":406,"definition":"Not acceptable"} 824 | {"code":407,"definition":"Proxy authentication required"} 825 | {"code":406,"definition":"Not acceptable"} 826 | {"code":407,"definition":"Proxy authentication required"} 827 | {"code":406,"definition":"Not acceptable"} 828 | {"code":404,"definition":"Page not found"} 829 | {"code":405,"definition":"Method not allowed"} 830 | {"code":404,"definition":"Page not found"} 831 | {"code":406,"definition":"Not acceptable"} 832 | {"code":406,"definition":"Not acceptable"} 833 | {"code":405,"definition":"Method not allowed"} 834 | {"code":404,"definition":"Page not found"} 835 | {"code":407,"definition":"Proxy authentication required"} 836 | {"code":406,"definition":"Not acceptable"} 837 | {"code":407,"definition":"Proxy authentication required"} 838 | {"code":407,"definition":"Proxy authentication required"} 839 | {"code":404,"definition":"Page not found"} 840 | {"code":404,"definition":"Page not found"} 841 | {"code":404,"definition":"Page not found"} 842 | {"code":404,"definition":"Page not found"} 843 | {"code":405,"definition":"Method not allowed"} 844 | {"code":406,"definition":"Not acceptable"} 845 | {"code":406,"definition":"Not acceptable"} 846 | {"code":404,"definition":"Page not found"} 847 | {"code":404,"definition":"Page not found"} 848 | {"code":404,"definition":"Page not found"} 849 | {"code":405,"definition":"Method not allowed"} 850 | {"code":405,"definition":"Method not allowed"} 851 | {"code":407,"definition":"Proxy authentication required"} 852 | {"code":405,"definition":"Method not allowed"} 853 | {"code":404,"definition":"Page not found"} 854 | {"code":406,"definition":"Not acceptable"} 855 | {"code":405,"definition":"Method not allowed"} 856 | {"code":406,"definition":"Not acceptable"} 857 | {"code":406,"definition":"Not acceptable"} 858 | {"code":404,"definition":"Page not found"} 859 | {"code":406,"definition":"Not acceptable"} 860 | {"code":404,"definition":"Page not found"} 861 | {"code":406,"definition":"Not acceptable"} 862 | {"code":407,"definition":"Proxy authentication required"} 863 | {"code":404,"definition":"Page not found"} 864 | {"code":405,"definition":"Method not allowed"} 865 | {"code":406,"definition":"Not acceptable"} 866 | {"code":404,"definition":"Page not found"} 867 | {"code":405,"definition":"Method not allowed"} 868 | {"code":407,"definition":"Proxy authentication required"} 869 | {"code":404,"definition":"Page not found"} 870 | {"code":407,"definition":"Proxy authentication required"} 871 | {"code":404,"definition":"Page not found"} 872 | {"code":405,"definition":"Method not allowed"} 873 | {"code":406,"definition":"Not acceptable"} 874 | {"code":406,"definition":"Not acceptable"} 875 | {"code":405,"definition":"Method not allowed"} 876 | {"code":406,"definition":"Not acceptable"} 877 | {"code":405,"definition":"Method not allowed"} 878 | {"code":404,"definition":"Page not found"} 879 | {"code":405,"definition":"Method not allowed"} 880 | {"code":404,"definition":"Page not found"} 881 | {"code":406,"definition":"Not acceptable"} 882 | {"code":407,"definition":"Proxy authentication required"} 883 | {"code":404,"definition":"Page not found"} 884 | {"code":406,"definition":"Not acceptable"} 885 | {"code":404,"definition":"Page not found"} 886 | {"code":407,"definition":"Proxy authentication required"} 887 | {"code":404,"definition":"Page not found"} 888 | {"code":404,"definition":"Page not found"} 889 | {"code":406,"definition":"Not acceptable"} 890 | {"code":405,"definition":"Method not allowed"} 891 | {"code":407,"definition":"Proxy authentication required"} 892 | {"code":407,"definition":"Proxy authentication required"} 893 | {"code":405,"definition":"Method not allowed"} 894 | {"code":405,"definition":"Method not allowed"} 895 | {"code":404,"definition":"Page not found"} 896 | {"code":404,"definition":"Page not found"} 897 | {"code":404,"definition":"Page not found"} 898 | {"code":405,"definition":"Method not allowed"} 899 | {"code":405,"definition":"Method not allowed"} 900 | {"code":407,"definition":"Proxy authentication required"} 901 | {"code":407,"definition":"Proxy authentication required"} 902 | {"code":407,"definition":"Proxy authentication required"} 903 | {"code":406,"definition":"Not acceptable"} 904 | {"code":407,"definition":"Proxy authentication required"} 905 | {"code":406,"definition":"Not acceptable"} 906 | {"code":406,"definition":"Not acceptable"} 907 | {"code":406,"definition":"Not acceptable"} 908 | {"code":407,"definition":"Proxy authentication required"} 909 | {"code":406,"definition":"Not acceptable"} 910 | {"code":406,"definition":"Not acceptable"} 911 | {"code":406,"definition":"Not acceptable"} 912 | {"code":405,"definition":"Method not allowed"} 913 | {"code":407,"definition":"Proxy authentication required"} 914 | {"code":404,"definition":"Page not found"} 915 | {"code":405,"definition":"Method not allowed"} 916 | {"code":406,"definition":"Not acceptable"} 917 | {"code":405,"definition":"Method not allowed"} 918 | {"code":406,"definition":"Not acceptable"} 919 | {"code":407,"definition":"Proxy authentication required"} 920 | {"code":407,"definition":"Proxy authentication required"} 921 | {"code":405,"definition":"Method not allowed"} 922 | {"code":404,"definition":"Page not found"} 923 | {"code":406,"definition":"Not acceptable"} 924 | {"code":406,"definition":"Not acceptable"} 925 | {"code":406,"definition":"Not acceptable"} 926 | {"code":406,"definition":"Not acceptable"} 927 | {"code":404,"definition":"Page not found"} 928 | {"code":405,"definition":"Method not allowed"} 929 | {"code":404,"definition":"Page not found"} 930 | {"code":407,"definition":"Proxy authentication required"} 931 | {"code":407,"definition":"Proxy authentication required"} 932 | {"code":407,"definition":"Proxy authentication required"} 933 | {"code":407,"definition":"Proxy authentication required"} 934 | {"code":405,"definition":"Method not allowed"} 935 | {"code":404,"definition":"Page not found"} 936 | {"code":404,"definition":"Page not found"} 937 | {"code":405,"definition":"Method not allowed"} 938 | {"code":405,"definition":"Method not allowed"} 939 | {"code":407,"definition":"Proxy authentication required"} 940 | {"code":404,"definition":"Page not found"} 941 | {"code":407,"definition":"Proxy authentication required"} 942 | {"code":407,"definition":"Proxy authentication required"} 943 | {"code":404,"definition":"Page not found"} 944 | {"code":405,"definition":"Method not allowed"} 945 | {"code":406,"definition":"Not acceptable"} 946 | {"code":406,"definition":"Not acceptable"} 947 | {"code":404,"definition":"Page not found"} 948 | {"code":407,"definition":"Proxy authentication required"} 949 | {"code":405,"definition":"Method not allowed"} 950 | {"code":404,"definition":"Page not found"} 951 | {"code":407,"definition":"Proxy authentication required"} 952 | {"code":406,"definition":"Not acceptable"} 953 | {"code":406,"definition":"Not acceptable"} 954 | {"code":407,"definition":"Proxy authentication required"} 955 | {"code":404,"definition":"Page not found"} 956 | {"code":407,"definition":"Proxy authentication required"} 957 | {"code":405,"definition":"Method not allowed"} 958 | {"code":405,"definition":"Method not allowed"} 959 | {"code":406,"definition":"Not acceptable"} 960 | {"code":406,"definition":"Not acceptable"} 961 | {"code":406,"definition":"Not acceptable"} 962 | {"code":407,"definition":"Proxy authentication required"} 963 | {"code":407,"definition":"Proxy authentication required"} 964 | {"code":405,"definition":"Method not allowed"} 965 | {"code":407,"definition":"Proxy authentication required"} 966 | {"code":407,"definition":"Proxy authentication required"} 967 | {"code":407,"definition":"Proxy authentication required"} 968 | {"code":405,"definition":"Method not allowed"} 969 | {"code":406,"definition":"Not acceptable"} 970 | {"code":407,"definition":"Proxy authentication required"} 971 | {"code":407,"definition":"Proxy authentication required"} 972 | {"code":405,"definition":"Method not allowed"} 973 | {"code":406,"definition":"Not acceptable"} 974 | {"code":405,"definition":"Method not allowed"} 975 | {"code":407,"definition":"Proxy authentication required"} 976 | {"code":404,"definition":"Page not found"} 977 | {"code":407,"definition":"Proxy authentication required"} 978 | {"code":405,"definition":"Method not allowed"} 979 | {"code":406,"definition":"Not acceptable"} 980 | {"code":404,"definition":"Page not found"} 981 | {"code":407,"definition":"Proxy authentication required"} 982 | {"code":404,"definition":"Page not found"} 983 | {"code":405,"definition":"Method not allowed"} 984 | {"code":406,"definition":"Not acceptable"} 985 | {"code":404,"definition":"Page not found"} 986 | {"code":406,"definition":"Not acceptable"} 987 | {"code":404,"definition":"Page not found"} 988 | {"code":404,"definition":"Page not found"} 989 | {"code":404,"definition":"Page not found"} 990 | {"code":406,"definition":"Not acceptable"} 991 | {"code":407,"definition":"Proxy authentication required"} 992 | {"code":404,"definition":"Page not found"} 993 | {"code":406,"definition":"Not acceptable"} 994 | {"code":405,"definition":"Method not allowed"} 995 | {"code":406,"definition":"Not acceptable"} 996 | {"code":406,"definition":"Not acceptable"} 997 | {"code":404,"definition":"Page not found"} 998 | {"code":407,"definition":"Proxy authentication required"} 999 | {"code":404,"definition":"Page not found"} 1000 | {"code":407,"definition":"Proxy authentication required"} -------------------------------------------------------------------------------- /server/cmd/ksql/statements.sql: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------------------------- 2 | -- Create sources: 3 | --------------------------------------------------------------------------------------------------- 4 | 5 | CREATE STREAM CLICKSTREAM_CODES ( 6 | CODE INTEGER, DEFINITION STRING 7 | ) WITH ( 8 | KAFKA_TOPIC='CLICKSTREAM_CODES', 9 | PARTITIONS=2, 10 | REPLICAS=1, 11 | VALUE_FORMAT='json'); 12 | 13 | --------------------------------------------------------------------------------------------------- 14 | -- Build materialized table views: 15 | --------------------------------------------------------------------------------------------------- 16 | 17 | CREATE TABLE 404_ERRORS_PER_MIN AS 18 | SELECT 19 | CODE, 20 | TIMESTAMPTOSTRING(WINDOWSTART, 'HH:mm:ss') as WINDOW_START, 21 | COUNT(CODE) AS COUNT 22 | FROM CLICKSTREAM_CODES WINDOW TUMBLING (size 10 seconds) 23 | WHERE CODE = 404 24 | GROUP BY CODE EMIT CHANGES; 25 | 26 | -- Query with statement below to see the actual seconds (does not include the default WINDOWSTART/END): 27 | -- SELECT TIMESTAMPTOSTRING(ROWTIME, 'HH:mm:ss'), CODE, COUNT 28 | -- FROM 404_ERRORS_PER_MIN EMIT CHANGES; 29 | 30 | CREATE TABLE 405_ERRORS_PER_MIN AS 31 | SELECT 32 | CODE, 33 | TIMESTAMPTOSTRING(WINDOWSTART, 'HH:mm:ss') as WINDOW_START, 34 | COUNT(CODE) AS COUNT 35 | FROM CLICKSTREAM_CODES WINDOW TUMBLING (size 10 seconds) 36 | WHERE CODE = 405 37 | GROUP BY CODE EMIT CHANGES; 38 | 39 | -- SELECT TIMESTAMPTOSTRING(ROWTIME, 'HH:mm:ss'), CODE, COUNT 40 | -- FROM 405_ERRORS_PER_MIN EMIT CHANGES; 41 | 42 | CREATE TABLE 406_ERRORS_PER_MIN AS 43 | SELECT 44 | CODE, 45 | TIMESTAMPTOSTRING(WINDOWSTART, 'HH:mm:ss') as WINDOW_START, 46 | COUNT(CODE) AS COUNT 47 | FROM CLICKSTREAM_CODES WINDOW TUMBLING (size 10 seconds) 48 | WHERE CODE = 406 49 | GROUP BY CODE EMIT CHANGES; 50 | 51 | -- SELECT TIMESTAMPTOSTRING(ROWTIME, 'HH:mm:ss'), CODE, COUNT 52 | -- FROM 406_ERRORS_PER_MIN EMIT CHANGES; 53 | 54 | CREATE TABLE 407_ERRORS_PER_MIN AS 55 | SELECT 56 | CODE, 57 | TIMESTAMPTOSTRING(WINDOWSTART, 'HH:mm:ss') as WINDOW_START, 58 | COUNT(CODE) AS COUNT 59 | FROM CLICKSTREAM_CODES WINDOW TUMBLING (size 10 seconds) 60 | WHERE CODE = 407 61 | GROUP BY CODE EMIT CHANGES; 62 | 63 | -- SELECT TIMESTAMPTOSTRING(ROWTIME, 'HH:mm:ss'), CODE, COUNT 64 | -- FROM 407_ERRORS_PER_MIN EMIT CHANGES; 65 | -------------------------------------------------------------------------------- /server/cmd/producer.sh: -------------------------------------------------------------------------------- 1 | kafka-producer-perf-test \ 2 | --topic CLICKSTREAM_CODES \ 3 | --throughput 2 \ 4 | --producer-props bootstrap.servers=localhost:9092 \ 5 | --payload-file server/cmd/ksql/error_data.json \ 6 | --num-records 1000 & -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const http = require("http"); 3 | const express = require("express"); 4 | const socketio = require("socket.io"); 5 | const app = express(); 6 | const server = http.createServer(app); 7 | const io = socketio(server, { 8 | cors: { 9 | origin: "*", 10 | methods: ["GET", "POST"], 11 | }, 12 | }); 13 | 14 | const cors = require("cors"); 15 | const morgan = require("morgan"); 16 | const { Kafka, CompressionTypes, CompressionCodecs } = require("kafkajs"); 17 | const SnappyCodec = require("kafkajs-snappy"); 18 | 19 | CompressionCodecs[CompressionTypes.Snappy] = SnappyCodec; 20 | 21 | // instantiate the KafkaJS client by pointing it towards at least one broker 22 | const kafka = new Kafka({ 23 | clientId: "my-app", 24 | brokers: ["localhost:9092", "localhost:9092"], 25 | }); 26 | 27 | app.use(cors()); 28 | app.use(morgan("combined")); 29 | // serve main html to the client 30 | // The server root will send our index.html 31 | app.get("/", function (req, res) { 32 | console.log(__dirname); 33 | res.sendFile(path.join(__dirname, "../client/index.html")); 34 | }); 35 | 36 | app.use("/dist", express.static(path.join(__dirname, "../dist"))); 37 | 38 | io.on("connection", (socket) => { 39 | socket.emit( 40 | "anything", 41 | "Websockets full duplex protocol established. Begin streaming data from Kafka cluster..." 42 | ); 43 | 44 | // 404 consumer 45 | const consumer_404 = kafka.consumer({ 46 | groupId: "group404", 47 | fromBeginning: true, 48 | }); 49 | consumer_404.connect(); 50 | consumer_404.subscribe({ topic: "404_ERRORS_PER_MIN" }); 51 | consumer_404.run({ 52 | eachMessage: async ({ topic, partition, message }) => { 53 | socket.broadcast.emit("404_ERRORS_PER_MIN", message.value.toString()); 54 | }, 55 | }); 56 | 57 | // 405 consumer 58 | const consumer_405 = kafka.consumer({ 59 | groupId: "group405", 60 | fromBeginning: true, 61 | }); 62 | consumer_405.connect(); 63 | consumer_405.subscribe({ topic: "405_ERRORS_PER_MIN" }); 64 | consumer_405.run({ 65 | eachMessage: async ({ topic, partition, message }) => { 66 | socket.broadcast.emit("405_ERRORS_PER_MIN", message.value.toString()); 67 | }, 68 | }); 69 | 70 | // 406 consumer 71 | const consumer_406 = kafka.consumer({ 72 | groupId: "group406", 73 | fromBeginning: true, 74 | }); 75 | consumer_406.connect(); 76 | consumer_406.subscribe({ topic: "406_ERRORS_PER_MIN" }); 77 | consumer_406.run({ 78 | eachMessage: async ({ topic, partition, message }) => { 79 | socket.broadcast.emit("406_ERRORS_PER_MIN", message.value.toString()); 80 | }, 81 | }); 82 | 83 | // 407 consumer 84 | const consumer_407 = kafka.consumer({ 85 | groupId: "group407", 86 | fromBeginning: true, 87 | }); 88 | consumer_407.connect(); 89 | consumer_407.subscribe({ topic: "407_ERRORS_PER_MIN" }); 90 | consumer_407.run({ 91 | eachMessage: async ({ topic, partition, message }) => { 92 | socket.broadcast.emit("407_ERRORS_PER_MIN", message.value.toString()); 93 | }, 94 | }); 95 | }); 96 | 97 | server.on("error", (err) => { 98 | console.log(err); 99 | }); 100 | 101 | const PORT = 3333 || process.env.PORT; 102 | 103 | server.listen(PORT, () => { 104 | console.log(`Server listening on port ${PORT}`); 105 | }); 106 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | 4 | module.exports = { 5 | entry: "./client/index.js", 6 | output: { 7 | path: path.resolve(__dirname, "dist"), 8 | filename: "index_bundle.js", 9 | }, 10 | devtool: 'source-map', 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.(js|jsx)$/, 15 | exclude: /(node_modules)/, 16 | use: { 17 | loader: "babel-loader", 18 | options: { 19 | presets: ["@babel/preset-env", "@babel/preset-react"], 20 | }, 21 | }, 22 | }, 23 | { 24 | test: /\.(css|scss)$/i, 25 | use: ["style-loader", "css-loader", "sass-loader"], 26 | }, 27 | { 28 | test: /\.(jpg|jpeg|png)$/, 29 | use: { 30 | loader: "url-loader", 31 | }, 32 | }, 33 | ], 34 | }, 35 | mode: "development", 36 | plugins: [ 37 | new HtmlWebpackPlugin({ 38 | template: "client/index.html", 39 | }), 40 | ], 41 | }; --------------------------------------------------------------------------------