Brn
Brn

Reputation: 1

Azure log data not appearing in custom log

I am looking to insert records (low volume) from a VS2022 C# function app into a custom log table within log analytics. I dont receive any errors, but the data does not appear. Its not a timing issue, I dont have the data an hour later. I am querying in the log analytics window in "KQL mode" with just putting my custom table name.

I have created a custom log table within log analytics using a JSON sample. I have set up the data collection endpoint (DCE) and data collection rule (DCR).

The DCR has a data source as Custom-mytablename with a destination showing the mytablename in my log analytics workspace. The DCR shows the "Data Collection Endpoint" as my DCE.

I've granted the function app the roles of "Log Analytics Contributor" and "Monitoring Metrics Publisher" on both the DCR and DCE.

Below is the relevant section of code. I cannot run this thru the local debugger because I cant yet figure out why the "DefaultAzureCredential" isnt working locally but I know it does work in the cloud because I am able to put data in the AppTraces table elsewhere in the same function app.

I have changed the URLs and ids to <..> for this post but I have the actual values in the real code. The sTest string is the same value that I used as the sample to create the table so I know the column names are correct.

LogsIngestionClient liClient = new LogsIngestionClient(new Uri("<my_logs_ingestion_URL_from_the_DCE>"), new DefaultAzureCredential());
    
string sTest = "{ \"ID\": \"ID0345P09B\", \"Status\": \"E\", \"ErrorMessage\": \"This is a sample error\" } ";

BinaryData data = BinaryData.FromString(sTest);
var response = liClient.Upload("<ID_from_my_DCR>", "Custom-<mytablename>", RequestContent.Create(data));

What am I missing? And how can I get further details on why I am not getting data? The response returned from the upload has a status of 204 which would be a success response.

Upvotes: 0

Views: 64

Answers (1)

RithwikBojja
RithwikBojja

Reputation: 11393

You can simply use Agents with Workspace id and Primary key. No need to create Data Collection rule for it:

enter image description here

Below code worked for me and I followed Microsoft-Document:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;

namespace RithFunctionApp
{
    public class Function1
    {
        private readonly ILogger<Function1> ri_lg;
        static string ri_sh_ky = "FKniPXwoaSg==";//primary key
        static string Custom_Table_Name = "Rith_Test_Table";
        static string ri_tmp = "";
        static string json = @"[{""Name"":""Rithwik"",""Id"":""8""},{""Name"":""Bojja"",""Id"":""7""}]";
        static string ri_cus_id = "91b575cad";// worspace id
        

        public Function1(ILogger<Function1> lg)
        {
            ri_lg = lg;
        }

        [Function("Function1")]
        public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req)
        {
            ri_lg.LogInformation("Hello Rithwik Bojja, The Function execution is started");
            var ri_ds = DateTime.UtcNow.ToString("r");
            var ri_jb = Encoding.UTF8.GetBytes(json);
            string ri_sth = "POST\n" + ri_jb.Length + "\napplication/json\n" + "x-ms-date:" + ri_ds + "\n/api/logs";
            string ri_hs = Rith_Build_Sign(ri_sth, ri_sh_ky);
            string ri_sign = "SharedKey " + ri_cus_id + ":" + ri_hs;
            string ri_url = "https://" + ri_cus_id + ".ods.opinsights.azure.com/api/logs?api-version=2016-04-01";

            using (HttpClient ri_cl = new HttpClient()){
                ri_cl.DefaultRequestHeaders.Add("Accept", "application/json");
                ri_cl.DefaultRequestHeaders.Add("Log-Type", Custom_Table_Name);
                ri_cl.DefaultRequestHeaders.Add("Authorization", ri_sign);
                ri_cl.DefaultRequestHeaders.Add("x-ms-date", ri_ds);
                ri_cl.DefaultRequestHeaders.Add("time-generated-field", ri_tmp);

                using (HttpContent rith = new StringContent(json, Encoding.UTF8)){
                    rith.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    HttpResponseMessage response = await ri_cl.PostAsync(new Uri(ri_url), rith);
                }
            }
            return new OkObjectResult("Hello Rithwik Bojja,Logs are sent!!");
        }
        private string Rith_Build_Sign(string ri_msg, string ri_sec)
        {
            var ri_en = new ASCIIEncoding();
            byte[] ri_kb = Convert.FromBase64String(ri_sec);
            byte[] ri_mb = ri_en.GetBytes(ri_msg);
            using (var ri_hma = new HMACSHA256(ri_kb))
            {
                byte[] ri_hash = ri_hma.ComputeHash(ri_mb);
                return Convert.ToBase64String(ri_hash);
            }
        }
    }
}

Output:

enter image description here

enter image description here

enter image description here

Upvotes: 0

Related Questions