Skip to content

Commit

Permalink
- source maps and example logger using them
Browse files Browse the repository at this point in the history
  • Loading branch information
ezolenko committed Nov 2, 2016
1 parent ce779c3 commit 9e3dc79
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 12 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ If you believe that some rules should not apply to a part of your code, you can

**More info about TSLint:** https://palantir.github.io/tslint/

### Source maps

Works out of the box with "npm run deploy-prod" and default values from src/config/config.example.ts.

Currently maps are generated, but "source-maps" module doesn't get uploaded for non-webpack builds.

![Console output example](/console.png "Console output example")

## Contributing

Expand Down
Binary file added console.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 26 additions & 2 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const ts = require('gulp-typescript');
const tslint = require('gulp-tslint');
const tsProject = ts.createProject('tsconfig.json', { typescript: require('typescript') });
const webpack = require('webpack-stream');
const sourcemaps = require('gulp-sourcemaps');
const through = require('through2');

/********/
/* INIT */
Expand Down Expand Up @@ -90,6 +92,19 @@ gulp.task('compile-bundled', gulp.series(gulp.parallel('lint', 'clean'), functio
const webpackConfig = require('./webpack.config.js');
return gulp.src('src/main.ts')
.pipe(webpack(webpackConfig))
.pipe(through.obj(function (file, enc, cb)
{
// Source maps are JSON files with a single object.
// Screeps server takes only *.js files, require() expects .js files to be modules and export something, so turning it into module with one export: "d".
// If we could name it *.json, this wouldn't be needed.
var isSourceMap = /\.map.js$/.test(file.path);
if (isSourceMap)
{
file._contents = Buffer.concat([Buffer.from("module.exports.d=", 'utf-8'), file._contents]);
}
this.push(file);
cb();
}))
.pipe(gulp.dest('dist/' + buildTarget));
}));

Expand All @@ -98,9 +113,12 @@ gulp.task('compile-flattened', gulp.series(
function tsc() {
global.compileFailed = false;
return tsProject.src()
.pipe(sourcemaps.init())
.pipe(tsProject())
.on('error', (err) => global.compileFailed = true)
.js.pipe(gulp.dest('dist/tmp'));
.on('error', (err) => global.compileFailed = true).js
.pipe(sourcemaps.write("."))
.pipe(gulp.dest('dist/tmp'))
;
},
function checkTsc(done) {
if (!global.compileFailed) {
Expand All @@ -110,7 +128,13 @@ gulp.task('compile-flattened', gulp.series(
},
function flatten() {
return gulp.src('dist/tmp/**/*.js')
.pipe(sourcemaps.init( { loadMaps: true } ))
.pipe(gulpDotFlatten(0))
.pipe(sourcemaps.write(".",
{
includeContent: false,
mapFile: f => { return f.replace('.js.map', '.map.js'); },
}))
.pipe(gulp.dest('dist/' + buildTarget));
}
));
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,20 @@
"gulp-rename": "^1.2.2",
"gulp-tslint": "^6.0.1",
"gulp-typescript": "^3.0.0",
"gulp-sourcemaps": "^2.2.0",
"gulp-util": "^3.0.7",
"jshint": "^2.9.2",
"lodash": "^4.14.0",
"q": "^1.4.1",
"recast": "^0.11.10",
"through2": "^2.0.1",
"ts-loader": "^0.8.2",
"source-map-loader": "^0.1.5",
"tslint": "^3.13.0",
"typescript": "^2.0.3",
"typings": "^1.3.0",
"webpack": "^1.13.1",
"webpack-stream": "^3.2.0"
"webpack-stream": "^3.2.0",
"source-map": "^0.5.6"
}
}
3 changes: 2 additions & 1 deletion src/components/rooms/baseRoom.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Config from "../../config/config";
import { log } from "../support/log";

/**
* The base class for Rooms.
Expand Down Expand Up @@ -66,7 +67,7 @@ export class BaseRoom {
*/
protected setBodyParts(role: string): string[] | undefined {
if (this.debug) {
console.log("[BaseRoom.setBodyParts] Current role:", role);
log.debug("[BaseRoom.setBodyParts] Current role:", role);
}

if (role === "harvester") {
Expand Down
11 changes: 6 additions & 5 deletions src/components/rooms/controlledRoom.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BaseRoom } from "./baseRoom";
import { Harvester } from "../creeps/roles/harvester";
import { log } from "../support/log";

/**
* Rooms that the player controls. Includes scripts necessary to run all tasks
Expand Down Expand Up @@ -43,7 +44,7 @@ export class ControlledRoom extends BaseRoom {
});

if (this.debug) {
console.log("[ControlledRoom.loadCreeps] " + this.creepCount + " creeps found in the playground.");
log.debug("[ControlledRoom.loadCreeps] " + this.creepCount + " creeps found in the playground.");
}
}

Expand All @@ -56,7 +57,7 @@ export class ControlledRoom extends BaseRoom {

if (this.debug) {
if (spawns[0]) {
console.log("[ControlledRoom.buildMissingCreeps] Spawn: " + spawns[0].name);
log.debug("[ControlledRoom.buildMissingCreeps] Spawn: " + spawns[0].name);
}
}

Expand Down Expand Up @@ -93,13 +94,13 @@ export class ControlledRoom extends BaseRoom {
if (body) {
let status: number | string = spawn.createCreep(body, name, properties);
if (typeof status === "string") {
console.log("Started creating new Creep in room " + spawn.room.name);
log.debug("Started creating new Creep in room " + spawn.room.name);
Memory.uuid++;
} else if (status !== -6) {
console.log("Failed to spawn creep in room " + spawn.room.name + ":", status, "[" + role + "]");
log.error("Failed to spawn creep in room " + spawn.room.name + ":", status, "[" + role + "]");
}
} else {
console.log("Failed to spawn creep in room " + spawn.room.name + ":", "unknown body part", "[" + role + "]");
log.error("Failed to spawn creep in room " + spawn.room.name + ":", "unknown body part", "[" + role + "]");
}
}

Expand Down
142 changes: 142 additions & 0 deletions src/components/support/log.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
export class Log {
public static ERROR = 0;
public static WARNING = 1;
public static INFO = 2;
public static DEBUG = 3;

public static loadSourceMap() {
try {
// tslint:disable-next-line
var SourceMapConsumer = require("source-map").SourceMapConsumer;
const map = require("main.js.map").d;
if (map) {
Log.sourceMap = new SourceMapConsumer(map);
}
} catch (err) {
console.log(err);
}
}

private static sourceMap: any;
private static stackLineRe = /([^ ]*) \(([^:]*):([0-9]*):([0-9]*)\)/;
private static color(str: string, color: string): string {
return "<font color='" + color + "'>" + str + "</font>";
}
private static tooltip(str: string, tooltip: string): string {
return "<abbr title='" + tooltip + "'>" + str + "</abbr>";
}

public level: number = Log.ERROR;
public showSource: boolean = true;
public decorateLine: boolean = true;
private maxFileString: number = 0;

public trace(error: Error): Log {
if (this.level >= Log.ERROR && error.stack) {
console.log(this.resolveStack(error.stack));
}

return this;
}

public error(...args: any[]) {
if (this.level >= Log.ERROR) {
console.log.apply(this,
[
Log.color("ERROR ", "red"),
this.time(),
this.getFileLine(),
].concat([].slice.call(args)));
}
}

public warning(...args: any[]) {
if (this.level >= Log.WARNING) {
console.log.apply(this,
[
Log.color("WARNING", "yellow"),
this.time(),
this.getFileLine(),
].concat([].slice.call(args)));
}
}

public info(...args: any[]) {
if (this.level >= Log.INFO) {
console.log.apply(this,
[
Log.color("INFO ", "green"),
this.time(),
this.getFileLine(),
].concat([].slice.call(args)));
}
}

public debug(...args: any[]) {
if (this.level >= Log.DEBUG) {
console.log.apply(this,
[
Log.color("DEBUG ", "gray"),
this.time(),
this.getFileLine(),
].concat([].slice.call(args)));
}
}

public getFileLine(upStack = 3): string {
if (!this.showSource) {
return "";
}

let stack = new Error("").stack;
if (stack) {
let lines = stack.split("\n");
if (lines.length > upStack) {
lines = this.resolveLines(_.drop(lines, upStack));
return Log.tooltip(Log.color(this.adjustFileLine(lines[0]), "gray"), lines.join("&#10;"));
}
}
return "";
}

public time(): string {
return Log.color(Game.time.toString(), "gray");
}

private resolve(fileLine: string): string {
let split = _.trim(fileLine).match(Log.stackLineRe);
if (!split) {
return fileLine;
}

let pos = { column: parseInt(split[4], 10), line: parseInt(split[3], 10) };

let original = Log.sourceMap.originalPositionFor(pos);
return split[1] + " (" + original.source + ":" + original.line + ")";
}

private resolveStack(stack: string): string {
if (!Log.sourceMap) {
return stack;
}

return stack.split("\n").map(this.resolve).join("\n");
}

private resolveLines(lines: Array<string>): Array<string> {
if (!Log.sourceMap) {
return lines;
}

return lines.map(this.resolve);
}

private adjustFileLine(line: string): string {
let newPad = Math.max(line.length, this.maxFileString);
this.maxFileString = Math.min(newPad, 100);

return _.padRight(line, this.maxFileString, " ");
}
}

export var log = new Log();
13 changes: 13 additions & 0 deletions src/config/config.example.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Log } from "../components/support/log";

/**
* Enable this if you want a lot of text to be logged to console.
* @type {boolean}
Expand All @@ -14,3 +16,14 @@ export const USE_PATHFINDER: boolean = true;
* @type {number}
*/
export const DEFAULT_MIN_LIFE_BEFORE_NEEDS_REFILL: number = 700;

export const LOG_LEVEL: number = Log.DEBUG;

// To print file/line number for each log entry. Slow, disable when not needed.
export const LOG_PRINT_LINES: boolean = true;

// To load source map and resolve file/line to original typescript source.
// Slow and doubles script size.
// Currently works only with prod deployments because depends on webpack
// to stream in "source-map" node module
export const LOG_LOAD_SOURCE_MAP: boolean = true;
2 changes: 2 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
interface Memory {
uuid: number;
}

declare function require(path: string): any;
15 changes: 14 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import * as Config from "./config/config";
import { ControlledRoom } from "./components/rooms/controlledRoom";

import { log, Log } from "./components/support/log";

log.showSource = Config.LOG_PRINT_LINES;
if (Config.LOG_LOAD_SOURCE_MAP) {
Log.loadSourceMap();
}

if (Config.LOG_LEVEL) {
log.level = Config.LOG_LEVEL;
}

// This is an example for using a config variable from `config.ts`.
if (Config.USE_PATHFINDER) {
PathFinder.use(true);
}

log.info("load");

/**
* This function is executed *every tick*.
*
Expand Down Expand Up @@ -35,7 +48,7 @@ export function loop() {

if (creep.room === room.name) {
if (!Game.creeps[name]) {
console.log("Clearing non-existing creep memory:", name);
log.info("Clearing non-existing creep memory:", name);
delete Memory.creeps[name];
}
}
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"experimentalDecorators": true,
"strictNullChecks": true,
"noUnusedParameters": true,
"noUnusedLocals": true
"noUnusedLocals": true,
"sourceMap": true
},
"compileOnSave": false,
"include": [
Expand Down
Loading

0 comments on commit 9e3dc79

Please sign in to comment.