From 158ea89e3ddb847385a238f2fff7aa7027992181 Mon Sep 17 00:00:00 2001 From: Esha Noronha Date: Mon, 17 Mar 2025 09:12:47 +0100 Subject: [PATCH 1/3] Updated article to make it more clear --- .../fundamentals/backoffice/logviewer.md | 59 +++++++++---------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/13/umbraco-cms/fundamentals/backoffice/logviewer.md b/13/umbraco-cms/fundamentals/backoffice/logviewer.md index f133689d46a..431ac71707e 100644 --- a/13/umbraco-cms/fundamentals/backoffice/logviewer.md +++ b/13/umbraco-cms/fundamentals/backoffice/logviewer.md @@ -4,7 +4,7 @@ description: Information on using the Umbraco log viewer # Log Viewer -Umbraco ships with a built-in Log Viewer feature. This allows you to filter and view log entries and perform much more complex search queries. This helps you find the log entries that you are interested in. You can find the Log viewer in the Settings section. +Umbraco ships with a built-in Log Viewer feature. This allows you to filter, view log entries, perform complex search queries, and analyze logs for debugging. You can find the Log viewer in the **Settings** section of the Umbraco backoffice. {% embed url="https://youtu.be/PDqIRVygAQ4?t=102" %} Learn how to use the Log Viewer to read and understand logs for your Umbraco CMS website. @@ -12,37 +12,37 @@ Learn how to use the Log Viewer to read and understand logs for your Umbraco CMS ## Benefits -Have you ever wanted to find all log entries which contain the same request ID? Or find all items in the log where a property called duration is greater than 1000ms? +Ever needed to find all log entries containing the same request ID? Or locate all logs where a property called `Duration` exceeds 1000ms? -With the power of structured logging and a query language, we are able to search and find log items for specific scenarios. When debugging the site you should now have more power to see and find patterns in your log files and get rid of those errors. +With structured logging and a query language, you can efficiently search and identify log items for specific scenarios. This helps in debugging and finding patterns in your logs, making it easier to resolve issues. -## Example queries +## Example Queries -Here are a handful of example queries to get you started, however, the saved searches contain some further examples. For more details on the syntax head over to the https://github.com/serilog/serilog-filters-expressions project. +Here are some example queries to help you get started. For more details on the syntax, see the https://github.com/serilog/serilog-filters-expressions project. -**Find all logs that are from the namespace 'Umbraco.Core'**\ -`StartsWith(SourceContext, 'Umbraco.Core')`\\ +**Find all logs that are from the namespace 'Umbraco.Core'** +`StartsWith(SourceContext, 'Umbraco.Core')` -**Find all logs that have the property 'Duration' and the duration is greater than 1000ms**\ -`Has(Duration) and Duration > 1000`\\ +**Find all logs that have the property 'Duration' and the duration is greater than 1000ms** +`Has(Duration) and Duration > 1000` -**Find all logs where the message has localhost in it with SQL like**\ -`@Message like '%localhost%'`\\ +**Find all logs where the message has localhost in it with SQL like** +`@Message like '%localhost%'` ## Saved Searches -Sometimes you want to use a custom query more often. It is possible to save a query and use the dropdown to re-use your saved search. To add a new saved search, use the search box to type your query and click the star icon. In doing so you can give it a friendly name. The saved queries are saved in the database in the table `umbracoLogViewerQuery`. +If you frequently use a custom query, you can save it for quick access. Type your query in the search box and click the heart icon to save it with a friendly name. Saved queries are stored in the `umbracoLogViewerQuery` table in the database. -## Implementing your own Log Viewer +## Implementing Your Own Log Viewer -With the flexibility of Umbraco, we give you the power to implement your own `ILogViewer`. This makes it possible to fetch logs and the saved searches from a different location such as Azure table storage. +Umbraco allows you to implement a customn `ILogViewer` to fetch logs from alternative sources, such as **Azure Table Storage**. -### Create your own implementation +### Creating a Custom Log Viewer -To do this we can implement a base class `SerilogLogViewerSourceBase` from `Umbraco.Cms.Core.Logging.Viewer` like so. +To fetch logs from Azure Table Storage, implement the `SerilogLogViewerSourceBase` class from `Umbraco.Cms.Core.Logging.Viewer`. {% hint style="info" %} -This uses the `Azure.Data.Tables` NuGet package. +This implementation requires the `Azure.Data.Tables` NuGet package. {% endhint %} ```csharp @@ -70,6 +70,7 @@ public class AzureTableLogViewer : SerilogLogViewerSourceBase protected override IReadOnlyList GetLogs(LogTimePeriod logTimePeriod, ILogFilter filter, int skip, int take) { + //Replace ACCOUNT_NAME and KEY with your actual Azure Storage Account details. The "Logs" parameter refers to the table name where logs will be stored and retrieved from. var client = new TableClient( "DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=KEY;EndpointSuffix=core.windows.net", @@ -93,19 +94,19 @@ public class AzureTableLogViewer : SerilogLogViewerSourceBase public override IReadOnlyList? GetSavedSearches() { - // Optional: If you want to store saved searches in the Azure Table Storage, implement here a method to fetch from the Azure Table. + //This method is optional. If you store saved searches in Azure Table Storage, implement fetching logic here. return base.GetSavedSearches(); } public override IReadOnlyList? AddSavedSearch(string? name, string? query) { - //Optional: If you want to store saved searches in the Azure Table Storage, implement here a method to add to the Azure Table. + //This method is optional. If you store saved searches in Azure Table Storage, implement adding logic here. return base.AddSavedSearch(name, query); } public override IReadOnlyList? DeleteSavedSearch(string? name, string? query) { - //Optional: If you want to store saved searches in the Azure Table Storage, implement here a method to remove from the Azure Table. + //This method is optional. If you store saved searches in Azure Table Storage, implement deleting logic here. return base.DeleteSavedSearch(name, query); } } @@ -118,7 +119,7 @@ public class AzureTableLogEntity : LogEventEntity, ITableEntity } ``` -Keep in mind that we have to implement our own version of a `LogEventEntity`. This is because the `TableClient` needs whatever it is fetching to implement the `ITableEntity` interface. +Azure Table Storage requires entities to implement the `ITableEntity` interface. Since Umbraco’s default log entity does not implement this, a custom entity (`AzureTableLogEntity`) must be created to ensure logs are correctly fetched and stored. ### Register implementation @@ -136,14 +137,14 @@ public class LogViewerSavedSearches : IComposer } ``` -### Configure Umbraco to log into Azure Table Storage +### Configuring Logging to Azure Table Storage -Now with the above two classes, we have the plumbing in place to view logs from an Azure Table. However, we are not persisting our logs into the Azure table storage account. So we need to configure the Serilog logging pipeline to store our logs in Azure table storage. +With the above two classes, the setup is in place to view logs from an Azure Table. However, logs are not yet persisted into the Azure Table Storage account. To enable persistence, configure the Serilog logging pipeline to store logs in Azure Table Storage. -* Install Serilog.Sinks.AzureTableStorage from Nuget -* Add a new sink to the appsettings with credentials (so logs persist to Azure) +* Install `Serilog.Sinks.AzureTableStorage` from NuGet. +* Add a new sink to `appsettings.json` with credentials to persist logs to Azure. -The following sink needs to be added to the array [`Serilog:WriteTo`](https://github.com/serilog/serilog-sinks-azuretablestorage#json-configuration). +The following sink needs to be added to the [`Serilog:WriteTo`](https://github.com/serilog/serilog-sinks-azuretablestorage#json-configuration) array. ```json { @@ -155,10 +156,8 @@ The following sink needs to be added to the array [`Serilog:WriteTo`](https://gi } ``` -For more in-depth information about logging and how to configure it, please read the [logging documentation](../code/debugging/logging.md). +For more in-depth information about logging and how to configure it, see the [Logging](../code/debugging/logging.md) article. ### Compact Log Viewer - Desktop App -This is a desktop tool for viewing & querying JSON log files from disk in the same way as the built-in logviewer dashboard of Umbraco. - -[English badge](https://www.microsoft.com/store/apps/9N8RV8LKTXRJ?cid=storebadge\&ocid=badge) +[Compact Log Viewer](https://www.microsoft.com/store/apps/9N8RV8LKTXRJ?cid=storebadge\&ocid=badge) - A desktop tool is available for viewing and querying JSON log files in the same way as the built-in Log Viewer in Umbraco. From c3180cb86d5631d468e45a85dbeeca882f8c79a1 Mon Sep 17 00:00:00 2001 From: Esha Noronha <82437098+eshanrnh@users.noreply.github.com> Date: Tue, 18 Mar 2025 09:12:45 +0100 Subject: [PATCH 2/3] Update 13/umbraco-cms/fundamentals/backoffice/logviewer.md Co-authored-by: sofietoft --- 13/umbraco-cms/fundamentals/backoffice/logviewer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/13/umbraco-cms/fundamentals/backoffice/logviewer.md b/13/umbraco-cms/fundamentals/backoffice/logviewer.md index 431ac71707e..6ab8a08ad26 100644 --- a/13/umbraco-cms/fundamentals/backoffice/logviewer.md +++ b/13/umbraco-cms/fundamentals/backoffice/logviewer.md @@ -160,4 +160,4 @@ For more in-depth information about logging and how to configure it, see the [Lo ### Compact Log Viewer - Desktop App -[Compact Log Viewer](https://www.microsoft.com/store/apps/9N8RV8LKTXRJ?cid=storebadge\&ocid=badge) - A desktop tool is available for viewing and querying JSON log files in the same way as the built-in Log Viewer in Umbraco. +[Compact Log Viewer](https://www.microsoft.com/store/apps/9N8RV8LKTXRJ?cid=storebadge\&ocid=badge). A desktop tool is available for viewing and querying JSON log files in the same way as the built-in Log Viewer in Umbraco. From 6348632da6f55fa02fdf58d4f711cb5ee08fad9d Mon Sep 17 00:00:00 2001 From: Esha Noronha Date: Tue, 18 Mar 2025 10:47:02 +0100 Subject: [PATCH 3/3] Added more information and updated layout of the article --- .../extending-overview/extension-kind.md | 29 +++--- .../extension-types/kind.md | 92 +++++++++++++------ 2 files changed, 78 insertions(+), 43 deletions(-) diff --git a/15/umbraco-cms/customizing/extending-overview/extension-kind.md b/15/umbraco-cms/customizing/extending-overview/extension-kind.md index 32dbe0443bd..7d6b711c1c9 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-kind.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-kind.md @@ -8,29 +8,29 @@ description: Learn how to use the Kind extension in your manifest files when ext This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. {% endhint %} -Extension Manifest Kind enables declarations to be based upon a preset Manifest. +The **Extension Manifest Kind** is used to declare a preset configuration that other extensions can inherit. It ensures maintainability and consistency when creating extensions for the Umbraco CMS backoffice. By using a Kind, developers can reuse predefined settings, which reduces redundancy across extensions. -This is used for maintainability or to inherit existing features. +When a Kind is applied, the extension's manifest inherits the fields defined in the Kind. This approach prevents the need to repeat configuration details across multiple extensions. ## Manifest Kind Declaration -A Kind is utilized by declaring it in the `kind` field of a Manifest: +A **Kind** is declared in the `kind` field of the manifest, which is part of the extension registration process. The declaration is linked to a specific extension type. ```typescript const manifest = { - type: 'headerApp', - kind: 'button', + type: 'headerApp', // The type of the extension + kind: 'button', // The kind alias to inherit settings from ... }; ``` -By declaring a kind, the Manifest will inherit fields of the defined Kind. +By setting the `kind` field, the extension automatically inherits all properties associated with that **Kind**. This is useful when you want to standardize a component (like a button) across multiple extensions. -A typical use case is a Kind that provides an element, but requires additional meta fields, to fulfill the needs of its element. +## Using the Kind for Inheritance -In the following example, a manifest using the type 'headerApp' utilizes the 'button' kind. This brings an element and requires some additional information as part of the meta object. +A Kind not only defines the basic configuration but may also require additional metadata to fully configure the element or component. -Adding the metadata provides the ability to use and configure existing functionality to a specific need. +### Example: Using the Button Kind in a Header App ```typescript const manifest = { @@ -46,10 +46,11 @@ const manifest = { }; ``` -## Learn more +In this example: + +- The `kind: 'button'` inherits all default settings from the **Button Kind**. +- The `meta` object is added to configure additional properties, such as the button's label, icon, and the URL to open when clicked. -Learn more about Kinds and how to create your own: +The Kind allows you to extend existing functionality and tailor it to specific needs while maintaining consistency. -{% content-ref url="extension-types/kind.md" %} -Kind Extension Type -{% endcontent-ref %} +For a deeper dive into Kind and how to create your own, see the [Kind](extension-types/kind.md) article. diff --git a/15/umbraco-cms/customizing/extending-overview/extension-types/kind.md b/15/umbraco-cms/customizing/extending-overview/extension-types/kind.md index ce3ec151038..37bb77f1da4 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-types/kind.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-types/kind.md @@ -1,5 +1,5 @@ --- -description: A kind extension provides the preset for other extensions to use +description: A kind extension provides the preset for other extensions to use. --- # Kind @@ -8,56 +8,86 @@ description: A kind extension provides the preset for other extensions to use This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. {% endhint %} -A kind is matched with a specific type. When another extension uses that type and kind it will inherit the preset manifest of the kind extension. +A Kind is a preset configuration that can be inherited by extensions to ensure consistency and reduce redundancy. It defines a set of default properties or behaviors that extensions can adopt, making it easier to maintain and configure extensions that share similar functionality. -The registration of Kinds is done in the same manner as the registration of other extensions. But the format of it is different. Let's take a look at an example of how to implement the `Kind registration` for a [**Header App**](../extension-types/header-apps.md) **Button Kind**. +A Kind is always linked to a specific extension type. Extensions using the same type and referencing a Kind automatically inherit its settings, ensuring uniformity across different extensions. -## Understanding the Kind Extension +## Benefits of Using a Kind -The root properties of this object define the `Kind registration`. Then the manifest property holds the preset for the extension using this kind to be based upon. This object can hold the property values that make sense for the Kind. +- Reduces redundancy – Common settings are defined once and reused across extensions. +- Ensures consistency – Extensions using the same Kind follow a standardized structure and behavior. +- Simplifies extension definitions – Extensions inherit predefined properties, reducing manual configuration. -```typescript -... +## Kind Registration + +To register a Kind, use the same method as other extensions. The key properties that define a Kind registration are: + +- `type`: Always set to `kind`. +- `alias`: A unique identifier for the Kind. +- `matchType`: Specifies the extension type that the Kind applies to. +- `matchKind`: Defines the Kind alias, which extensions must reference. +- `manifest`: Contains the preset values that extensions will inherit. +### Example: Registering a Button Kind for Header Apps + +The following example shows how to register a Button Kind for [**Header Apps**](../extension-types/header-apps.md). This kind provides a preset configuration for a button element that can be reused by other Header App extensions. + +```typescript const manifest: ManifestKind = { type: 'kind', - alias: 'Umb.Kind.MyButtonKind', - matchType: 'headerApp', - matchKind: 'button', + alias: 'Umb.Kind.MyButtonKind', // Unique alias for the Kind + matchType: 'headerApp', // Applies to Header App extensions + matchKind: 'button', // Defines the Kind alias manifest: { - ... + // Add default properties for the 'button' Kind + elementName: 'umb-header-app-button', }, }; - -... ``` -For the kind to be used, it needs to match up with the registration of the extension using it. This happens when the extension uses a type, which matches the value of `matchType` of the Kind. As well the extension has to utilize that kind, by setting the value of `kind` to the value of `matchKind` the Kind. +In this example: -```typescript -... +- `type` is set to 'kind' to register it as a Kind extension. +- `matchType` is 'headerApp', specifying that this Kind is for Header App extensions. +- `matchKind` is 'button', which is the alias of the Kind. +- The `manifest` contains default properties like elementName that extensions using this Kind will inherit. + +## Using the Kind in Other Extensions +To use the Kind in other extensions, the extension must reference it by setting the `type` and `kind` properties. The extension will automatically inherit the Kind's properties. + +### Example: Header App Extension Using the Button Kind + +```typescript const manifest = { - type: 'headerApp', - kind: 'button', - ... + type: 'headerApp', // Extension type + kind: 'button', // References the 'button' Kind + name: 'My Header App Example', + alias: 'My.HeaderApp.Example', + meta: { + label: 'My Example', + icon: 'icon-home', + href: '/some/path/to/open/when/clicked', + }, }; -... +extensionRegistry.register(manifest); ``` -## Kind example +In this example, the Header App extension uses the `kind: 'button'`, meaning it inherits the `elementName` defined in the Button Kind. The extension can still add custom properties (like metadata in this case) to further customize the behavior or appearance. + +## Kind Example -In the following example, a kind is registered. This kind provides a default element for extensions utilizing this kind. +Here’s an example of how to register and use the Button Kind in a Header App extension: ```typescript import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; const manifest: UmbExtensionManifest = { type: 'kind', - alias: 'Umb.Kind.MyButtonKind', - matchType: 'headerApp', - matchKind: 'button', + alias: 'Umb.Kind.MyButtonKind', // Alias for the Kind + matchType: 'headerApp', // Extension type the Kind applies to + matchKind: 'button', // Defines the Kind alias manifest: { elementName: 'umb-header-app-button', }, @@ -66,16 +96,16 @@ const manifest: UmbExtensionManifest = { umbExtensionsRegistry.register(manifest); ``` -This enables other extensions to use this kind and inherit the manifest properties defined in the kind. +This code registers the Button Kind, so other Header App extensions using `type: 'headerApp'` and `kind: 'button'` will inherit the preset `elementName: 'umb-header-app-button'`. -In this example a **Header App** is registered without defining an element, this is possible because the registration inherits the elementName from the kind. +Now, another Header App extension can be created without defining `elementName`, as it will automatically inherit it from the Kind: ```typescript import { extensionRegistry } from '@umbraco-cms/extension-registry'; const manifest = { - type: 'headerApp', - kind: 'button', + type: 'headerApp', // Extension type + kind: 'button', // References the 'button' Kind name: 'My Header App Example', alias: 'My.HeaderApp.Example', meta: { @@ -87,3 +117,7 @@ const manifest = { extensionRegistry.register(manifest); ``` + +By referencing the Kind, the extension inherits shared properties like `elementName`, ensuring consistency and reducing redundancy across extensions. This method also makes it easier to update configurations across multiple extensions. + +By using Kinds, you can create reusable, standardized configurations for extensions, helping to streamline development, ensure consistency, and reduce duplication. Understanding how to register and reference Kinds effectively will enhance the maintainability of your Umbraco extensions.