Skip to content

Commit cec2312

Browse files
authored
Log server (#433)
* Start on log file server. * Support for delete, get, head, and post; with passing tests!
1 parent f504374 commit cec2312

8 files changed

Lines changed: 607 additions & 2 deletions

File tree

extras/log_file_server/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# https://dart.dev/guides/libraries/private-files
2+
# Created by `dart pub`
3+
.dart_tool/
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# This file configures the static analysis results for your project (errors,
2+
# warnings, and lints).
3+
#
4+
# This enables the 'recommended' set of lints from `package:lints`.
5+
# This set helps identify many issues that may lead to problems when running
6+
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
7+
# style and format.
8+
#
9+
# If you want a smaller set of lints you can change this to specify
10+
# 'package:lints/core.yaml'. These are just the most critical lints
11+
# (the recommended set includes the core lints).
12+
# The core lints are also what is used by pub.dev for scoring packages.
13+
14+
include: package:lints/recommended.yaml
15+
16+
# Uncomment the following section to specify additional rules.
17+
18+
# linter:
19+
# rules:
20+
# - camel_case_types
21+
22+
# analyzer:
23+
# exclude:
24+
# - path/to/excluded/files/**
25+
26+
# For more information about the core and recommended set of lints, see
27+
# https://dart.dev/go/core-lints
28+
29+
# For additional information about configuring this file, see
30+
# https://dart.dev/guides/language/analysis-options
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import 'dart:async' show Future;
2+
import 'dart:io';
3+
4+
import 'package:shelf/shelf.dart';
5+
import 'package:shelf/shelf_io.dart';
6+
import 'package:shelf_router/shelf_router.dart';
7+
8+
const rootDir = '/var/opt/oap/logs';
9+
10+
// Configure routes.
11+
final _router = Router()
12+
..delete('/logs/deleteMe.log', _delete)
13+
..get('/logs/<path>', _get)
14+
..head('/logs/<path>', _head)
15+
..post('/logs/<path>', _post);
16+
17+
Future<Response> _delete(Request req) async {
18+
var file = File('$rootDir/deleteMe.log');
19+
if (file.existsSync()) {
20+
await file.delete();
21+
}
22+
return Response.ok(null);
23+
}
24+
25+
Future<Response> _get(Request req, String path) async {
26+
var file = File('$rootDir/$path');
27+
if (!file.existsSync()) {
28+
return Response.notFound(null);
29+
}
30+
var body = file.readAsStringSync();
31+
return Response.ok(body);
32+
}
33+
34+
Future<Response> _head(Request req, String path) async {
35+
var file = File('$rootDir/$path');
36+
if (!file.existsSync()) {
37+
return Response.notFound(null);
38+
}
39+
var length = file.lengthSync();
40+
return Response.ok(null, headers: {'content-length': '$length'});
41+
}
42+
43+
Future<Response> _post(Request req, String path) async {
44+
// validate received data
45+
var mimeType = req.mimeType;
46+
if (mimeType != 'text/plain') {
47+
return Response.badRequest(body: 'Content-Type must be text/plain!');
48+
}
49+
if (req.isEmpty) {
50+
return Response.badRequest(body: 'Body must not be empty!');
51+
}
52+
53+
// get body
54+
var length = req.contentLength;
55+
var body = await req.readAsString();
56+
if (length != body.length) {
57+
return Response.badRequest(
58+
body: 'Content-Length of $length '
59+
'did not match body.length of ${body.length}!');
60+
}
61+
62+
// // get remote address
63+
// var connectionInfo =
64+
// req.context['shelf.io.connection_info'] as HttpConnectionInfo;
65+
// var remoteAddress = connectionInfo.remoteAddress.address;
66+
// print('remoteAddress = "$remoteAddress" (${remoteAddress.runtimeType})');
67+
68+
var file = File('$rootDir/$path');
69+
file.createSync(exclusive: false);
70+
file.writeAsStringSync(
71+
body,
72+
mode: FileMode.writeOnlyAppend,
73+
);
74+
return Response.ok(null);
75+
}
76+
77+
void main(List<String> args) async {
78+
Directory(rootDir).create(recursive: true);
79+
80+
// Use any available host or container IP (usually `0.0.0.0`).
81+
final ip = InternetAddress.anyIPv4;
82+
83+
// Configure a pipeline that logs requests.
84+
final handler = Pipeline().addMiddleware(logRequests()).addHandler(_router);
85+
86+
// For running in containers, we respect the PORT environment variable.
87+
final port = int.parse(Platform.environment['PORT'] ?? '8080');
88+
final server = await serve(handler, ip, port);
89+
print('Server listening on port ${server.port}');
90+
}

0 commit comments

Comments
 (0)