Integration Platform

Microservice Management

Connect your code to Copyl

Code from a API controller

This article is for developers who wants to connect Copyl to their code for centralized logging in the Microservice Management and to publish trigger events to the Integration Platform. This is how we manage our own logging and integrations between all the different microservices.

Code examples below are in C# but any language can be used.

Please contact [email protected] if you have any questions. We are here to help you.

1. Install CopylHelper

First we need to install the CopylHelper from Nuget. CopylHelper is simplifying the communication with Copyl so you don’t need to write more code than nessecary.

  1. You need to have special credentials to download the package. Please contact [email protected] to get a nuget.config file that you put in the project root in Visual Studio.
  2. Install CopylHelper from Nuget:
nuget install CopylHelper

2. Add configurations to appsettings.json

You need to define the Microservice id and the App id from Copyl into the appsettings-files.

Please observe that you have two settings files in your API project; appsettings.json and appsettings.Development.json. The latter should have the microservice id for the Development environment. The OcpApimSubscriptionKey is your key to our API Manager.

{
  "ConnectionStrings": {
  },
  "AppSettings": {
    "ServiceId": "1234549b-e903-abcd-efgh-1234f98778c3",
    "AppId": "123456DC-1234-1234-1234-D49D3891234A",
    "OcpApimSubscriptionKey" : "12345678910",
    "AppName": "{YOUR INTEGRATION APP NAME (SYSCODE)}",
    "EnterpriseId": "{YOUR ENTERPRISE ID ON COPYL}",
    "ApiKey": "{YOUR API KEY TO COPYL}",
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Warning",
      "CopylAPI_Users": "Information"
    },
    "CopylLoggerProvider": {
      "IncludeScopes": true,
      "LogLevel": {
        "Default": "Information",
        "Microsoft": "Error",
      }
    }
  },
  "AllowedHosts": "*"
}

3. Set up integration helper

This code makes it easy to make any changes to your interactions with Copyl.

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Dynamic;
using System.Threading.Tasks;

namespace YOUR_NAMESPACE_HERE.Integrations
{
    public interface ITriggerEvent
    {
        Task ExecuteAsync();
    }

    public abstract class BaseTrigger : ITriggerEvent
    {
        protected readonly IConfiguration _configuration;
        protected readonly IHttpContextAccessor _httpContextAccessor;

        public BaseTrigger(IConfiguration configuration, IHttpContextAccessor httpContextAccessor)
        {
            _configuration = configuration;
            _httpContextAccessor = httpContextAccessor;
        }

        protected virtual string TriggerName => GetType().Name;
        protected abstract object TriggerData { get; }

        public async Task ExecuteAsync()
        {
            try
            {
                var currentHttpContext = _httpContextAccessor.HttpContext;
                var _triggerEvent = new CopylHelper.Entities.IntegrationAppTriggerEventDTO
                {
                    SysCode = _configuration.GetValue<string>("AppSettings:AppName") + "." + TriggerName,
                    EnterpriseId = new Guid(_configuration.GetValue<string>("AppSettings:EnterpriseId")),
                    ApiKey = new Guid(_configuration.GetValue<string>("AppSettings:ApiKey")),
                    Url = currentHttpContext?.Request.Path.ToString(),
                    Data = JsonConvert.SerializeObject(TriggerData, new Newtonsoft.Json.Converters.ExpandoObjectConverter())
                };

                await CopylHelper.Trigger.PublishTriggerToCopylAsync(_triggerEvent, _configuration.GetValue<string>("AppSettings:OcpApimSubscriptionKey"));
            }
            catch (Exception exception)
            {
                // add your logic for error management here
            }
        }
    }

    public class GenericTrigger : BaseTrigger
    {
        private ExpandoObject _triggerData;
        private string _triggerName;

        // Define a default trigger name
        private const string DefaultTriggerName = "DefaultTriggerName";

        public GenericTrigger(ILogger<BaseTrigger> logger, IConfiguration configuration, IHttpContextAccessor httpContextAccessor)
            : base(logger, configuration, httpContextAccessor)
        {
        }

        public void SetTriggerData(ExpandoObject triggerData, string triggerName = null)
        {
            _triggerData = triggerData;
            _triggerName = triggerName;
        }

        protected override object TriggerData => _triggerData;

        protected override string TriggerName => _triggerName ?? DefaultTriggerName; // Use default name if not set
    }
}

4. Set up Centralized Logging

Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args)
        .ConfigureLogging((hostingContext, logging) => 
        // Configuring logging using a delegate that takes hostingContext and logging.
        {
            logging.ClearProviders(); // Clearing all existing logging providers.
            logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); 
            // Adding logging configuration from appsettings.json

            // Getting AppSettings from the configuration
           var copylSettings = hostingContext.Configuration.GetSection("AppSettings").Get<CopylSettings>();

            Guid? appId = null; // Initialize nullable Guid for AppId.

            // Check if AppId is not null or empty in the configuration. 
            // If AppId exists, create a new Guid from AppId.
            if (!string.IsNullOrEmpty(copylSettings?.AppId))
            {
                appId = new System.Guid(copylSettings.AppId);
            }

            // Adding a custom logging provider with specific configuration
            logging.AddProvider(new CopylLoggerProvider(
                new CopylLoggerConfiguration
                {
                    // Assigning ServiceId from configuration
                    ServiceId = new System.Guid(copylSettings.ServiceId),

                    // Assigning AppId from configuration or null if not provided
                    AppId = appId,

                    // UserId is always null in this configuration
                    UserId = (Guid?)null,

                    // Setting the logging level to Information
                    LogLevel = LogLevel.Information
                }));
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>(); // Setting the startup class for the web application
        });
}

Error, warning and information logging

  1. Inject the ILogger into your controller / code
  2. use try{} catch{} to register errors to Copyl Microservice logging.
public class UsersController : ControllerBase
{
    private readonly ILogger<UsersController> _logger;

    public UsersController(ILogger<UsersController> logger)
    {
        _logger = logger;
    }
    
    [HttpPost]
    public async Task<ActionResult<User>> PostUser(User user)
    {
        try
        {
            _logger.LogInformation("Processing request");
            _logger.LogWarning("This is a warning and will be orange in the Copyl logging window.");
            ...
        }
        catch (Exception err)
        {
            _logger.LogError(err, "Error in {method}", MethodBase.GetCurrentMethod().Name);
            throw;
        }
    }
}

5. Create and report a Trigger from code

This is the simplest way to create Triggers in Copyl, directly from your code. Your are using the generic function above to both create and report an event/Trigger in Copyl.

Add data to the Trigger

Fill the triggerData below with all the data you want to report to the Trigger. You can add any variable type, E.g., strings, numbers, booleans, dates and arrays.

    // Post to Copyl Integration Platform
    var trigger = _serviceProvider.GetService<GenericTrigger>();
    dynamic triggerData = new ExpandoObject();
    triggerData.Team = team;
    triggerData.EnterpriseId = eid;
    triggerData.AnyString = aString;
    trigger.SetTriggerData(triggerData, CopylHelper.Trigger.GetMethodName());
    await trigger.ExecuteAsync();
    // finished sending trigger to Copyl

Use the method name as the Trigger name

This code will generate a Trigger called DeleteTeam in Copyl.

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTeam[Required] Guid id, [Required][FromHeader] string Authorization, [FromHeader(Name = "Accept-Language")] string acceptLanguage)
{
 try
 {
    ClaimsIdentity claimsIdentity;
    claimsIdentity = this.User.Identity as ClaimsIdentity;
    Guid eid = new(claimsIdentity.FindFirst(ClaimTypes.UserData).Value);
    Guid uid = new(claimsIdentity.FindFirst("name").Value);

    var team = await _context.Teams.FindAsync(id);
    if (team == null || team.EnterpriseId != eid)
    {
       return NotFound();
    }

    _context.Team.Remove(persona);
    await _context.SaveChangesAsync();

    // Post to Copyl Integration Platform
    var trigger = _serviceProvider.GetService<GenericTrigger>();
    dynamic triggerData = new ExpandoObject();
    triggerData.Team = team;
    trigger.SetTriggerData(triggerData, CopylHelper.Trigger.GetMethodName());
    await trigger.ExecuteAsync();
    // finished sending trigger to Copyl

    return NoContent();
 }
 catch (Exception err)
 {
    _logger.LogError(err, MethodBase.GetCurrentMethod().Name);
    throw;
 }
}

Define a manual name for the Trigger

Sometimes we want to report the same trigger from different methods and then we just change the code to:

    // Post to Copyl Integration Platform
    var trigger = _serviceProvider.GetService<GenericTrigger>();
    dynamic triggerData = new ExpandoObject();
    triggerData.Team = team;
    trigger.SetTriggerData(triggerData, "DeleteTeam");
    await trigger.ExecuteAsync();
    // finished sending trigger to Copyl

6. Set up a new Trigger manually

A Trigger is an event that your API is generating, and that event can trigger an Integration to be started.

Create/edit Trigger event in Copyl

Use the code generator

Here comes the beauty of using Copyl for integrations and the CopylHelper library. We get all the code we need to report the event as a Trigger in Copyl.