diff --git a/cherrypick/lib/src/log_format.dart b/cherrypick/lib/src/log_format.dart deleted file mode 100644 index 4cf1f88..0000000 --- a/cherrypick/lib/src/log_format.dart +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright 2021 Sergey Penkovsky (sergey.penkovsky@gmail.com) -// 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. -// - - -/// Formats a log message string for CherryPick's logging system. -/// -/// This function provides a unified structure for framework logs (info, warn, error, debug, etc.), -/// making it easier to parse and analyze events related to DI operations such as resolving bindings, -/// scope creation, module installation, etc. -/// -/// All parameters except [name] and [params] are required. -/// -/// Example: -/// ```dart -/// final msg = formatLogMessage( -/// type: 'Binding', -/// name: 'MyService', -/// params: {'parent': 'AppModule', 'lifecycle': 'singleton'}, -/// description: 'created', -/// ); -/// // Result: [Binding:MyService] parent=AppModule lifecycle=singleton created -/// ``` -/// -/// Parameters: -/// - [type]: The type of the log event subject (e.g., 'Binding', 'Scope', 'Module'). Required. -/// - [name]: Optional name of the subject (binding/scope/module) to disambiguate multiple instances/objects. -/// - [params]: Optional map for additional context (e.g., id, parent, lifecycle, named, etc.). -/// - [description]: Concise description of the event. Required. -/// -/// Returns a structured string: -/// [type(:name)] param1=val1 param2=val2 ... description -String formatLogMessage({ - required String type, // Binding, Scope, Module, ... - String? name, // Имя binding/scope/module - Map? params, // Дополнительные параметры (id, parent, named и др.) - required String description, // Краткое описание события -}) { - final label = name != null ? '$type:$name' : type; - final paramsStr = (params != null && params.isNotEmpty) - ? params.entries.map((e) => '${e.key}=${e.value}').join(' ') - : ''; - return '[$label]' - '${paramsStr.isNotEmpty ? ' $paramsStr' : ''}' - ' $description'; -} diff --git a/cherrypick/lib/src/observer.dart b/cherrypick/lib/src/observer.dart index 130b031..93718d3 100644 --- a/cherrypick/lib/src/observer.dart +++ b/cherrypick/lib/src/observer.dart @@ -1,31 +1,148 @@ -/// Observer for DI container (CherryPick): lifecycle, cache, modules, errors, etc. +// +// Copyright 2021 Sergey Penkovsky (sergey.penkovsky@gmail.com) +// 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. +// + +/// An abstract Observer for CherryPick DI container events. +/// +/// Extend this class to react to and log various events inside the CherryPick Dependency Injection container. +/// Allows monitoring of registration, creation, disposal, module changes, cache hits/misses, cycles, and +/// errors/warnings for improved diagnostics and debugging. +/// +/// All methods have detailed event information, including name, type, scope, and other arguments. +/// +/// Example: Logging and debugging container events +/// ```dart +/// final CherryPickObserver observer = PrintCherryPickObserver(); +/// // Pass observer to CherryPick during setup +/// CherryPick.openRootScope(observer: observer); +/// ``` abstract class CherryPickObserver { // === Registration and instance lifecycle === + /// Called when a binding is registered within the container (new dependency mapping). + /// + /// Example: + /// ```dart + /// observer.onBindingRegistered('MyService', MyService, scopeName: 'root'); + /// ``` void onBindingRegistered(String name, Type type, {String? scopeName}); + + /// Called when an instance is requested (before it is created or retrieved from cache). + /// + /// Example: + /// ```dart + /// observer.onInstanceRequested('MyService', MyService, scopeName: 'root'); + /// ``` void onInstanceRequested(String name, Type type, {String? scopeName}); + + /// Called when a new instance is successfully created. + /// + /// Example: + /// ```dart + /// observer.onInstanceCreated('MyService', MyService, instance, scopeName: 'root'); + /// ``` void onInstanceCreated(String name, Type type, Object instance, {String? scopeName}); + + /// Called when an instance is disposed (removed from cache and/or finalized). + /// + /// Example: + /// ```dart + /// observer.onInstanceDisposed('MyService', MyService, instance, scopeName: 'root'); + /// ``` void onInstanceDisposed(String name, Type type, Object instance, {String? scopeName}); // === Module events === + /// Called when modules are installed into the container. + /// + /// Example: + /// ```dart + /// observer.onModulesInstalled(['NetworkModule', 'RepositoryModule'], scopeName: 'root'); + /// ``` void onModulesInstalled(List moduleNames, {String? scopeName}); + + /// Called when modules are removed from the container. + /// + /// Example: + /// ```dart + /// observer.onModulesRemoved(['RepositoryModule'], scopeName: 'root'); + /// ``` void onModulesRemoved(List moduleNames, {String? scopeName}); // === Scope lifecycle === + /// Called when a new DI scope is opened (for example, starting a new feature or screen). + /// + /// Example: + /// ```dart + /// observer.onScopeOpened('user-session'); + /// ``` void onScopeOpened(String name); + + /// Called when an existing DI scope is closed. + /// + /// Example: + /// ```dart + /// observer.onScopeClosed('user-session'); + /// ``` void onScopeClosed(String name); // === Cycle detection === + /// Called if a dependency cycle is detected during resolution. + /// + /// Example: + /// ```dart + /// observer.onCycleDetected(['A', 'B', 'C', 'A'], scopeName: 'root'); + /// ``` void onCycleDetected(List chain, {String? scopeName}); // === Cache events === + /// Called when an instance is found in the cache. + /// + /// Example: + /// ```dart + /// observer.onCacheHit('MyService', MyService, scopeName: 'root'); + /// ``` void onCacheHit(String name, Type type, {String? scopeName}); + + /// Called when an instance is not found in the cache and should be created. + /// + /// Example: + /// ```dart + /// observer.onCacheMiss('MyService', MyService, scopeName: 'root'); + /// ``` void onCacheMiss(String name, Type type, {String? scopeName}); - // === Диагностика === + // === Diagnostic === + /// Used for custom diagnostic and debug messages. + /// + /// Example: + /// ```dart + /// observer.onDiagnostic('Cache cleared', details: detailsObj); + /// ``` void onDiagnostic(String message, {Object? details}); // === Warnings & errors === + /// Called on non-fatal, recoverable DI container warnings. + /// + /// Example: + /// ```dart + /// observer.onWarning('Binding override', details: {...}); + /// ``` void onWarning(String message, {Object? details}); + + /// Called on error (typically exceptions thrown during resolution, instantiation, or disposal). + /// + /// Example: + /// ```dart + /// observer.onError('Failed to resolve dependency', errorObj, stackTraceObj); + /// ``` void onError(String message, Object? error, StackTrace? stackTrace); } @@ -86,7 +203,7 @@ class PrintCherryPickObserver implements CherryPickObserver { } } -/// Silent observer: игнорирует все события +/// Silent observer: ignores all events class SilentCherryPickObserver implements CherryPickObserver { @override void onBindingRegistered(String name, Type type, {String? scopeName}) {}