Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
1 change: 1 addition & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2
* feat(sampler-composite): add ComposableAnnotatingSampler and ComposableRuleBasedSampler [#6305](https://github.com/open-telemetry/opentelemetry-js/pull/6305) @trentm
* feat(configuration): parse config for rc 3 [#6304](https://github.com/open-telemetry/opentelemetry-js/pull/6304) @maryliag
* feat(instrumentation): use the `internals: true` option with import-in-the-middle hook, allowing instrumentations to hook internal files in ES modules [#6344](https://github.com/open-telemetry/opentelemetry-js/pull/6344) @trentm
* feat(api-logs,sdk-logs): add log exception helpers and mapping [#6379](https://github.com/open-telemetry/opentelemetry-js/issues/6379) @iblancasa

### :bug: Bug Fixes

Expand Down
3 changes: 3 additions & 0 deletions experimental/packages/api-logs/src/NoopLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
* limitations under the License.
*/

import type { Exception } from '@opentelemetry/api';
import { Logger } from './types/Logger';
import { LogRecord } from './types/LogRecord';
import type { RecordExceptionOptions } from './types/RecordExceptionOptions';

export class NoopLogger implements Logger {
emit(_logRecord: LogRecord): void {}
recordException(_exception: Exception, _options?: RecordExceptionOptions): void {}
}

export const NOOP_LOGGER = new NoopLogger();
12 changes: 12 additions & 0 deletions experimental/packages/api-logs/src/ProxyLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
* limitations under the License.
*/

import type { Exception } from '@opentelemetry/api';
import { NOOP_LOGGER } from './NoopLogger';
import { Logger } from './types/Logger';
import { LoggerOptions } from './types/LoggerOptions';
import { LogRecord } from './types/LogRecord';
import type { RecordExceptionOptions } from './types/RecordExceptionOptions';

export class ProxyLogger implements Logger {
// When a real implementation is provided, this will be it
Expand Down Expand Up @@ -48,6 +50,16 @@ export class ProxyLogger implements Logger {
this._getLogger().emit(logRecord);
}

/**
* Record an exception as a log record.
*
* @param exception
* @param options
*/
recordException(exception: Exception, options?: RecordExceptionOptions): void {
this._getLogger().recordException(exception, options);
}

/**
* Try to get a logger from the proxy logger provider.
* If the proxy logger provider has no delegate, return a noop logger.
Expand Down
1 change: 1 addition & 0 deletions experimental/packages/api-logs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type { Logger } from './types/Logger';
export type { LoggerProvider } from './types/LoggerProvider';
export { SeverityNumber } from './types/LogRecord';
export type { LogAttributes, LogBody, LogRecord } from './types/LogRecord';
export type { RecordExceptionOptions } from './types/RecordExceptionOptions';
export type { LoggerOptions } from './types/LoggerOptions';
export type { AnyValue, AnyValueMap } from './types/AnyValue';
export { NOOP_LOGGER, NoopLogger } from './NoopLogger';
Expand Down
7 changes: 6 additions & 1 deletion experimental/packages/api-logs/src/types/LogRecord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import { Context, TimeInput } from '@opentelemetry/api';
import { Context, Exception, TimeInput } from '@opentelemetry/api';
import { AnyValue, AnyValueMap } from './AnyValue';

export type LogBody = AnyValue;
Expand Down Expand Up @@ -84,6 +84,11 @@ export interface LogRecord {
*/
attributes?: LogAttributes;

/**
* An exception (or error) associated with the log record.
*/
exception?: Exception;
Comment thread
pichlermarc marked this conversation as resolved.
Outdated

/**
* The Context associated with the LogRecord.
*/
Expand Down
10 changes: 10 additions & 0 deletions experimental/packages/api-logs/src/types/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
* limitations under the License.
*/

import type { Exception } from '@opentelemetry/api';
import { LogRecord } from './LogRecord';
import { RecordExceptionOptions } from './RecordExceptionOptions';

export interface Logger {
/**
Expand All @@ -23,4 +25,12 @@ export interface Logger {
* @param logRecord
*/
emit(logRecord: LogRecord): void;

/**
* Record an exception as a log record.
*
* @param exception
* @param options
*/
recordException(exception: Exception, options?: RecordExceptionOptions): void;
Comment thread
iblancasa marked this conversation as resolved.
Outdated
}
60 changes: 60 additions & 0 deletions experimental/packages/api-logs/src/types/RecordExceptionOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Context, TimeInput } from '@opentelemetry/api';
import { LogAttributes, LogBody, SeverityNumber } from './LogRecord';

export interface RecordExceptionOptions {
/**
* The time when the log record occurred as UNIX Epoch time in nanoseconds.
*/
timestamp?: TimeInput;

/**
* Time when the event was observed by the collection system.
*/
observedTimestamp?: TimeInput;

/**
* Numerical value of the severity.
*/
severityNumber?: SeverityNumber;

/**
* The severity text.
*/
severityText?: string;

/**
* A value containing the body of the log record.
*/
body?: LogBody;

/**
* The event name of the log record.
*/
eventName?: string;

/**
* Attributes that define the log record.
*/
attributes?: LogAttributes;

/**
* The Context associated with the LogRecord.
*/
context?: Context;
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ describe('ProxyLogger', () => {
emit() {
emitCalled = true;
},
recordException() {
emitCalled = true;
},
};

logger = provider.getLogger('test');
Expand Down
3 changes: 2 additions & 1 deletion experimental/packages/sdk-logs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
"dependencies": {
"@opentelemetry/api-logs": "0.211.0",
"@opentelemetry/core": "2.5.0",
"@opentelemetry/resources": "2.5.0"
"@opentelemetry/resources": "2.5.0",
"@opentelemetry/semantic-conventions": "^1.39.0"
Comment thread
iblancasa marked this conversation as resolved.
Outdated
}
}
47 changes: 47 additions & 0 deletions experimental/packages/sdk-logs/src/LogRecordImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,14 @@ import type {
SeverityNumber,
} from '@opentelemetry/api-logs';
import * as api from '@opentelemetry/api';
import type { Exception } from '@opentelemetry/api';
import { timeInputToHrTime, InstrumentationScope } from '@opentelemetry/core';
import type { Resource } from '@opentelemetry/resources';
import {
ATTR_EXCEPTION_MESSAGE,
ATTR_EXCEPTION_STACKTRACE,
ATTR_EXCEPTION_TYPE,
} from '@opentelemetry/semantic-conventions';
import type { ReadableLogRecord } from './export/ReadableLogRecord';
import type { LogRecordLimits } from './types';
import { isLogAttributeValue } from './utils/validation';
Expand Down Expand Up @@ -102,6 +108,7 @@ export class LogRecordImpl implements ReadableLogRecord {
severityText,
body,
attributes = {},
exception,
context,
} = logRecord;

Expand All @@ -123,6 +130,9 @@ export class LogRecordImpl implements ReadableLogRecord {
this._logRecordLimits = _sharedState.logRecordLimits;
this._eventName = eventName;
this.setAttributes(attributes);
if (exception != null) {
this._setException(exception);
}
}

public setAttribute(key: string, value?: AnyValue) {
Expand Down Expand Up @@ -180,6 +190,14 @@ export class LogRecordImpl implements ReadableLogRecord {
return this;
}

public setException(exception: Exception) {
if (this._isLogRecordReadonly()) {
return this;
}
this._setException(exception);
return this;
}

/**
* @internal
* A LogRecordProcessor may freely modify logRecord for the duration of the OnEmit call.
Expand Down Expand Up @@ -231,6 +249,35 @@ export class LogRecordImpl implements ReadableLogRecord {
return value;
}

private _setException(exception: Exception): void {
const attributes: LogAttributes = {};
if (typeof exception === 'string') {
attributes[ATTR_EXCEPTION_MESSAGE] = exception;
} else if (exception) {
if (exception.code) {
attributes[ATTR_EXCEPTION_TYPE] = exception.code.toString();
} else if (exception.name) {
attributes[ATTR_EXCEPTION_TYPE] = exception.name;
}
if (exception.message) {
attributes[ATTR_EXCEPTION_MESSAGE] = exception.message;
}
if (exception.stack) {
attributes[ATTR_EXCEPTION_STACKTRACE] = exception.stack;
}
}

if (attributes[ATTR_EXCEPTION_TYPE] || attributes[ATTR_EXCEPTION_MESSAGE]) {
for (const [key, value] of Object.entries(attributes)) {
if (!Object.prototype.hasOwnProperty.call(this.attributes, key)) {
this.setAttribute(key, value);
}
}
Comment thread
iblancasa marked this conversation as resolved.
Outdated
} else {
api.diag.warn(`Failed to record an exception ${exception}`);
}
}

private _truncateToLimitUtil(value: string, limit: number): string {
if (value.length <= limit) {
return value;
Expand Down
11 changes: 11 additions & 0 deletions experimental/packages/sdk-logs/src/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
trace,
TraceFlags,
isSpanContextValid,
Exception,
} from '@opentelemetry/api';

import { LogRecordImpl } from './LogRecordImpl';
Expand Down Expand Up @@ -108,4 +109,14 @@ export class Logger implements logsAPI.Logger {
*/
logRecordInstance._makeReadonly();
}

public recordException(
exception: Exception,
options?: logsAPI.RecordExceptionOptions
): void {
this.emit({
exception,
...options,
});
}
}
9 changes: 8 additions & 1 deletion experimental/packages/sdk-logs/src/export/SdkLogRecord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import type { HrTime, SpanContext } from '@opentelemetry/api';
import type { HrTime, SpanContext, Exception } from '@opentelemetry/api';
import { InstrumentationScope } from '@opentelemetry/core';
import type {
AnyValue,
Expand Down Expand Up @@ -88,4 +88,11 @@ export interface SdkLogRecord {
* @returns The updated SdkLogRecord.
*/
setSeverityText(severityText: string): SdkLogRecord;

/**
* Sets exception attributes based on the provided exception.
* @param exception The exception to record.
* @returns The updated SdkLogRecord.
*/
setException(exception: Exception): SdkLogRecord;
}
Loading
Loading