Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhanced Logging System with Winston Integration #69

Merged
merged 26 commits into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
66d1711
Update logger.js
Sweetdevil144 Feb 3, 2024
d80b039
Implement logger.js
Sweetdevil144 Feb 3, 2024
c61b1db
Update logger.js
Sweetdevil144 Feb 3, 2024
0b3cdf0
Update logger.js
Sweetdevil144 Feb 3, 2024
850bc1c
Merge branch 'master' of https://github.com/Sweetdevil144/geoip
Sweetdevil144 Feb 3, 2024
ea671d3
Merge branch 'ChakshuGautam:master' into master
Sweetdevil144 Feb 6, 2024
983a35a
Update logger.js class requirement
Sweetdevil144 Feb 6, 2024
44c4279
Merge branch 'ChakshuGautam:master' into master
Sweetdevil144 Feb 7, 2024
39f49aa
Merge branch 'master' into master
Sweetdevil144 Feb 9, 2024
2b3b5a3
Update db.mmdb
Sweetdevil144 Feb 11, 2024
bdc79f6
Merge branch 'ChakshuGautam:master' into master
Sweetdevil144 Feb 14, 2024
1d1b3cb
Update Logger constructor
Sweetdevil144 Feb 14, 2024
1920a8c
merging branches
Sweetdevil144 Feb 14, 2024
e02150a
Merge branch 'master' of https://github.com/Sweetdevil144/geoip
Sweetdevil144 Feb 14, 2024
945c9ff
Update db.mmdb
Sweetdevil144 Feb 18, 2024
79e9961
Merge branch 'ChakshuGautam:master' into master
Sweetdevil144 Feb 25, 2024
e6fe831
Updated all logger logs
Sweetdevil144 Feb 25, 2024
a879a42
Update swagger.js
Sweetdevil144 Feb 25, 2024
ec63183
Update lock files
Sweetdevil144 Feb 25, 2024
ff89c52
Update db.mmdb
Sweetdevil144 Feb 25, 2024
7f173a7
Merge branch 'ChakshuGautam:master' into master
Sweetdevil144 Feb 25, 2024
ae3a083
Update syntax
Sweetdevil144 Feb 25, 2024
ee48e96
Update loggers
Sweetdevil144 Feb 28, 2024
f7c2e63
Update db.mmdb
Sweetdevil144 Mar 3, 2024
9e52fa3
Merge branch 'ChakshuGautam:master' into master
Sweetdevil144 Mar 8, 2024
cd8929b
Update db.mmdb
Sweetdevil144 Mar 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
100755 → 100644
Binary file not shown.
97 changes: 93 additions & 4 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import Bun from 'bun';
import express from 'express';
import swagger from './util/swagger';
import config from './config.json';
import Logger from './util/logger';
import { Level, LocationSearch } from './location.search';

const buffer = fs.readFileSync(`${import.meta.dir}/db.mmdb`);
const reader = Reader.openBuffer(buffer);
const logger = new Logger('app.js');

const locationSearch = new LocationSearch(`${import.meta.dir}/geojson-data/PARSED_MASTER_LOCATION_NAMES.json`);
const swaggerApp = express();
Expand All @@ -27,14 +29,14 @@ const GeoLocationLevel = {
const geoJsonFilesPath = `${import.meta.dir}/geojson-data`;
fs.readdir(geoJsonFilesPath, (err, files) => {
if (err) {
console.error("Error reading folder: ", err);
logger.error(`Error reading folder: ${err}`);
process.exit();
}

for (const locationLevel of config.requiredGeoLocationLevels) {
const geoJsonFileName = `${config.country}_${locationLevel}.geojson`;
if (!files.includes(geoJsonFileName)) {
console.error(`Required GeoJson file: ${geoJsonFileName} not present`);
logger.error(`Required GeoJson file: ${geoJsonFileName} not present`);
process.exit();
}
}
Expand All @@ -44,6 +46,7 @@ const geoJsonFiles = {};
for (const locationLevel of config.requiredGeoLocationLevels) {
const geoJsonFileName = `${config.country}_${locationLevel}`;
geoJsonFiles[geoJsonFileName] = JSON.parse(fs.readFileSync(`${geoJsonFilesPath}/${geoJsonFileName}.geojson`, 'utf8'));
logger.info(`Loaded GeoJson file: ${geoJsonFileName}`);
}

// format the success response data
Expand All @@ -69,6 +72,7 @@ const formatSuccessResponse = (data) => {

// format the georev success response
const formatGeorevSuccessResponse = (data) => {
logger.info(`GeoRev Success Response: ${JSON.stringify(data)}`);
return {
status: 'success',
state: data.stname ? data.stname : '',
Expand All @@ -79,6 +83,7 @@ const formatGeorevSuccessResponse = (data) => {

// format the error response data
const formatErrorResponse = (error, ip) => {
logger.error(`Error processing IP: ${ip}, Error: ${error.name}`);
return {
status: "fail",
message: error.name,
Expand All @@ -87,6 +92,7 @@ const formatErrorResponse = (error, ip) => {
}

const formatCentroidResponse = (data, latitude, longitude) => {
logger.info(`Centroid Success Response: ${JSON.stringify(data)}`);
return {
status: 'success',
state: data.stname ? data.stname : '',
Expand All @@ -101,6 +107,7 @@ const formatCentroidResponse = (data, latitude, longitude) => {
}

function isPointInMultiPolygon(multiPolygon, point) {
logger.info(`Checking if point is in MultiPolygon`);
return multiPolygon.geometry.coordinates.some(polygonCoordinates => {
const poly = turf.polygon(polygonCoordinates);
return turf.booleanContains(poly, point);
Expand All @@ -111,12 +118,16 @@ function individualQuery(country, geoLocationLevel, coordinates) {
const pointToSearch = turf.point(coordinates);
for (let feature of geoJsonFiles[`${country}_${geoLocationLevel}`].features) {
if (feature.geometry.type === 'Polygon') {
logger.info(`Checking if point is in Polygon`);
let poly = turf.polygon(feature.geometry.coordinates, feature.properties);
if (turf.booleanContains(poly, pointToSearch)) {
logger.info(`Point is in Polygon`);
return poly.properties;
}
} else if (feature.geometry.type === 'MultiPolygon') {
logger.info(`Checking if point is in MultiPolygon`);
if (isPointInMultiPolygon(feature, pointToSearch)) {
logger.info(`Point is in MultiPolygon`);
return feature.properties;
}
}
Expand All @@ -128,29 +139,35 @@ export const app = new Router()
.get('/city/:ip', (ctx) => {
try {
const resp = reader.city(ctx.params.ip);
logger.info(`City Success Response: ${JSON.stringify(resp)}`);
return Response.json(formatSuccessResponse(resp));
} catch (error) {
logger.error(`Error processing IP: ${ctx.params.ip}, Error: ${error.name}`);
return Response.json(formatErrorResponse(error,ctx.params.ip));
}
})
.post('/city/batch', async (req) => {
try {
logger.info(`Batch City Request: ${JSON.stringify(req)}`);
const ips = await req.json(); // Extract the 'ips' array from the request body
// Create an array of promises, each promise resolves to the city corresponding to the IP address
const promises = ips.map(async (ip) => {
let response;
try {
response = reader.city(ip);
logger.info(`City Success Response: ${JSON.stringify(response)}`);
return formatSuccessResponse(response);
} catch (error) {
logger.error(`Error processing IP: ${ip}, Error: ${error.name}`);
return formatErrorResponse(error,ip);
}
});
// Wait for all promises to settle and collect the results
const results = await Promise.all(promises);

logger.info(`Batch City Success Response: ${JSON.stringify(results)}`);
return Response.json(results, { status: 200 });
} catch (error) {
logger.error(`Error processing IP addresses: ${error.name}`);
return new Response('Error processing IP addresses', { status: 500 });
}
})
Expand All @@ -160,6 +177,7 @@ export const app = new Router()
let latitude = url.searchParams.get('lat');
let longitude = url.searchParams.get('lon');
if (!latitude || !longitude) {
logger.error(`lat lon query missing`);
return Response.json({
status: 'fail',
error: `lat lon query missing`
Expand All @@ -168,13 +186,16 @@ export const app = new Router()
// Searching for SUBDISTRICT GeoLocation Level
let resp = individualQuery(config.country, GeoLocationLevel.SUBDISTRICT, [longitude, latitude])
if (!resp) {
logger.error(`No GeoLocation found for lat: ${latitude}, lon ${longitude}`);
return Response.json({
status: "fail",
error: `No GeoLocation found for lat: ${latitude}, lon ${longitude}`
}, { status: 404 });
}
logger.info(`GeoRev Success Response: ${JSON.stringify(resp)}`);
return Response.json(formatGeorevSuccessResponse(resp));
} catch (error) {
logger.error(`Error processing lat lon: ${error.name}`);
return Response.json({
status: "fail",
error: error.message
Expand All @@ -186,13 +207,15 @@ export const app = new Router()
let url = new URL(ctx.url);
const locationLevel = ctx.params.locationlevel;
if (!Object.keys(GeoLocationLevel).includes(locationLevel)) {
logger.error(`Unsupported GeoLocation Level: ${locationLevel}`);
return Response.json({
status: 'fail',
error: `Unsupported GeoLocation Level: ${locationLevel}`
}, { status: 400});
}
let query = url.searchParams.get('query');
if (!query) {
logger.error(`No ${locationLevel} query found`);
return Response.json({
status: 'fail',
error: `No ${locationLevel} query found`
Expand All @@ -205,6 +228,7 @@ export const app = new Router()
}
}
if (!queryFeature) {
logger.error(`No ${locationLevel} found with name: ${query}`);
return Response.json({
status: 'fail',
error: `No ${locationLevel} found with name: ${query}`
Expand All @@ -219,7 +243,71 @@ export const app = new Router()
const centroid = turf.centroid(polygonFeature);
const longitude = centroid.geometry.coordinates[0];
const latitude = centroid.geometry.coordinates[1];
logger.info(`Centroid Success Response: ${JSON.stringify(queryFeature.properties)}`);
return Response.json(formatCentroidResponse(queryFeature.properties, latitude, longitude), { status : 200 })
} catch (error) {
logger.error(`Error processing ${locationLevel} query: ${error.name}`);
return Response.json({
status: 'fail',
error: error.name
}, { status: 500 });
}
})
.post('/location/:locationlevel/fuzzysearch', async (req) => {
try {
let reqBody = await req.json();
const locationLevel = req.params.locationlevel;
if (!Object.keys(GeoLocationLevel).includes(locationLevel)) {
return Response.json({
status: 'fail',
error: `Unsupported GeoLocation Level: ${locationLevel}`
}, { status: 400});
}
let query = reqBody.query;
if (!query) {
return Response.json({
status: 'fail',
error: `No ${locationLevel} query found`
}, { status: 400 });
}
let filter = reqBody.filter;
let filterArray = [];
if (filter) {
for (const filterKey of Object.keys(filter)) {
if (!Object.keys(GeoLocationLevel).includes(filterKey)) {
return Response.json({
status: 'fail',
error: `Unsupported GeoLocation Level Filter: ${filterKey}`,
}, { status: 400 })
}
filterArray.push({
level: Level[`${filterKey}`],
query: filter[filterKey],
});
}
}
let searchLevel;
switch (locationLevel) {
case 'STATE':
searchLevel = Level.STATE;
break;
case 'DISTRICT':
searchLevel = Level.DISTRICT;
break;
case 'SUBDISTRICT':
searchLevel = Level.SUBDISTRICT;
break;
case 'VILLAGE':
searchLevel = Level.VILLAGE;
break;
default:
// Unreachable
break;
}
const queryResponse = locationSearch.fuzzySearch(searchLevel, query, filterArray);
return Response.json({
matches: queryResponse
}, { status: 200 });
} catch (error) {
return Response.json({
status: 'fail',
Expand Down Expand Up @@ -291,12 +379,13 @@ export const app = new Router()
});

app.use(404, () => {
logger.error(`404 Not Found`);
return new Response(Bun.file(import.meta.dir + '/www/404.html'))
});

app.port = (process.env.PORT || 3000);
app.hostname = '0.0.0.0';


swaggerApp.listen(3001, () => console.log('Swagger listening on port 3000'))
swaggerApp.listen(3001, () => logger.info('Swagger listening on port 3000'));
app.listen();
5 changes: 5 additions & 0 deletions server/combined.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
debug: [swagger.js] [object Object]
debug: [swagger.js] [object Response]
debug: [swagger.js] function formData() {
[native code]
}
Binary file modified server/db.mmdb
Binary file not shown.
Empty file added server/error.log
Empty file.
3 changes: 2 additions & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
"bun": "^1.0.7",
"express": "^4.18.2",
"fgdb": "^1.0.0",
"fuse.js": "^7.0.0",
"geojson-rbush": "^3.2.0",
"maxmind": "^4.3.16",
"maxmind-db-reader": "^0.2.1",
"mmdb-lib": "^2.0.2",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.0",
"fuse.js": "^7.0.0"
"winston": "^3.11.0"
},
"jest": {
"testEnvironment": "node",
Expand Down
8 changes: 5 additions & 3 deletions server/scripts/gdb_to_geojson.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import fgdb from 'fgdb';
import * as fs from 'fs/promises';
import * as path from "path";
import Logger from '../util/logger';

const logger = new Logger('gdb_to_geojson.js');
const inputDir = `${import.meta.dir}/../geojson-data/indian_villages_boundaries.zip`;
const outputDir = `${import.meta.dir}/../geojson-data/indian_village_boundaries`;

Expand All @@ -20,10 +22,10 @@ const convertGDBtoGeoJSON = async (gdbFileBuffer, outputFilePath) => {
const geoJSON = await fgdb(gdbFileBuffer);
const contentToWrite = JSON.stringify(geoJSON);
await fs.writeFile(outputFilePath, contentToWrite, 'utf8');
console.log("Converted and saved:", outputFilePath);
logger.debug("Converted and saved:", outputFilePath);

} catch (error) {
console.error("Error converting GDB to GeoJSON:", error);
logger.error("Error converting GDB to GeoJSON:", error);
}
};

Expand All @@ -45,5 +47,5 @@ const processFiles = async () => {


processFiles().then(r => {
console.log("Converted all gdbs to geJSON");
logger.debug("Converted all gdbs to geJSON");
});
15 changes: 8 additions & 7 deletions server/scripts/parse.geojson.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as fs from 'fs';
import Logger from '../util/logger';


const logger = new Logger('parse.geojson.js');
const geoJsonFilesPath = `${import.meta.dir}/../geojson-data`;
let featuresLength;

console.log('Parsing INDIA_STATE');
logger.debug('Parsing INDIA_STATE');
const INDIA_STATE = JSON.parse(fs.readFileSync(`${geoJsonFilesPath}/INDIA_STATE.geojson`, 'utf8'));
featuresLength = INDIA_STATE.features.length;
for (let i = 0; i < featuresLength; i++) {
Expand All @@ -17,7 +18,7 @@ for (let i = 0; i < featuresLength; i++) {
}
fs.writeFileSync(`${geoJsonFilesPath}/INDIA_STATE.geojson`, JSON.stringify(INDIA_STATE));

console.log('Parsing INDIA_DISTRICT');
logger.debug('Parsing INDIA_DISTRICT');
const INDIA_DISTRICT = JSON.parse(fs.readFileSync(`${geoJsonFilesPath}/INDIA_DISTRICT.geojson`, 'utf8'));
featuresLength = INDIA_DISTRICT.features.length;
for (let i = 0; i < featuresLength; i++) {
Expand All @@ -29,7 +30,7 @@ for (let i = 0; i < featuresLength; i++) {
}
fs.writeFileSync(`${geoJsonFilesPath}/INDIA_DISTRICT.geojson`, JSON.stringify(INDIA_DISTRICT));

console.log('Parsing INDIA_SUBDISTRICT');
logger.debug('Parsing INDIA_SUBDISTRICT');
const INDIA_SUBDISTRICT = JSON.parse(fs.readFileSync(`${geoJsonFilesPath}/INDIA_SUBDISTRICT.geojson`, 'utf8'));
featuresLength = INDIA_SUBDISTRICT.features.length;
for (let i = 0; i < featuresLength; i++) {
Expand All @@ -42,15 +43,15 @@ for (let i = 0; i < featuresLength; i++) {
fs.writeFileSync(`${geoJsonFilesPath}/INDIA_SUBDISTRICT.geojson`, JSON.stringify(INDIA_SUBDISTRICT));


console.log('Parsing indian_village_boundaries geoJSONs')
logger.debug('Parsing indian_village_boundaries geoJSONs');
var states = fs.readdirSync(`${geoJsonFilesPath}/indian_village_boundaries/`);

for (const state of states) {
console.log(`Parsing geoJSON(s) for state ${state}`)
logger.debug(`Parsing geoJSON(s) for state ${state}`);
var stateFiles = fs.readdirSync(`${geoJsonFilesPath}/indian_village_boundaries/${state}`)
for (const file of stateFiles) {
if (!file.endsWith(`.geojson`)) continue;
console.log(`Parsing ${file}`);
logger.debug(`Parsing ${file}`);
const villagesGeoJson = JSON.parse(fs.readFileSync(`${geoJsonFilesPath}/indian_village_boundaries/${state}/${file}`));
const geoJsonLength = villagesGeoJson.features.length;
for (let i = 0; i < geoJsonLength; i++) {
Expand Down
Loading