зеркало из https://github.com/microsoft/napajs.git
Merged PR 282183: Add support for logging providers
Add support for logging providers
This commit is contained in:
Родитель
f92c2e4b3f
Коммит
f6026033b5
|
@ -3,20 +3,30 @@
|
|||
#include <iostream>
|
||||
#include <exception>
|
||||
|
||||
#define NAPA_ASSERT(condition, message) do { \
|
||||
if (!(condition)) { \
|
||||
std::cerr << "Assertion failed: `" \
|
||||
<< #condition \
|
||||
<< "`, file " \
|
||||
<< __FILE__ \
|
||||
<< ", line " \
|
||||
<< __LINE__ \
|
||||
<< " : " \
|
||||
<< message \
|
||||
<< "." \
|
||||
<< std::endl; \
|
||||
std::terminate(); \
|
||||
} \
|
||||
#include <stdarg.h>
|
||||
|
||||
/// <summary> The maximum message length of a single assert call. Anything over will be truncated. </summary>
|
||||
static constexpr size_t MAX_ASSERT_MESSAGE_SIZE = 512;
|
||||
|
||||
inline void OutputAssertMessage(const char* condition, const char* file, int line, const char* format, ...) {
|
||||
char message[MAX_ASSERT_MESSAGE_SIZE];
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int size = vsnprintf(message, MAX_ASSERT_MESSAGE_SIZE, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (size >= 0) {
|
||||
std::cerr << "Assertion failed: `" << condition << "`, file " << file << ", line " << line
|
||||
<< " : " << message << "." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#define NAPA_ASSERT(condition, format, ...) do { \
|
||||
if (!(condition)) { \
|
||||
OutputAssertMessage(#condition, __FILE__, __LINE__, format, __VA_ARGS__); \
|
||||
std::terminate(); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define NAPA_FAIL(message) NAPA_ASSERT(false, message)
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa/exports.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace napa {
|
||||
|
@ -7,7 +9,7 @@ namespace providers {
|
|||
|
||||
/// <summary> Enumeration of metric type. </summary>
|
||||
enum class MetricType {
|
||||
Number,
|
||||
Number = 0,
|
||||
Rate,
|
||||
Percentile,
|
||||
};
|
||||
|
@ -94,7 +96,8 @@ namespace providers {
|
|||
/// The IMetric class returned is owned and cached by this class.
|
||||
/// Callers are not required to call destroy() on the Metric.
|
||||
/// </remarks>
|
||||
virtual Metric* GetMetric(const char* section,
|
||||
virtual Metric* GetMetric(
|
||||
const char* section,
|
||||
const char* name,
|
||||
MetricType type,
|
||||
size_t dimensions,
|
||||
|
@ -109,6 +112,9 @@ namespace providers {
|
|||
virtual ~MetricProvider() = default;
|
||||
};
|
||||
|
||||
/// <summary> Exports a getter function for retrieves the configured metric provider. </summary>
|
||||
NAPA_API MetricProvider& GetMetricProvider();
|
||||
|
||||
typedef MetricProvider* (*CreateMetricProvider)();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { log } from './log';
|
||||
import * as memory from './memory';
|
||||
import * as metric from './metric';
|
||||
import * as runtime from './runtime';
|
||||
import * as transport from './transport';
|
||||
import * as zone from './zone';
|
||||
|
||||
export { memory, runtime, transport, zone };
|
||||
export { log, memory, metric, runtime, transport, zone };
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
let binding = require('./binding');
|
||||
|
||||
export interface LogFunction {
|
||||
(message: string): void;
|
||||
(section: string, message: string): void;
|
||||
(section: string, traceId: string, message: string): void;
|
||||
}
|
||||
|
||||
export interface Log extends LogFunction {
|
||||
err(message: string): void;
|
||||
err(section: string, message: string): void;
|
||||
err(section: string, traceId: string, message: string): void;
|
||||
|
||||
warn(message: string): void;
|
||||
warn(section: string, message: string): void;
|
||||
warn(section: string, traceId: string, message: string): void;
|
||||
|
||||
info(message: string): void;
|
||||
info(section: string, message: string): void;
|
||||
info(section: string, traceId: string, message: string): void;
|
||||
|
||||
debug(message: string): void;
|
||||
debug(section: string, message: string): void;
|
||||
debug(section: string, traceId: string, message: string): void;
|
||||
}
|
||||
|
||||
export let log: Log = createLogObject();
|
||||
|
||||
enum LogLevel {
|
||||
Error = 0,
|
||||
Warning = 1,
|
||||
Info = 2,
|
||||
Debug = 3,
|
||||
}
|
||||
|
||||
function dispatchLog(level: LogLevel, arg1: string, arg2?: string, arg3?: string) {
|
||||
if (arg3 != undefined) {
|
||||
binding.log(level, arg1, arg2, arg3);
|
||||
}
|
||||
else if (arg2 != undefined) {
|
||||
binding.log(level, arg1, undefined, arg2);
|
||||
}
|
||||
else {
|
||||
binding.log(level, undefined, undefined, arg1);
|
||||
}
|
||||
}
|
||||
|
||||
function createLogObject() : Log {
|
||||
// napa.log()
|
||||
let logObj: any = function(arg1: string, arg2?: string, arg3?: string) {
|
||||
dispatchLog(LogLevel.Info, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
// napa.log.err()
|
||||
logObj.err = function(arg1: string, arg2?: string, arg3?: string) {
|
||||
dispatchLog(LogLevel.Error, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
// napa.log.warn()
|
||||
logObj.warn = function(arg1: string, arg2?: string, arg3?: string) {
|
||||
dispatchLog(LogLevel.Warning, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
// napa.log.info()
|
||||
logObj.info = function(arg1: string, arg2?: string, arg3?: string) {
|
||||
dispatchLog(LogLevel.Info, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
// napa.log.debug()
|
||||
logObj.debug = function(arg1: string, arg2?: string, arg3?: string) {
|
||||
dispatchLog(LogLevel.Debug, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
return logObj;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
let binding = require('./binding');
|
||||
|
||||
export enum MetricType {
|
||||
Number = 0,
|
||||
Rate,
|
||||
Percentile,
|
||||
}
|
||||
|
||||
export interface Metric {
|
||||
section: string;
|
||||
name: string;
|
||||
|
||||
set(value: number, dimensions?: string[]): void;
|
||||
increment(value: number, dimensions?: string[]): void;
|
||||
decrement(value: number, dimensions?: string[]): void;
|
||||
}
|
||||
|
||||
/// <summary> A cache for metric wraps. </summary>
|
||||
var _metricsCache: { [key: string]: Metric } = {};
|
||||
|
||||
export function get(section: string, name: string, type: MetricType, dimensions: string[] = []) : Metric {
|
||||
let key: string = (section ? section : "") + "_" + (name ? name : "");
|
||||
|
||||
// Check cache first
|
||||
let metricWrap: Metric = _metricsCache[key];
|
||||
if (metricWrap) {
|
||||
return metricWrap;
|
||||
}
|
||||
|
||||
// Add to cache
|
||||
metricWrap = new binding.MetricWrap(section, name, type, dimensions);
|
||||
metricWrap.section = section;
|
||||
metricWrap.name = name;
|
||||
_metricsCache[key] = metricWrap;
|
||||
|
||||
return metricWrap;
|
||||
}
|
|
@ -29,6 +29,7 @@ export function setPlatformSettings(settings: PlatformSettings) {
|
|||
}
|
||||
|
||||
_platformSettings = settings;
|
||||
initialize();
|
||||
}
|
||||
|
||||
export function initialize() {
|
||||
|
|
|
@ -19,6 +19,7 @@ export function create(id: string, settings?: zone.ZoneSettings) : zone.Zone {
|
|||
|
||||
/// <summary> Returns the zone associated with the provided id. </summary>
|
||||
export function get(id: string) : zone.Zone {
|
||||
platform.initialize();
|
||||
if (id === "node") {
|
||||
return new node.NodeZone();
|
||||
}
|
||||
|
@ -30,6 +31,7 @@ export function get(id: string) : zone.Zone {
|
|||
export declare let current: zone.Zone;
|
||||
Object.defineProperty(exports, "current", {
|
||||
get: function () : zone.Zone {
|
||||
platform.initialize();
|
||||
if (typeof __in_napa !== 'undefined') {
|
||||
return new napa.NapaZone(binding.getCurrentZone());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "napa-binding.h"
|
||||
|
||||
#include "napa-wraps/metric-wrap.h"
|
||||
#include "napa-wraps/allocator-debugger-wrap.h"
|
||||
#include "napa-wraps/allocator-wrap.h"
|
||||
#include "napa-wraps/shared-ptr-wrap.h"
|
||||
|
@ -11,7 +12,8 @@
|
|||
#include <napa-memory.h>
|
||||
#include <napa/module/binding/wraps.h>
|
||||
#include <napa/module/worker-context.h>
|
||||
|
||||
#include <napa/providers/logging.h>
|
||||
#include <napa/providers/metric.h>
|
||||
|
||||
using namespace napa;
|
||||
using namespace napa::module;
|
||||
|
@ -133,12 +135,59 @@ static void GetDefaultAllocator(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|||
args.GetReturnValue().Set(binding::CreateAllocatorWrap(NAPA_MAKE_SHARED<napa::memory::DefaultAllocator>()));
|
||||
}
|
||||
|
||||
static void Log(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
CHECK_ARG(isolate, args.Length() == 4, "log accepts exactly 4 arguments (level, section, traceId, message)");
|
||||
CHECK_ARG(isolate, args[0]->IsUint32(), "'level' must be a uint32 type that represents the native enum");
|
||||
CHECK_ARG(isolate, args[1]->IsString() || args[1]->IsUndefined(), "'section' must be a valid string or undefined");
|
||||
|
||||
auto level = static_cast<napa::providers::LoggingProvider::Verboseness>(args[0]->Uint32Value());
|
||||
|
||||
napa::v8_helpers::Utf8String sectionValue;
|
||||
const char* section = "";
|
||||
if (!args[1]->IsUndefined()) {
|
||||
sectionValue = napa::v8_helpers::V8ValueTo<napa::v8_helpers::Utf8String>(args[1]);
|
||||
section = sectionValue.Length() > 0 ? sectionValue.Data() : "";
|
||||
}
|
||||
|
||||
auto& logger = napa::providers::GetLoggingProvider();
|
||||
|
||||
// If log is not enabled we can return early.
|
||||
if (!logger.IsLogEnabled(section, level)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_ARG(isolate, args[2]->IsString() || args[2]->IsUndefined(), "'traceId' must be a valid string or undefined");
|
||||
CHECK_ARG(isolate, args[3]->IsString(), "'message' must be a valid string");
|
||||
|
||||
napa::v8_helpers::Utf8String traceIdValue;
|
||||
const char* traceId = "";
|
||||
if (!args[2]->IsUndefined()) {
|
||||
traceIdValue = napa::v8_helpers::V8ValueTo<napa::v8_helpers::Utf8String>(args[2]);
|
||||
traceId = traceIdValue.Length() > 0 ? traceIdValue.Data() : "";
|
||||
}
|
||||
|
||||
v8::String::Utf8Value message(args[3]->ToString());
|
||||
|
||||
// Get the first frame in user code.
|
||||
// The first 2 frames are part of the log.js file.
|
||||
auto stackFrame = v8::StackTrace::CurrentStackTrace(isolate, 3)->GetFrame(2);
|
||||
|
||||
v8::String::Utf8Value file(stackFrame->GetScriptName());
|
||||
int line = stackFrame->GetLineNumber();
|
||||
|
||||
logger.LogMessage(section, level, traceId, *file, line, *message);
|
||||
}
|
||||
|
||||
void binding::Init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module) {
|
||||
// Register napa binding in worker context.
|
||||
RegisterBinding(module);
|
||||
|
||||
AllocatorDebuggerWrap::Init();
|
||||
AllocatorWrap::Init();
|
||||
MetricWrap::Init();
|
||||
SharedPtrWrap::Init();
|
||||
StoreWrap::Init();
|
||||
TransportContextWrapImpl::Init();
|
||||
|
@ -146,6 +195,7 @@ void binding::Init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module)
|
|||
|
||||
NAPA_EXPORT_OBJECTWRAP(exports, "AllocatorDebuggerWrap", AllocatorDebuggerWrap);
|
||||
NAPA_EXPORT_OBJECTWRAP(exports, "AllocatorWrap", AllocatorWrap);
|
||||
NAPA_EXPORT_OBJECTWRAP(exports, "MetricWrap", MetricWrap);
|
||||
NAPA_EXPORT_OBJECTWRAP(exports, "SharedPtrWrap", SharedPtrWrap);
|
||||
NAPA_EXPORT_OBJECTWRAP(exports, "TransportContextWrap", TransportContextWrapImpl);
|
||||
|
||||
|
@ -160,4 +210,6 @@ void binding::Init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module)
|
|||
|
||||
NAPA_SET_METHOD(exports, "getCrtAllocator", GetCrtAllocator);
|
||||
NAPA_SET_METHOD(exports, "getDefaultAllocator", GetDefaultAllocator);
|
||||
|
||||
NAPA_SET_METHOD(exports, "log", Log);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
#include "metric-wrap.h"
|
||||
|
||||
using namespace napa::module;
|
||||
using namespace napa::v8_helpers;
|
||||
|
||||
NAPA_DEFINE_PERSISTENT_CONSTRUCTOR(MetricWrap);
|
||||
|
||||
void MetricWrap::Init() {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
|
||||
// Prepare constructor template.
|
||||
auto functionTemplate = v8::FunctionTemplate::New(isolate, ConstructorCallback);
|
||||
functionTemplate->SetClassName(MakeV8String(isolate, _exportName));
|
||||
functionTemplate->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
|
||||
// Prototypes.
|
||||
NAPA_SET_PROTOTYPE_METHOD(functionTemplate, "set", Set);
|
||||
NAPA_SET_PROTOTYPE_METHOD(functionTemplate, "increment", Increment);
|
||||
NAPA_SET_PROTOTYPE_METHOD(functionTemplate, "decrement", Decrement);
|
||||
|
||||
// Set persistent constructor into V8.
|
||||
NAPA_SET_PERSISTENT_CONSTRUCTOR(_exportName, functionTemplate->GetFunction());
|
||||
}
|
||||
|
||||
MetricWrap::MetricWrap(napa::providers::Metric* metric, uint32_t dimensions) :
|
||||
_metric(metric), _dimensions(dimensions) {
|
||||
}
|
||||
|
||||
void MetricWrap::ConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
JS_ENSURE(isolate, args.IsConstructCall(), "class \"MetricWrap\" allows constructor call only.");
|
||||
|
||||
CHECK_ARG(isolate, args.Length() == 4,
|
||||
"class \"MetricWrap\" accepts exactly 4 arguments (section, name, type, dimensions)");
|
||||
CHECK_ARG(isolate, args[0]->IsString(), "'section' must be a valid string");
|
||||
CHECK_ARG(isolate, args[1]->IsString(), "'name' must be a valid string");
|
||||
CHECK_ARG(isolate, args[2]->IsUint32(), "'type' must be a uint32 type that represents the native enum");
|
||||
CHECK_ARG(isolate, args[3]->IsArray(), "'dimensions' must be a valid array");
|
||||
|
||||
auto section = V8ValueTo<Utf8String>(args[0]);
|
||||
auto name = V8ValueTo<Utf8String>(args[1]);
|
||||
auto type = static_cast<napa::providers::MetricType>(args[2]->Uint32Value());
|
||||
|
||||
// Holds te dimensions strings on the stack for the GetMetric call.
|
||||
auto dimensionsStringsHolder = V8ArrayToVector<Utf8String>(isolate, v8::Local<v8::Array>::Cast(args[3]));
|
||||
|
||||
std::vector<const char*> dimensions;
|
||||
dimensions.reserve(dimensionsStringsHolder.size());
|
||||
for (const auto& dimension : dimensionsStringsHolder) {
|
||||
dimensions.emplace_back(dimension.Data());
|
||||
}
|
||||
|
||||
auto& metricProvider = napa::providers::GetMetricProvider();
|
||||
auto metric = metricProvider.GetMetric(section.Data(), name.Data(), type, dimensions.size(), dimensions.data());
|
||||
|
||||
auto wrap = new MetricWrap(metric, static_cast<uint32_t>(dimensions.size()));
|
||||
|
||||
wrap->Wrap(args.This());
|
||||
args.GetReturnValue().Set(args.This());
|
||||
}
|
||||
|
||||
void MetricWrap::Set(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
CHECK_ARG(isolate, args[0]->IsUint32(), "'value' argument must be a valid Uint32");
|
||||
auto value = args[0]->Uint32Value();
|
||||
|
||||
InvokeWithDimensions(args, 1, [value](napa::providers::Metric* metric, std::vector<const char*>& dimensions) {
|
||||
metric->Set(value, dimensions.size(), dimensions.data());
|
||||
});
|
||||
}
|
||||
|
||||
void MetricWrap::Increment(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
InvokeWithDimensions(args, 0, [](napa::providers::Metric* metric, std::vector<const char*>& dimensions) {
|
||||
metric->Increment(1, dimensions.size(), dimensions.data());
|
||||
});
|
||||
}
|
||||
|
||||
void MetricWrap::Decrement(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
InvokeWithDimensions(args, 0, [](napa::providers::Metric* metric, std::vector<const char*>& dimensions) {
|
||||
metric->Decrement(1, dimensions.size(), dimensions.data());
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void MetricWrap::InvokeWithDimensions(const v8::FunctionCallbackInfo<v8::Value>& args, uint32_t index, Func&& func) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto dimensionsArg = args[index];
|
||||
CHECK_ARG(isolate, dimensionsArg->IsArray() || dimensionsArg->IsUndefined(), "'dimensions' must be an array or undefined");
|
||||
|
||||
auto wrap = NAPA_OBJECTWRAP::Unwrap<MetricWrap>(args.Holder());
|
||||
|
||||
// Holds the dimensions strings on the stack for so it exists during the call to func.
|
||||
std::vector<napa::v8_helpers::Utf8String> dimensionsStringsHolder;
|
||||
|
||||
std::vector<const char*> dimensions;
|
||||
if (dimensionsArg->IsArray() && wrap->_dimensions > 0) {
|
||||
auto arr = v8::Local<v8::Array>::Cast(dimensionsArg);
|
||||
JS_ENSURE(
|
||||
isolate,
|
||||
wrap->_dimensions == arr->Length(),
|
||||
"the dimensions count does not match. expected: %d, received: %d",
|
||||
wrap->_dimensions,
|
||||
arr->Length());
|
||||
|
||||
dimensionsStringsHolder = napa::v8_helpers::V8ArrayToVector<napa::v8_helpers::Utf8String>(isolate, arr);
|
||||
|
||||
dimensions.reserve(dimensionsStringsHolder.size());
|
||||
for (const auto& dimension : dimensionsStringsHolder) {
|
||||
dimensions.emplace_back(dimension.Data());
|
||||
}
|
||||
} else {
|
||||
JS_ENSURE(isolate, wrap->_dimensions == 0, "expected %s dimensions but received 0", wrap->_dimensions);
|
||||
}
|
||||
|
||||
func(wrap->_metric, dimensions);
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa-module.h>
|
||||
#include <napa/module/common.h>
|
||||
#include <napa/providers/metric.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace napa {
|
||||
namespace module {
|
||||
|
||||
/// <summary> An object wrap to expose metric APIs. </summary>
|
||||
class MetricWrap : public NAPA_OBJECTWRAP {
|
||||
public:
|
||||
|
||||
|
||||
|
||||
/// <summary> Initializes the wrap. </summary>
|
||||
static void Init();
|
||||
|
||||
/// <summary> Create a new MetricWrap instance that wraps the provided metric. </summary>
|
||||
static v8::Local<v8::Object> NewInstance(napa::providers::Metric* metric, uint32_t dimensions);
|
||||
|
||||
/// <summary> Declare persistent constructor to create Metric Javascript wrapper instance. </summary>
|
||||
NAPA_DECLARE_PERSISTENT_CONSTRUCTOR;
|
||||
|
||||
private:
|
||||
|
||||
/// <summary> The underlying metric. </summary>
|
||||
napa::providers::Metric* _metric;
|
||||
|
||||
/// <summary> Exported class name. </summary>
|
||||
static constexpr const char* _exportName = "MetricWrap";
|
||||
|
||||
/// <summary> Number of dimensions this metric expects. </summary>
|
||||
uint32_t _dimensions;
|
||||
|
||||
/// <summary> Constructor. </summary>
|
||||
MetricWrap(napa::providers::Metric* metric, uint32_t dimensions);
|
||||
|
||||
/// <summary> MetricWrap.constructor </summary>
|
||||
static void ConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
// MetricWrap getters
|
||||
static void NameGetter(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
static void SectionGetter(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value>& args);
|
||||
|
||||
// MetricWrap methods
|
||||
static void Set(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Increment(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Decrement(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that extracts the dimensions and metric from args and calls the func
|
||||
/// with these arguments.
|
||||
/// </summary>
|
||||
template <typename Func>
|
||||
static void InvokeWithDimensions(const v8::FunctionCallbackInfo<v8::Value>& args, uint32_t index, Func&& func);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\allocator-debugger-wrap.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\allocator-wrap.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\metric-wrap.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\shared-ptr-wrap.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\store-wrap.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\transport-context-wrap-impl.cpp" />
|
||||
|
|
|
@ -18,7 +18,11 @@ namespace providers {
|
|||
const char* file,
|
||||
int line,
|
||||
const char* message) override {
|
||||
printf("[%s] %s [%s:%d]\n", section, message, file, line);
|
||||
if (section == nullptr || section[0] == '\0') {
|
||||
printf("%s [%s:%d]\n", message, file, line);
|
||||
} else {
|
||||
printf("[%s] %s [%s:%d]\n", section, message, file, line);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool IsLogEnabled(const char* section, Verboseness level) override {
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace napa {
|
|||
namespace providers {
|
||||
|
||||
///<summary> A no-operation instance of a Metric. </summary>
|
||||
class NoOpMetric : public Metric {
|
||||
class NopMetric : public Metric {
|
||||
public:
|
||||
|
||||
bool Set(int64_t, size_t, const char*[]) override {
|
||||
|
@ -31,7 +31,7 @@ namespace providers {
|
|||
{
|
||||
public:
|
||||
|
||||
NopMetricProvider() : _defaultMetric(new NoOpMetric()) {}
|
||||
NopMetricProvider() : _defaultMetric(new NopMetric()) {}
|
||||
|
||||
Metric* GetMetric(const char*, const char*, MetricType, size_t, const char**) override {
|
||||
return _defaultMetric;
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
#include "nop-logging-provider.h"
|
||||
#include "nop-metric-provider.h"
|
||||
|
||||
#include "module/module-resolver.h"
|
||||
|
||||
#include <napa-log.h>
|
||||
|
||||
#include <boost/dll.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
@ -18,19 +20,14 @@ using namespace napa::providers;
|
|||
static LoggingProvider* LoadLoggingProvider(const std::string& providerName);
|
||||
static MetricProvider* LoadMetricProvider(const std::string& providerName);
|
||||
|
||||
// Providers.
|
||||
static LoggingProvider* _loggingProvider = nullptr;
|
||||
static MetricProvider* _metricProvider = nullptr;
|
||||
// Providers - Initilally assigned to defaults.
|
||||
static LoggingProvider* _loggingProvider = LoadLoggingProvider("");
|
||||
static MetricProvider* _metricProvider = LoadMetricProvider("");
|
||||
|
||||
|
||||
bool napa::providers::Initialize(const napa::PlatformSettings& settings) {
|
||||
try {
|
||||
_loggingProvider = LoadLoggingProvider(settings.loggingProvider);
|
||||
_metricProvider = LoadMetricProvider(settings.metricProvider);
|
||||
} catch (std::exception& ex) {
|
||||
std::cerr << "Error occurred while loading providers: " << ex.what() << "\n";
|
||||
return false;
|
||||
}
|
||||
_loggingProvider = LoadLoggingProvider(settings.loggingProvider);
|
||||
_metricProvider = LoadMetricProvider(settings.metricProvider);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -46,38 +43,67 @@ void napa::providers::Shutdown() {
|
|||
}
|
||||
|
||||
LoggingProvider& napa::providers::GetLoggingProvider() {
|
||||
NAPA_ASSERT(_loggingProvider, "logging provider not set");
|
||||
return *_loggingProvider;
|
||||
}
|
||||
|
||||
MetricProvider& napa::providers::GetMetricProvider() {
|
||||
NAPA_ASSERT(_metricProvider, "metric provider not set");
|
||||
return *_metricProvider;
|
||||
}
|
||||
|
||||
template <typename ProviderType>
|
||||
static ProviderType* LoadProvider(const std::string& providerName, const std::string& functionName) {
|
||||
// TODO @asib: resolve path to shared library given the provider name, need to use module loader APIs.
|
||||
auto createProviderFunc = boost::dll::import<ProviderType*()>(providerName, functionName);
|
||||
static ProviderType* LoadProvider(
|
||||
const std::string& providerName,
|
||||
const std::string& jsonProperyPath,
|
||||
const std::string& functionName) {
|
||||
|
||||
napa::module::ModuleResolver moduleResolver;
|
||||
|
||||
// Resolve the provider module information
|
||||
auto moduleInfo = moduleResolver.Resolve(providerName.c_str());
|
||||
NAPA_ASSERT(!moduleInfo.packageJsonPath.empty(), "missing package.json in provider '%s'", providerName.c_str());
|
||||
|
||||
// Full path to the root of the provider module
|
||||
auto modulePath = boost::filesystem::path(moduleInfo.packageJsonPath).parent_path();
|
||||
|
||||
// Extract relative path to provider dll from package.json
|
||||
boost::property_tree::ptree package;
|
||||
boost::property_tree::json_parser::read_json(moduleInfo.packageJsonPath, package);
|
||||
auto providerRelativePath = package.get_optional<std::string>(jsonProperyPath);
|
||||
NAPA_ASSERT(
|
||||
providerRelativePath.is_initialized(),
|
||||
"missing property '%s' in '%s'",
|
||||
jsonProperyPath.c_str(),
|
||||
moduleInfo.packageJsonPath.c_str());
|
||||
|
||||
// Full path to provider dll
|
||||
auto providerPath = (modulePath / providerRelativePath.get()).normalize().make_preferred();
|
||||
|
||||
// boost::dll unloads dll when a reference object is gone.
|
||||
// Keep a static instance for each provider type (each template type will have its own static variable).
|
||||
static auto createProviderFunc = boost::dll::import<ProviderType*()>(providerPath, functionName);
|
||||
|
||||
return createProviderFunc();
|
||||
}
|
||||
|
||||
static LoggingProvider* LoadLoggingProvider(const std::string& providerName) {
|
||||
if (providerName.empty() || providerName == "nop") {
|
||||
return new NopLoggingProvider();
|
||||
if (providerName.empty() || providerName == "console") {
|
||||
static auto consoleLoggingProvider = std::make_unique<ConsoleLoggingProvider>();
|
||||
return consoleLoggingProvider.get();
|
||||
}
|
||||
|
||||
if (providerName == "console") {
|
||||
return new ConsoleLoggingProvider();
|
||||
if (providerName == "nop") {
|
||||
static auto nopLoggingProvider = std::make_unique<NopLoggingProvider>();
|
||||
return nopLoggingProvider.get();
|
||||
}
|
||||
|
||||
return LoadProvider<LoggingProvider>(providerName, "CreateLoggingProvider");
|
||||
return LoadProvider<LoggingProvider>(providerName, "providers.logging", "CreateLoggingProvider");
|
||||
}
|
||||
|
||||
static MetricProvider* LoadMetricProvider(const std::string& providerName) {
|
||||
if (providerName.empty()) {
|
||||
return new NopMetricProvider();
|
||||
static auto nopMetricProvider = std::make_unique<NopMetricProvider>();
|
||||
return nopMetricProvider.get();
|
||||
}
|
||||
|
||||
return LoadProvider<MetricProvider>(providerName, "CreateMetricProvider");;
|
||||
return LoadProvider<MetricProvider>(providerName, "providers.metric", "CreateMetricProvider");;
|
||||
}
|
||||
|
|
|
@ -14,11 +14,5 @@ namespace providers {
|
|||
|
||||
/// <summary> Clean up and destroy all loaded providers. </summary>
|
||||
void Shutdown();
|
||||
|
||||
/// <summary> Returns the logging provider. </summary>
|
||||
LoggingProvider& GetLoggingProvider();
|
||||
|
||||
/// <summary> Returns the metric provider. </summary>
|
||||
MetricProvider& GetMetricProvider();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<QCustomProjectReference Include="$(NapaVanillaRoot)\package\napajs.proj" />
|
||||
<QCustomProjectReference Include="test-provider\package\test-provider.proj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QCustomInput Include="$(NapaBuildRoot)\**\*" />
|
||||
|
@ -38,6 +39,12 @@
|
|||
</ItemGroup>
|
||||
<Copy SourceFiles="@(RuntimeFiles)" DestinationFiles="@(RuntimeFiles->'$(PackageOutPath)\%(RecursiveDir)%(Filename)%(Extension)')" ContinueOnError="false" SkipUnchangedFiles="true" />
|
||||
|
||||
<Message Text="Prepare 'test-provider'' runtime files." />
|
||||
<ItemGroup>
|
||||
<TestProviderFiles Include="test-provider\package\$(IntermediateOutputPath)\node_modules\test-provider\**\*.*"/>
|
||||
</ItemGroup>
|
||||
<Copy SourceFiles="@(TestProviderFiles)" DestinationFiles="@(TestProviderFiles->'$(IntermediateOutputPath)\node_modules\test-provider\%(RecursiveDir)%(Filename)%(Extension)')" ContinueOnError="false" SkipUnchangedFiles="true" />
|
||||
|
||||
</Target>
|
||||
<Import Project="$(ExtendedTargetsPath)\NoTarget.targets" />
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
import * as napa from "napajs";
|
||||
import * as assert from "assert";
|
||||
import * as path from "path";
|
||||
|
||||
// Require this module to verify logging was done correctly
|
||||
var testProvider = require('test-provider');
|
||||
|
||||
napa.runtime.setPlatformSettings({
|
||||
loggingProvider: "test-provider",
|
||||
metricProvider: "test-provider"
|
||||
});
|
||||
|
||||
let zone: napa.zone.Zone = napa.zone.create('napa-zone1', { workers: 1});
|
||||
|
||||
describe('napajs/logging', function () {
|
||||
|
||||
it('@node: default log', () => {
|
||||
napa.log("test");
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test');
|
||||
assert.strictEqual(testProvider.lastLog.level, 2 /* LogLevel.Info */);
|
||||
});
|
||||
|
||||
it('@napa: default log', () => {
|
||||
zone.broadcastSync(() => {
|
||||
var napa = require('napajs');
|
||||
napa.log("test-from-napa");
|
||||
}, []);
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test-from-napa');
|
||||
assert.strictEqual(testProvider.lastLog.level, 2 /* LogLevel.Info */);
|
||||
});
|
||||
|
||||
it('@node: log with section', () => {
|
||||
napa.log("test-section", "test");
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test');
|
||||
assert.strictEqual(testProvider.lastLog.section, "test-section");
|
||||
});
|
||||
|
||||
it('@napa: log with section', () => {
|
||||
zone.broadcastSync(() => {
|
||||
var napa = require('napajs');
|
||||
napa.log("test-section", "test-from-napa");
|
||||
}, []);
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test-from-napa');
|
||||
assert.strictEqual(testProvider.lastLog.section, "test-section");
|
||||
});
|
||||
|
||||
it('@node: log with section and trace id', () => {
|
||||
napa.log("test-section", "trace-id", "test");
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test');
|
||||
assert.strictEqual(testProvider.lastLog.section, "test-section");
|
||||
assert.strictEqual(testProvider.lastLog.traceId, 'trace-id');
|
||||
});
|
||||
|
||||
it('@napa: log with section and trace id', () => {
|
||||
zone.broadcastSync(() => {
|
||||
var napa = require('napajs');
|
||||
napa.log("test-section", "trace-id", "test-from-napa");
|
||||
}, []);
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test-from-napa');
|
||||
assert.strictEqual(testProvider.lastLog.section, "test-section");
|
||||
assert.strictEqual(testProvider.lastLog.traceId, 'trace-id');
|
||||
});
|
||||
|
||||
it('@node: log with verbosity', () => {
|
||||
napa.log.err("test0");
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test0');
|
||||
assert.strictEqual(testProvider.lastLog.level, 0 /* LogLevel.Error */);
|
||||
|
||||
napa.log.warn("test1");
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test1');
|
||||
assert.strictEqual(testProvider.lastLog.level, 1 /* LogLevel.Warning */);
|
||||
|
||||
napa.log.info("test2");
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test2');
|
||||
assert.strictEqual(testProvider.lastLog.level, 2 /* LogLevel.Information */);
|
||||
|
||||
napa.log.debug("test3");
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test3');
|
||||
assert.strictEqual(testProvider.lastLog.level, 3 /* LogLevel.Debug */);
|
||||
});
|
||||
|
||||
it('@napa: log with verbosity', () => {
|
||||
zone.broadcastSync(() => { var napa = require('napajs'); napa.log.err("test-from-napa0"); }, []);
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test-from-napa0');
|
||||
assert.strictEqual(testProvider.lastLog.level, 0 /* LogLevel.Error */);
|
||||
|
||||
zone.broadcastSync(() => { var napa = require('napajs'); napa.log.warn("test-from-napa1"); }, []);
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test-from-napa1');
|
||||
assert.strictEqual(testProvider.lastLog.level, 1 /* LogLevel.Warning */);
|
||||
|
||||
zone.broadcastSync(() => { var napa = require('napajs'); napa.log.info("test-from-napa2"); }, []);
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test-from-napa2');
|
||||
assert.strictEqual(testProvider.lastLog.level, 2 /* LogLevel.Information */);
|
||||
|
||||
zone.broadcastSync(() => { var napa = require('napajs'); napa.log.debug("test-from-napa3"); }, []);
|
||||
assert.strictEqual(testProvider.lastLog.message, 'test-from-napa3');
|
||||
assert.strictEqual(testProvider.lastLog.level, 3 /* LogLevel.Debug */);
|
||||
});
|
||||
});
|
||||
|
||||
describe('napajs/metric', function () {
|
||||
|
||||
it('@node: get metric', () => {
|
||||
let metric = napa.metric.get("section1", "name1", napa.metric.MetricType.Number);
|
||||
assert.strictEqual(metric.section, 'section1');
|
||||
assert.strictEqual(metric.name, 'name1');
|
||||
});
|
||||
|
||||
it('@napa: get metric', () => {
|
||||
zone.broadcastSync(() => {
|
||||
var napa = require('napajs');
|
||||
var metric = napa.metric.get("section2", "name2", napa.metric.MetricType.Number) ;
|
||||
metric.set(24);
|
||||
}, []);
|
||||
|
||||
assert.strictEqual(testProvider.lastMetricValue, 24);
|
||||
});
|
||||
|
||||
it('@node: get metric from cache (per isolate)', () => {
|
||||
let metric = napa.metric.get("section3", "name3", napa.metric.MetricType.Number);
|
||||
metric.set(7);
|
||||
metric = napa.metric.get("section3", "name3", napa.metric.MetricType.Number);
|
||||
assert.strictEqual(testProvider.lastMetricValue, 7);
|
||||
});
|
||||
|
||||
it('@napa: get metric from cache (per isolate)', () => {
|
||||
zone.broadcastSync(() => {
|
||||
var napa = require('napajs');
|
||||
let metric = napa.metric.get("section4", "name4", napa.metric.MetricType.Number);
|
||||
metric.set(15);
|
||||
metric = napa.metric.get("section4", "name4", napa.metric.MetricType.Number);
|
||||
metric.increment();
|
||||
}, []);
|
||||
|
||||
assert.strictEqual(testProvider.lastMetricValue, 16);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<AddonType>Napa</AddonType>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\node\addon.vcxproj" />
|
||||
</Project>
|
|
@ -0,0 +1,46 @@
|
|||
#include <napa-module.h>
|
||||
#include <napa/v8-helpers.h>
|
||||
|
||||
#include "logging-provider.h"
|
||||
#include "metric-provider.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace napa::v8_helpers;
|
||||
|
||||
void LastLogGetter(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
|
||||
auto& lastLog = TestLoggingProvider::GetInstance().GetLastLog();
|
||||
|
||||
auto obj = v8::Object::New(isolate);
|
||||
|
||||
obj->CreateDataProperty(context, MakeV8String(isolate, "section"), MakeV8String(isolate, lastLog.section));
|
||||
obj->CreateDataProperty(context, MakeV8String(isolate, "message"), MakeV8String(isolate, lastLog.message));
|
||||
obj->CreateDataProperty(context, MakeV8String(isolate, "traceId"), MakeV8String(isolate, lastLog.traceId));
|
||||
obj->CreateDataProperty(context, MakeV8String(isolate, "file"), MakeV8String(isolate, lastLog.file));
|
||||
obj->CreateDataProperty(context, MakeV8String(isolate, "line"), v8::Integer::New(isolate, lastLog.line));
|
||||
|
||||
auto level = static_cast<uint32_t>(lastLog.level);
|
||||
obj->CreateDataProperty(context, MakeV8String(isolate, "level"),v8::Uint32::NewFromUnsigned(isolate, level));
|
||||
|
||||
args.GetReturnValue().Set(obj);
|
||||
}
|
||||
|
||||
static void LastMetricValueGetter(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value>& args) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto value = TestMetricProvider::GetInstance().GetLastMetric()->GetValue();
|
||||
|
||||
args.GetReturnValue().Set(static_cast<int32_t>(value));
|
||||
}
|
||||
|
||||
void InitAll(v8::Local<v8::Object> exports) {
|
||||
exports->SetAccessor(MakeV8String(v8::Isolate::GetCurrent(), "lastLog"), LastLogGetter);
|
||||
exports->SetAccessor(MakeV8String(v8::Isolate::GetCurrent(), "lastMetricValue"), LastMetricValueGetter);
|
||||
}
|
||||
|
||||
NAPA_MODULE(addon, InitAll);
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(EnvironmentConfig)" />
|
||||
<Import Project="$(ExtendedTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AddonName>addon</AddonName>
|
||||
<TargetName Condition=" '$(AddonType)' != 'Napa' ">$(AddonName)</TargetName>
|
||||
<TargetName Condition=" '$(AddonType)' == 'Napa' ">$(AddonName)_napa</TargetName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(ExtendedTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions Condition=" '$(AddonType)' != 'Napa' ">BUILDING_NODE_EXTENSION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition=" '$(AddonType)' == 'Napa' ">BUILDING_NAPA_EXTENSION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(NapaVanillaRoot)\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\src\test-provider.vcxproj" />
|
||||
<ProjectReference Include="$(NapaVanillaRoot)\src\napa.vcxproj" Condition=" '$(AddonType)' == 'Napa' " />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)\addon.cpp" />
|
||||
</ItemGroup>
|
||||
<Target Name="ChangeExtention" AfterTargets="Build">
|
||||
<Move SourceFiles="$(OutputPath)\$(TargetFileName)" DestinationFiles="$(OutputPath)\$(AddonName).node" Condition=" '$(AddonType)' != 'Napa' " />
|
||||
<Move SourceFiles="$(OutputPath)\$(TargetFileName)" DestinationFiles="$(OutputPath)\$(AddonName).napa" Condition=" '$(AddonType)' == 'Napa' " />
|
||||
</Target>
|
||||
<Import Project="$(Pkgnapa_nodelib_vc140)\exports_node.props" Condition=" '$(AddonType)' != 'Napa' " />
|
||||
<Import Project="$(Pkgnapa_nodelib_vc140)\exports_v8_includes.props" Condition=" '$(AddonType)' == 'Napa' " />
|
||||
<Import Project="$(ExtendedTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "test-provider",
|
||||
"version": "0.1.0",
|
||||
"author": "napajs",
|
||||
"main": "./bin/addon",
|
||||
"providers": {
|
||||
"logging": "./bin/test-provider.dll",
|
||||
"metric": "./bin/test-provider.dll"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(EnvironmentConfig)" />
|
||||
|
||||
<!-- These targets must be built before the package -->
|
||||
<ItemGroup>
|
||||
<QCustomProjectReference Include="..\src\test-provider.vcxproj" />
|
||||
<QCustomProjectReference Include="..\napa\addon.vcxproj" />
|
||||
<QCustomProjectReference Include="..\node\addon.vcxproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageOutPath>$(IntermediateOutputPath)\node_modules\test-provider</PackageOutPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="CreateNpmPackage" AfterTargets="AfterBuild">
|
||||
<Message Text="Create NPM package." />
|
||||
|
||||
<!-- Setup package root directory -->
|
||||
<Copy SourceFiles="..\package.json" DestinationFolder="$(PackageOutPath)" ContinueOnError="false" SkipUnchangedFiles="true" />
|
||||
|
||||
<!-- Setup ./bin directory-->
|
||||
<!-- Binplace napa binaries -->
|
||||
<Copy SourceFiles="..\src\$(IntermediateOutputPath)\test-provider.dll" DestinationFolder="$(PackageOutPath)\bin" ContinueOnError="false" SkipUnchangedFiles="true" />
|
||||
<Copy SourceFiles="..\napa\$(IntermediateOutputPath)\addon.napa" DestinationFolder="$(PackageOutPath)\bin" ContinueOnError="false" SkipUnchangedFiles="true" />
|
||||
<Copy SourceFiles="..\node\$(IntermediateOutputPath)\addon.node" DestinationFolder="$(PackageOutPath)\bin" ContinueOnError="false" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
|
||||
<Import Project="$(ExtendedTargetsPath)\NoTarget.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,37 @@
|
|||
#include "logging-provider.h"
|
||||
|
||||
using namespace napa::providers;
|
||||
|
||||
TestLoggingProvider& TestLoggingProvider::GetInstance() {
|
||||
static TestLoggingProvider instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
const LogEntry& TestLoggingProvider::GetLastLog() const {
|
||||
return _lastLog;
|
||||
}
|
||||
|
||||
void TestLoggingProvider::LogMessage(
|
||||
const char* section,
|
||||
Verboseness level,
|
||||
const char* traceId,
|
||||
const char* file,
|
||||
int line,
|
||||
const char* message) {
|
||||
_lastLog = { section, level, traceId, file, line, message };
|
||||
}
|
||||
|
||||
bool TestLoggingProvider::IsLogEnabled(const char *, Verboseness) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestLoggingProvider::Destroy() {
|
||||
// Singleton
|
||||
}
|
||||
|
||||
|
||||
// Export a function for creating the test logging provider
|
||||
EXTERN_C NAPA_API LoggingProvider* CreateLoggingProvider() {
|
||||
return &TestLoggingProvider::GetInstance();
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa/providers/logging.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
struct LogEntry {
|
||||
std::string section;
|
||||
napa::providers::LoggingProvider::Verboseness level;
|
||||
std::string traceId;
|
||||
std::string file;
|
||||
int line;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
class TestLoggingProvider : public napa::providers::LoggingProvider {
|
||||
public:
|
||||
|
||||
NAPA_API static TestLoggingProvider& GetInstance();
|
||||
|
||||
NAPA_API const LogEntry& GetLastLog() const;
|
||||
|
||||
void LogMessage(
|
||||
const char* section,
|
||||
Verboseness level,
|
||||
const char* traceId,
|
||||
const char* file,
|
||||
int line,
|
||||
const char* message) override;
|
||||
|
||||
bool IsLogEnabled(const char *, Verboseness) override;
|
||||
|
||||
void Destroy() override;
|
||||
|
||||
private:
|
||||
|
||||
LogEntry _lastLog;
|
||||
|
||||
TestLoggingProvider() = default;
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
#include "metric-provider.h"
|
||||
|
||||
using namespace napa::providers;
|
||||
|
||||
TestMetric::TestMetric() : _value(0) {
|
||||
}
|
||||
|
||||
bool TestMetric::Set(int64_t value, size_t, const char*[]) {
|
||||
_value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestMetric::Increment(uint64_t value, size_t, const char*[]) {
|
||||
_value += value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestMetric::Decrement(uint64_t value, size_t, const char*[]) {
|
||||
_value -= value;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestMetric::Destroy() {
|
||||
delete this;
|
||||
}
|
||||
|
||||
int64_t TestMetric::GetValue() const {
|
||||
return _value;
|
||||
}
|
||||
|
||||
|
||||
TestMetricProvider& TestMetricProvider::GetInstance() {
|
||||
static TestMetricProvider instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
Metric* TestMetricProvider::GetMetric(const char*, const char*, MetricType, size_t, const char*[]) {
|
||||
_metrics.emplace_back(TestMetric());
|
||||
return &_metrics.back();
|
||||
}
|
||||
|
||||
const TestMetric* TestMetricProvider::GetLastMetric() const {
|
||||
return &_metrics.back();
|
||||
}
|
||||
|
||||
void TestMetricProvider::Destroy() {
|
||||
// Singleton
|
||||
}
|
||||
|
||||
// Export a function for creating the test metric provider
|
||||
EXTERN_C NAPA_API MetricProvider* CreateMetricProvider() {
|
||||
return &TestMetricProvider::GetInstance();
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <napa/providers/metric.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class TestMetric : public napa::providers::Metric {
|
||||
public:
|
||||
|
||||
explicit TestMetric();
|
||||
|
||||
bool Set(int64_t value, size_t, const char*[]) override;
|
||||
|
||||
bool Increment(uint64_t value, size_t, const char*[]) override;
|
||||
|
||||
bool Decrement(uint64_t value, size_t, const char*[]) override;
|
||||
|
||||
void Destroy() override;
|
||||
|
||||
NAPA_API int64_t GetValue() const;
|
||||
|
||||
private:
|
||||
int64_t _value;
|
||||
};
|
||||
|
||||
class TestMetricProvider : public napa::providers::MetricProvider {
|
||||
public:
|
||||
|
||||
NAPA_API static TestMetricProvider& GetInstance();
|
||||
|
||||
NAPA_API const TestMetric* GetLastMetric() const;
|
||||
|
||||
napa::providers::Metric* GetMetric(
|
||||
const char* section,
|
||||
const char* name,
|
||||
napa::providers::MetricType type,
|
||||
size_t dimensions,
|
||||
const char* dimensionNames[]) override;
|
||||
|
||||
void Destroy() override;
|
||||
|
||||
private:
|
||||
std::vector<TestMetric> _metrics;
|
||||
|
||||
TestMetricProvider() = default;
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(EnvironmentConfig)" />
|
||||
<Import Project="$(ExtendedTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(ExtendedTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NAPA_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(NapaVanillaRoot)\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="logging-provider.cpp" />
|
||||
<ClCompile Include="metric-provider.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(ExtendedTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
Загрузка…
Ссылка в новой задаче