.Net Core’da ElasticSearch
Selamlar Arkadaşlar,
Bu makalede, .Net Core ile macOS High Sierra üzerinde Elastic Search konusunu hep beraber inceleyeceğiz. Elastic Search hakkında daha detaylı bilgiye buradaki makaleden erişebilirsiniz. Öncelikle Elastic Search ve buna bağlı componentler için ilgili kurlumları birlikte yapacağız. Daha sonra .Net Core ile bir WebApi projesi oluşturacağız. Ve bu projede kullanılmak üzere 3 Sharding’li, 1 Replicalı ve 3 nodelu bir index oluşturacağız. Son olarak da aranacak Error Logları Tekil ve Bulk Insert şeklinde atarak, filitreleme işlemlerini yeni yaratılacak bir Mvc proje üzerinde yapacağız.
Öncelikle gelin bu elastik search için kurulum işlemlerini Macbook üzerinde yapalım:
Makinanızda yok ise önce Homebrew kurulur. Var ise Update edilir.
- Install :
1/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" -
Update:
1brew update - Elastic Search Kurulur:
1brew install elasticsearch
- Elasticsearch Monitör’ü için Kabana kurulur:
1brew install kibana
İşler yolunda gitti ise yeni bir terminal açılıp, “elasticsearch” komutu yazıldığında yukarıdaki gibi bir ekran ile karşılaşılır.
1 |
http://localhost:9200 |
Aynı şekilde kibana için terminalde : “kibana” komutu yazılır. Ve aşağıdaki komut yazıldığında yukarıdaki gibi bir ekran ile karşılaşılır. Kibana dataların ve log işlemlerinin istenir ise grafikler ile gösterilmesini sağlayan bir tooldur.
1 |
http://localhost:5601 |
Kurulumlar bittiğine göre sıra geldi Webservisi uygulamasını .Net Core ile oluşturmaya. Alttaki komut satırı ile ilgili application oluşturulur.
1 |
dotnet new webapi -o elasticService |
.Net Core’da Elasticsearch kullanabilmek için öncelikle projeye “Nest” kütüphanesinin “dotnet add package NEST” komutu ile eklenmesi gerekmektedir.
Öncelikle kaydedilecek Log Model aşağıdaki gibi oluşturulur.
Log:
1 2 3 4 5 6 |
public class Log { public int UserID { get; set; } public DateTime PostDate { get; set; } public string message { get; set; } } |
Öncelikle alttaki connSettings ve elasticClient static olarak tanımlanır. Böylece ilgili objelerin sadece 1 kere oluşturulması, performans arttırma amacı ile sağlanmıştır. Connection ayarlarında “log_history” default olarak verilmiştir.
1 2 3 4 5 6 7 8 |
private static readonly ConnectionSettings connSettings = new ConnectionSettings(new Uri("http://localhost:9200/")) .DefaultIndex("log_history") //Optionally override the default index for specific types .MapDefaultTypeIndices(m => m .Add(typeof(Log), "log_history")); private static readonly ElasticClient elasticClient = new ElasticClient(connSettings); |
Logs/InsertLog() :
- Aşağıda görüldüğü gibi “!elasticClient.IndexExists(“error_log”).Exists” eğer ‘error_log’ index’i hiç oluşturulmamış ise bu kod satırı çalıştırılır. Yani yeni bir Index oluşturulur.
- “error_log” index sadece bir eşleniğinin alındığı tek replicali bir yapıya sahiptir.==>”indexSettings.NumberOfReplicas = 1“
- İlgili index’in 3 farklı sharding yani sunucusu vardır. ==>”indexSettings.NumberOfShards = 3“.
Image Source: https://elastic-stack.readthedocs.io/en/latest/_images/elk_cluster_shard.png
Not: Herbir sunucunun yedeği yani replica’sı alınacak ise en az 3 Node’u olması gerekmektedir. Herbir node, tekbir elastic search anlamına gelmektedir. Cluster’da tüm nodeların bulunduğu kümedir. Nodelar içinde bulunan herbir shardingin yedeğinin yani replicasının başka bir node’da çapraz dediğimiz bir şekilde olması gerekmektedir. Bu tamamen güvenlik amaçlıdır. Bir shard yani makina çöker ise, başka bir cluster’da olan replicası yanbi yedeği ya da eşleniği devreye girer. Bu durumda toplam makina sayısı 3 container ve her containerda 2 shard’dan “6” dır.
- “var createIndexDescriptor = new CreateIndexDescriptor(“log_history”)” : “log_history” adında bir index yaratılacaktır.
- “.Map<Log>(m => m.AutoMap())” ==>İlgili index log sınıfına maplenmiştir.
- “Aliases(a => a.Alias(“error_log”))” ==> Var olan “log_history” index’ine “error_log” adında alies bir isim tanımlanmıştır. Burada amaç eski index kayıtlarının, var olan index silindiğinde ya da silinmesi gerektiğinde kaybolmasını engellemektir. Bunun için eski Index’e ait alies, örneğin burada “error_log” yeni yaratılacak Index’e yeni alies olarak atanması ile mümkün kılınır.
- Sıra geldi gönderilen hatanın Elastic Search’e kaydedilmesine:
- “var conn=connSettings .DefaultIndex(“log_history”)” : Önceden oluşturulan static connSettings’e default olarak “log_history” index’i atanır.
- “Add(typeof(Log), “log_history”))“: Alınacak data tipi olarak “log” sınıfı tanımlanır.
- “var client = new ElasticClient(conn);” : Yeni bir connection oluşturulur.
- “client.Index<Log>(log, idx => idx.Index(“log_history”))” :Gönderilen log datası ilgili Index altına kaydedilir.
- “//elasticClient.DeleteIndex(“log_history”)” : İstenir ise aşağıda yorum satırı haline getirilen DeleteIndex() methodu ile oluşturulan “error_log” index’i silinebilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
//Post /Logs/api/InsertLog [HttpPost] public void InsertLog([FromBody]Log log) { //elasticClient.DeleteIndex("log_history"); //Yok ise error_log Index Oluşturma. Sadece 1 kez çalışır. if (!elasticClient.IndexExists("error_log").Exists) { var indexSettings = new IndexSettings(); indexSettings.NumberOfReplicas = 1; indexSettings.NumberOfShards = 3; var createIndexDescriptor = new CreateIndexDescriptor("log_history") .Mappings(ms => ms .Map<Log>(m => m.AutoMap()) ) .InitializeUsing(new IndexState() { Settings = indexSettings }) .Aliases(a => a.Alias("error_log")); var response = elasticClient.CreateIndex(createIndexDescriptor); } //Insert Data elasticClient.Index<Log>(log, idx => idx.Index("log_history")); } |
Şimdi gelin bir MVC projeyi .Net Core ile oluşturalım ve ilk hatamızı WebApi servisimize gönderelim.
“dotnet new mvc -o elasticWeb” : Komutu ile ilgili Mvc Web application oluşturulur.
Home/Index() : Test amaçlı Index() Action’ınında “1/0” işlemi yapılarak hataya düşünülmesi sağlanmıştır. Daha sonra oluşturulan Log sınıfı “http://localhost:1453/api/logs” webapi servisine gönderilmiştir. İlk etapta hata yakalama işlemi try{} catch{} blokları içerisinde yapılmaktadır. İlgili Log sınıfına, Kullanıcı ID(UserID), hata mesajı(message) ve hatanın oluştuğu zaman (DateTime.Now) atanmaktadır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public async Task<IActionResult> Index() { try { int b = 1; int c = 0; int a = b / c; return View(); } catch (Exception ex) { Log log = new Log() { PostDate = DateTime.Now, message = ex.Message, UserID = 1 }; using (HttpClient client = new HttpClient()) { var data = JsonConvert.SerializeObject(log); HttpContent content = new StringContent(data,System.Text.Encoding.UTF8, "application/json"); await client.PostAsync("http://localhost:1453/api/logs", content); } return View(); } } |
Test amaçlı hata fırlatan static A() methodu aşağıdaki gibi tanımlanır: Bu sınıf About ve Contact sayfalarında çağrılarak, test amaçlı hata oluşması sağlanmıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
static int A(string argument) { // Handle null argument. if (argument == null) { throw new ArgumentNullException("argument"); } // Handle invalid argument. if (argument.Length == 0) { throw new ArgumentException("Zero-length string invalid","argument"); } return argument.Length; } |
Home/About() : Aşağıda görüldüğü gibi özellikle test amaçlı hata fırlatmak amacı ile “A(null)” methodu çağrılmıştır. Yine burada hata, şimdilik try{} catch{} blokları arasında yakalanmkatadır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public async Task<IActionResult> About() { try { A(null); } catch (Exception ex) { Log log = new Log() { PostDate = DateTime.Now, message = ex.Message, UserID = 2 }; using (HttpClient client = new HttpClient()) { var data = JsonConvert.SerializeObject(log); HttpContent content = new StringContent(data, System.Text.Encoding.UTF8, "application/json"); await client.PostAsync("http://localhost:1453/api/logs", content); } } ViewData["Message"] = "Your application description page."; return View(); } |
Home/Contact() : Aşağıda görüldüğü gibi özellikle test amaçlı hata fırlatmak amacı ile “A(“”)” methodu çağrılmıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public async Task<IActionResult> Contact() { try { A(""); } catch (Exception ex) { Log log = new Log() { PostDate = DateTime.Now, message = ex.Message, UserID = 3 }; using (HttpClient client = new HttpClient()) { var data = JsonConvert.SerializeObject(log); HttpContent content = new StringContent(data, System.Text.Encoding.UTF8, "application/json"); await client.PostAsync("http://localhost:1453/api/logs", content); } } ViewData["Message"] = "Your contact page."; return View(); } |
Mvc Web appliction çalıştırılır ve sıra ile Home , About ve Contact sayfalarına girilir ise oluşan toplam 3 hata elastic search’e yazılır.
Webapi servisine ilk gelinildiğinde index daha hiç yaratılmadığı için “log_history” ya da alies’i “error_log” index’i create edilir. Daha sonra ilgili “log” hatası index’e yazılır.
Kibana Log: 3 Hata da oluştuktan sonra kibanada aşağıdaki gibi bir log listesi oluşur.
Postman’de : “http://localhost:9200/log_history/log/_search” şeklinde bir search işlemi yapıldığında aşağıdaki gibi bir sonuç listesi dönmektedir. İlk dönen node “log_history” Index, diğer notlar error yani hata loglarıdır.
Gelin şimdi son bir haftaya kadar olan sadece hata mesajlarını çekip, Index sayfasında bir radio List olarak listeleyelim.
Öncelikle WebApi servisine aşağıdaki gibi “GetAllErrors()” methodunu ekleyelim:
elasticService (Project):
Log/GetAllErrors() :
- await elasticClient.SearchAsync<Log>(p => p : Log Document’a göre asenkron bir arama yapılacağı anlamına gelmektedir.
- “.Source(f=>f.Includes(p2=>p2.Field(f2=>f2.message)))” : Eğer istenirse performans amaçlı sadece tekbir alanın(message) çekilmesi yandaki gibi “Includes()” methodu ile belirlenebilir. Bu yazılmadığı takdirde document’e ait tüm fieldlar çekilir.
- “.Query(q => q .MatchAll()” : Tüm kayıtların çekileceği anlamına gelmektedir.
- “.PostFilter(f => f.DateRange(r => r.Field(f2 => f2.PostDate)” : Query işleminden sonra dönen kayıtlar arasında, Tarihe göre “Log.PostDate” filed’ında bir filitreleme işlemi yapılacağı belirtilir.
- “.GreaterThanOrEquals(DateTime.Now.AddDays(-7))))” : İlgili tarih alanınıdan son 7 günün kayıtları filitrelenir.
- “foreach (var document in response.Documents)” : Dönen cevabın içindeki Documentler gezilir.
- “result.Add(document.message)” : Sadece Log.message field’ı, bir string[ ] diziye atılır.
- “return result.Distinct().ToList()” => Ve string[ ] sonucu tekilleştirilerek asenkron olarak geriye dönülür.
Not: Tüm data çekildikten sonra Distinct() methodu yerine, elasticsearch’de “Aggregation“‘lar yazılarak da unique kayıt gelmesi sağlanabilirdi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[HttpGet] public async Task<List<string>> GetAllErrors() { var response = await elasticClient.SearchAsync<Log>(p => p //.Source(f=>f.Includes(p2=>p2.Field(f2=>f2.message))) .Query(q => q .MatchAll() ) .PostFilter(f => f.DateRange(r => r.Field(f2 => f2.PostDate).GreaterThanOrEquals(DateTime.Now.AddDays(-7)))) ); var result = new List<string>(); foreach (var document in response.Documents) { result.Add(document.message); } return result.Distinct().ToList(); } |
elasticWeb (Project):
Home/Index (): İlgili Mvc Action’ına aşağıdaki kodlar eklenir. Bu kodlar hem hatanın olmadığı, hem de hatanın olabileceği durumlar için eklenmiştir.
- using (HttpClient client = new HttpClient()) : Yeni bir HttpClient oluşturulur.
- var result = await client.GetAsync(“http://localhost:1453/api/logs”) : Yukarıda WebApi servisinde yazılan “GetAllErrors()” methodu çağrılır.
- var data = JsonConvert.DeserializeObject<List<string>>(result.Content.ReadAsStringAsync().Result) : Geriye dönülen değer, List of String’e(List<string>) deserialize edilir.
- return View(data) : WebApi’den List<string>’e deserialize edilmiş data Index view’ına gönderilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
public async Task<IActionResult> Index() { try { int b = 1; int c = 0; int a = b / c; //Hata Listesi çekilir. using (HttpClient client = new HttpClient()) { var result = await client.GetAsync("http://localhost:1453/api/logs"); var data = JsonConvert.DeserializeObject<List<string>>(result.Content.ReadAsStringAsync().Result); return View(data); } } catch (Exception ex) { Log log = new Log() { PostDate = DateTime.Now, message = ex.Message, UserID = 1 }; using (HttpClient client = new HttpClient()) { var data = JsonConvert.SerializeObject(log); HttpContent content = new StringContent(data, System.Text.Encoding.UTF8, "application/json"); await client.PostAsync("http://localhost:1453/api/logs", content); //Hata Listesi çekilir. var result = await client.GetAsync("http://localhost:1453/api/logs"); var data2 = JsonConvert.DeserializeObject<List<string>>(result.Content.ReadAsStringAsync().Result); return View(data2); } } } |
Index.cshtm: Yukarıda görüldüğü gibi Unique olarak çekilen List<string> hata mesajları, ekrana Radio Button Listesi olarak basılmaktadır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@model List<string> <div class="container"> <div class="jumbotron"> <h3>ElasticSearch Error Log List</h3> </div> @using(Html.BeginForm("Detail","Home","FormMethod.Post")) { @foreach(var error in Model) { <div class="radio"> <label for="female"> <input type="radio" name="error" id="error" value="@error">@error </label> </div> } <br> <input type="submit" value="Detay" class="btn btn-success"> } </div> |
Şimdi gelin seçilen hata mesajının toplam sayısını ve detayını nasıl bulacağımızı hep beraber inceleyelim.
Yukarıda görüldüğü gibi seçilen radio button’daki hata mesajı, “Home/Detail” Action’ına aşağıdaki gibi gönderilmektedir.
Home/Detail: Gelen string error değer parametre olarak, ilgili webapi servisine post edilir. Servisden geriye dönen List<Log> result, Detail.cshtml sayfaya view model olarak gönderilir.
1 2 3 4 5 6 7 8 9 10 |
[HttpPost] public async Task<IActionResult> Detail(string error) { using (HttpClient client = new HttpClient()) { var result = await client.GetAsync($"http://localhost:1453/api/logs/{error}"); var data = JsonConvert.DeserializeObject<List<Log>>(result.Content.ReadAsStringAsync().Result); return View(data); } } |
Home/Detail.cshtml: Yukarıda görüldüğü gibi aranan hataya göre bulunan toplam kayıt sayısı ve hataların detayı ekrana zamana göre descending yani yakın zamana göre sıralanarak basılmıştır. Makalenin devamında detay için yazılan bu webservisini hep beraber inceleyeceğiz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
@model List<Log> <div class="container"> <div class="jumbotron"> <h3>Error Detail Total Count : @Model.Count</h3> </div> <hr> <table class="table"> <thead> <thead> <tr> <th>User ID</th> <th>Created Date</th> <th>Message</th> </tr> </thead> <tbody> @foreach(var log in Model) { <tr> <td> @log.UserID </td> <td> @log.PostDate </td> <td> @log.message </td> </tr> } </tbody> </thead> </table> </div> |
elasticService(WebApi Project):
Logs/Get(): Aşağıda görüldüğü gibi Web tarafında ilgili radio listesinden seçilen hata mesajına göre , elastic search’den ilgili message sorgulanıp, önceden bu tipte oluşmuş tüm hatalar bulunur ve geri dönülür.
- “ .Query(q => q.Term(f => f.UserID, 1)” : İlk yorumlanan “Term” kısmı, UserID’ye göre filitreleme işleminin de yapılabildiği kısımdır.
- “var response = await elasticClient.SearchAsync<Log>(p => p” : ElasticSearch’den “Log” document tipinde bir asenkron aramanın yapılacağı tanımlanmıştır.
- “.Query(q => q .Match(m => m .Field(f => f.message) .Query(error) )” : “Log” sınıfının “message” field’ında, gelen error string değeri aranır.
- “.Operator(Operator.And)” : Burası önemli arkadaşlar! Diyelim ki “Zero(1)-length string invalid Parameter(2) name(3): argument(4)” hatasını arattık. “Match()” default query methodu, bu cümlede geçen tüm kelimeleri tek tek “OR” ile arar. Yani eğer yandaki “Operator.And” eklenmez ise sonuç olarak
- “Attempted to divide by zero(1).“
- “Value cannot be null. Parameter(2) name(3): argument(4)” hata mesajları da, aranan cümledeki renkli olarak gösterilen kelimeleri içerdikleri için gelirler. Bunu önlemenin yolu, kelimeleri tek tek değilde cümle bazında eşleniğine bakılmasıdır. Bunun yolu kelimeler arası “And” koymaktan geçer.
- “.Sort(s=>s.Descending(f=>f.PostDate))” : Çekilen Query “PostDate” alanına göre, en yakın tarih en üstte olucak şekilde sıralanır.
- “foreach (var document in response.Documents)” : Bulunan dökümanlar “List<Log>” bir diziye eklenerek geri dönülür.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// GET api/values/5 [HttpGet("{error}")] public async Task<List<Log>> Get(string error) { /*var response2 = elasticClient.Search<Log>(p => p .From(0) .Size(10) .Query(q => q.Term(f => f.UserID, 1) ) );*/ var response = await elasticClient.SearchAsync<Log>(p => p .Query(q => q .Match(m => m .Field(f => f.message) .Query(error) .Operator(Operator.And) ) ) .Sort(s=>s.Descending(f=>f.PostDate)) ); var result = new List<Log>(); foreach (var document in response.Documents) { result.Add(document); } return result; } |
Sonu en güzeli:) Bu makalenin sonunda bir çoğunuzun kafasında projede her yere try{} cath{}’mi yazacağız ya da var olan projeme elastik search’ü en hızlı şekilde nasıl entegre ederim gibi sorular vardır. Bu son bölümde golabal olarak hataları yakalayacağız. Yani şu ana kadar yazdığımız try{} catch{}’lerin hepsini kaldırıp kodları kısaltacağız. Ve hata sistemini tekbir yerden yöneteceğiz.
Global Exception Handling :
Öncelikle Startup.cs’e “UseMvc()” methodundan önce, “app.UseExceptionHandler(“/Home/Error”)” tanımlaması yazılır. Yakalanamayan hatalarda çalıştırılacak(Unhandled Exception) Action burada en tepede tanımlanır. Hata olması durumunda “Home/Error” action’ına gidilecektir.
Startup.cs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseExceptionHandler("/Home/Error"); app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } |
elasticWeb (Application): Sayfalara göre yapılacak değişiklikler.
Home/Index : Aşağıda görüldüğü gibi try{} catch{} bloğu kaldırılmıştır. Hata globalde yakalanacaktır.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public async Task<IActionResult> Index() { int b = 1; int c = 0; int a = b / c; using (HttpClient client = new HttpClient()) { var result = await client.GetAsync("http://localhost:1453/api/logs"); var data = JsonConvert.DeserializeObject<List<string>>(result.Content.ReadAsStringAsync().Result); return View(data); } } |
Home/About: Aşağıda görüldüğü gibi hata blokları tamamen kaldırıldı. Hata globalde yakalanacaktır.
1 2 3 4 5 6 |
public async Task<IActionResult> About() { ViewData["Message"] = "Your application description page."; A(null); return View(); } |
Home/Contact: try{} catch{} bloğu, yine burada da kaldırılmıştır. Hata globalde yakalanacaktır.
1 2 3 4 5 6 |
public async Task<IActionResult> Contact() { ViewData["Message"] = "Your contact page."; A(""); return View(); } |
Home/Error: Global olarak hatanın yakalandığı ve elastic search’e yazıldığı yerdir.
- “var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>()“: Yakalanan hata exceptionFeature’a atanır.
- “message = exceptionFeature.Error.Message” : Gelen hatanın mesajı bu şekilde alınıp atanır.
- “UserID =GetUserIDByPage(exceptionFeature.Path.Replace(“/Home/”,””))” : Burada amaç hatanın geldiği sayfanın nasıl yakaladığını ve herbiri için farklı işlemlerin nasıl yapıldığı göstermektir. Mesela burada örnek amaçlı olarak, hatanın gelindiği sayfaya göre UserID değişmektedir. Bu case “GetUserIDByPage()” methodu ile yapılmaktadır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public async Task<IActionResult> Error() { var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>(); Log log = new Log() { PostDate = DateTime.Now, message = exceptionFeature.Error.Message, UserID =GetUserIDByPage(exceptionFeature.Path.Replace("/Home/","")) }; using (HttpClient client = new HttpClient()) { var data = JsonConvert.SerializeObject(log); HttpContent content = new StringContent(data, System.Text.Encoding.UTF8, "application/json"); await client.PostAsync("http://localhost:1453/api/logs", content); } return View(exceptionFeature.Path.Replace("/Home/","")); } |
GetUserIDByPage(): Kendisine gelen sayfalara göre farklı UserID’ler i geriye döndürmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public int GetUserIDByPage(string page) { switch (page) { case "About": { return 3; } case "Contact": { return 2; } case "Index": { return 1; } default: { return 1; } } } |
Geldik bir makalenin daha sonuna. Bu makalede .Net Core ile Elastic Search’ün ne kadar da güzel çalıştığını, kurulumundan kodlanmasına kadar beraberce inceledik. Kurulumu sırasında Elastic Search üzerinde Mapping, Replica, Sharding, Aliases gibi terimleri kullandık. Bunun haricinde hata loglarının, proje bazında globalde nasıl yakalanacağını ve bunların elastik search’de nasıl saklanacağını gördük. Son olarak oluşan hataların Unique bir listesini, yine yazdığımız bir WebApi ile çekip, seçilen hatanın detay listesini ekrana döktük. Bu işlemleri yaparken Elastic Search üzerinde Query, Fitler, Term, Operator, Match, PostFilter gibi kavramları inceledik.
Yeni bir makalede görüşmek üzere hoşçakalın.
Source:
- https://www.dotnetcurry.com/aspnet/1354/elastic-search-kibana-in-docker-dotnet-core-app
- https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/nest-getting-started.html
- https://github.com/elastic/elasticsearch-net
- https://stackoverflow.com/questions/42770362/elasticsearch-nest-matchphraseprefix-multiple-fields
Source Code: https://github.com/borakasmer/CoreElasticSearch
Super ve cok faydali bir yazi. Emeginiz icin cok tesekkur ediyorum.
Teşekkürler Elif…
Üstadım Merhaba, Uzun zamandır Apache Solr kullanmaktayım. Config olarak daha kolay gibi geldi Solr dan. Kibana ile kullanımına dikkat etmemiştim bu makalede basic olarak kullanımı çok işime yaradı. Detaylı bir şekililde bir projeye dahil edilebilir. Yalnız burada Elastic artı ve eksileri diye bir makale göremedim bence bizler için o da çok faydalı olur :) Ağzına sağlık.
Selam Hocam,
Öncelikle teşekkürler. Evet kesinlikle eksikleri de yazmak lazım. Ama genelde Elastic çok başarılı hocam. Solr da bu da lucene altyapısını kullanıyor.
Zamanım olunca gördüğüm yaşadığım eksikleri de kalem alırım.
Hoşçakal.
Bora.
Merhaba. Burada Elasticsearch hangi DB’yi kullanıyor? Ben mesela MongoDB’yi kullanmak istiyorum. Nasıl yapabilirim?
Selamlar Oğuzhan,
Elasticsearch kendisi indexleyip datayı saklıyor. Amaç zaten bu :) Herhangi bir DB kullanılmıyor. Zaten DB kullanılsa Elasticsearch’e ihtiyaç kalmaz.
MongoDB kullanacak iseniz, ElasticSearch’ün bir anlamı olmamaktadır.
İyi çalışmalar.
Hoşçakalın.
Merhaba,
Yazı için teşekkürler oldukça faydalı oldu.
Ben denemdim fakat şöyle bir problemim var;
Microservis bir yapıda bütün mikroservislerin loglarını elastichsearche aktarmak istiyorum.
Bir servis için loglamayı yazdım o servis kendi loglarını gönderiyor başarılı bir şekilde yazıyorum fakat aynı konfigürasyonlarla diğer servisleri elastichsearche baktırdığımda onlar loglarını basmıyor.
Sizce neden kaynaklanıyor olabilir?
Selamlar,
Öncelikle teşekkürler.
Hata mesajlarına bakabilirsem, size çok daha faydalı olabilirim. Ama sanki erişim sorunu, yetki gibi geldi bana..
İyi çalışmalar. Hoşçakalın.
Merhabalar,
Erişim problemi yada yetki benimde aklıma geldi fakat, birebir aynı konfigürasyona sahip diğer uygulamanın log verisi akıyor.
Elastichsearch.log dosyasındaki hatayı paylaşıyorum.
Teşekkürler.
https://imgur.com/hzTH2N5