mirror of https://github.com/grafana/grafana.git
				
				
				
			devenv: better loki environment (#49383)
* devenv: rename loki to loki-promtail * devenv: new loki devenv entry with fake data generation
This commit is contained in:
		
							parent
							
								
									b07904fe56
								
							
						
					
					
						commit
						ebc20849bd
					
				|  | @ -0,0 +1,14 @@ | |||
|   # datasource URL: http://localhost:3100/ | ||||
|   loki: | ||||
|     image: grafana/loki:latest | ||||
|     ports: | ||||
|       - "3100:3100" | ||||
|     command: -config.file=/etc/loki/local-config.yaml | ||||
|   promtail: | ||||
|     image: grafana/promtail:latest | ||||
|     volumes: | ||||
|       - ./docker/blocks/loki-promtail/promtail-config.yaml:/etc/promtail/docker-config.yaml | ||||
|       - /var/log:/var/log | ||||
|       - ../data/log:/var/log/grafana | ||||
|     command: | ||||
|       -config.file=/etc/promtail/docker-config.yaml | ||||
|  | @ -0,0 +1,3 @@ | |||
| FROM node:16-alpine | ||||
| 
 | ||||
| COPY data.js /home/node/data.js | ||||
|  | @ -0,0 +1,107 @@ | |||
| const http = require('http'); | ||||
| 
 | ||||
| if (process.argv.length !== 3) { | ||||
|   throw new Error('invalid command line: use node sendLogs.js LOKIC_BASE_URL'); | ||||
| } | ||||
| 
 | ||||
| const LOKI_BASE_URL = process.argv[2]; | ||||
| 
 | ||||
| // helper function, do a http request
 | ||||
| async function jsonRequest(data, method, url, expectedStatusCode) { | ||||
|   return new Promise((resolve, reject) => { | ||||
|     const req = http.request( | ||||
|       { | ||||
|         protocol: url.protocol, | ||||
|         host: url.hostname, | ||||
|         port: url.port, | ||||
|         path: `${url.pathname}${url.search}`, | ||||
|         method, | ||||
|         headers: { 'content-type': 'application/json' }, | ||||
|       }, | ||||
|       (res) => { | ||||
|         if (res.statusCode !== expectedStatusCode) { | ||||
|           reject(new Error(`Invalid response: ${res.statusCode}`)); | ||||
|         } else { | ||||
|           resolve(); | ||||
|         } | ||||
|       } | ||||
|     ); | ||||
| 
 | ||||
|     req.on('error', (err) => reject(err)); | ||||
| 
 | ||||
|     req.write(JSON.stringify(data)); | ||||
|     req.end(); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // helper function, choose a random element from an array
 | ||||
| function chooseRandomElement(items) { | ||||
|   const index = Math.trunc(Math.random() * items.length); | ||||
|   return items[index]; | ||||
| } | ||||
| 
 | ||||
| // helper function, sleep for a duration
 | ||||
| async function sleep(duration) { | ||||
|   return new Promise((resolve) => { | ||||
|     setTimeout(resolve, duration); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| async function lokiSendLogLine(timestampMs, line, tags) { | ||||
|   // we keep nanosecond-timestamp in a string because
 | ||||
|   // as a number it would be too large
 | ||||
|   const timestampNs = `${timestampMs}000000`; | ||||
|   const data = { | ||||
|     streams: [ | ||||
|       { | ||||
|         stream: tags, | ||||
|         values: [[timestampNs, line]], | ||||
|       }, | ||||
|     ], | ||||
|   }; | ||||
| 
 | ||||
|   const url = new URL(LOKI_BASE_URL); | ||||
|   url.pathname = '/loki/api/v1/push'; | ||||
| 
 | ||||
|   await jsonRequest(data, 'POST', url, 204); | ||||
| } | ||||
| 
 | ||||
| function getRandomLogLine(counter) { | ||||
|   const randomText = `${Math.trunc(Math.random() * 1000 * 1000 * 1000)}`; | ||||
|   const maybeAnsiText = Math.random() < 0.5 ? 'with ANSI \u001b[31mpart of the text\u001b[0m' : ''; | ||||
|   return JSON.stringify({ | ||||
|     _entry: `log text ${maybeAnsiText} [${randomText}]`, | ||||
|     counter: counter.toString(), | ||||
|     float: Math.random() > 0.2 ? (100 * Math.random()).toString() : 'NaN', | ||||
|     label: chooseRandomElement(['val1', 'val2', 'val3']), | ||||
|     level: chooseRandomElement(['info', 'info', 'error']), | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| const SLEEP_ANGLE_STEP = Math.PI / 200; | ||||
| let sleepAngle = 0; | ||||
| function getNextSineWaveSleepDuration() { | ||||
|   sleepAngle += SLEEP_ANGLE_STEP; | ||||
|   return Math.trunc(1000 * Math.abs(Math.sin(sleepAngle))); | ||||
| } | ||||
| 
 | ||||
| async function main() { | ||||
|   const tags = { | ||||
|     place: 'moon', | ||||
|   }; | ||||
| 
 | ||||
|   for (let step = 0; step < 300; step++) { | ||||
|     await sleep(getNextSineWaveSleepDuration()); | ||||
|     const timestampMs = new Date().getTime(); | ||||
|     const line = getRandomLogLine(step + 1); | ||||
|     lokiSendLogLine(timestampMs, line, tags); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // when running in docker, we catch the needed stop-signal, to shutdown fast
 | ||||
| process.on('SIGTERM', () => { | ||||
|   console.log('shutdown requested'); | ||||
|   process.exit(0); | ||||
| }); | ||||
| 
 | ||||
| main(); | ||||
|  | @ -1,14 +1,13 @@ | |||
|   # datasource URL: http://localhost:3100/ | ||||
|   loki: | ||||
|     image: grafana/loki:latest | ||||
|     ports: | ||||
|       - "3100:3100" | ||||
|     command: -config.file=/etc/loki/local-config.yaml | ||||
|   promtail: | ||||
|     image: grafana/promtail:latest | ||||
|     volumes: | ||||
|       - ./docker/blocks/loki/promtail-config.yaml:/etc/promtail/docker-config.yaml | ||||
|       - /var/log:/var/log | ||||
|       - ../data/log:/var/log/grafana | ||||
|     command: | ||||
|       -config.file=/etc/promtail/docker-config.yaml | ||||
| 
 | ||||
|   data: | ||||
|     build: docker/blocks/loki/data | ||||
|     command: node /home/node/data.js http://loki:3100 | ||||
|     depends_on: | ||||
|       - loki | ||||
|     # when loki starts, there might be some time while it is not | ||||
|     # accepting requests, so we allow data.js to restart on failure. | ||||
|     restart: "on-failure" | ||||
		Loading…
	
		Reference in New Issue