Some log analysis commands

  1. This command searches all .log files which contains the target message in the current directory.
    It prints the filename, the matching line and the 30 lines that follow the matching line.
    grep -H -A 30 "target error message" *.log
    
  2. This command locates every line that contains the target message (-i here is for ignoring case distinctions) and prints it, along with the 30 lines that immediately follow each matching line.
    | less provides paging functions.
    grep -i -A 30 "target error message" sample.log | less
    
  3. tail -f starts continuously outputting new lines as they are written to the specified file.
    grep then, in real-time, scans these incoming lines and print necessary logs.
    This process continues indefinitely until we manually stop the command.
    tail -f sample.log | grep -A 30 "target error message"
    
  4. This command counts the occurrences of the target error message in the sample.log.
    grep -c "target error message" sample.log
    
  5. This command prints 30 lines of context both before and after the target message in the sample.log.
    grep -C 30 "target error message" sample.log
    
  6. Nowadays we have more useful tools such as ELK (Elasticsearch, Logstash, Kibana) stack.
    The configuration is more complicated so I guess I will add those contents in the future :)

A simple DP example

DP code sample.
Just a quick refresh.

class Program
{
  static void Main()
  {
    int goal = 97;
    int[] coins = {10, 25, 5, 1};

    int []table = new int[goal + 1];

    table[0] = 0;

    for (int i = 1; i <= goal; i++)
    {
      table[i] = int.MaxValue;
    }

    for (int j = 1; j <= goal; j++)
    {
      for (int k = 0; k < coins.Length; k++)
      {
        int selectedCoin = coins[k];
        if (selectedCoin <= j)
        {
          table[j] = int.Min(table[j], table[j - selectedCoin] + 1);
        }
      }
    }

    foreach (var elem in table)
    {
      Console.Write(elem);
      Console.Write(" ");
    }
    Console.WriteLine();
    Console.WriteLine(table.Last());

  }
}

Switch from Snap to DEB Firefox on Kubuntu

Steps may change in the future.

  • sudo snap remove firefox

  • Follow https://support.mozilla.org/en-US/kb/install-firefox-linux#w_install-firefox-deb-package-for-debian-based-distributions
    • However, in step 5: onfigure APT to prioritize packages from the Mozilla repository, use the command below:
      echo '
      Package: *
      Pin: origin packages.mozilla.org
      Pin-Priority: 1001
      
      Package: firefox
      Pin: version 1:1snap*
      Pin-Priority: -1
      ' | sudo tee /etc/apt/preferences.d/mozilla-firefox
      
  • sudo apt install firefox

  • To ensure that unattended upgrades do not reinstall the snap version of Firefox:
    echo 'Unattended-Upgrade::Allowed-Origins:: "namespaces/moz-fx-productdelivery-pr-38b5/repositories/mozilla:mozilla";' | sudo tee /etc/apt/apt.conf.d/51unattended-upgrades-firefox
    

Some Minimal API patterns

Minimal API is a fairly new way to implement Web APIs, introduced in .NET 6.
I initially thought it was only suitable for small projects, as its name suggests. Recently, I read some articles and watched videos about how to organize Minimal API projects, and I have changed my mind.
The main reason I believed Minimal API was only for small projects is that most demos are quite small and put all APIs in Program.cs, which is obviously not scalable and somewhat messy.
By using extension methods, it is quite convenient to group APIs into different files, making them much easier to manage.
A third-party library Carter also seems useful in grouping APIs.

Below are some articles and videos I found useful regarding organizing Minimal API applications:
Milan Jovanović’s video
Milan Jovanović’s blog Tess Ferrandez’s article about organizing ASP.NET Core Minimal APIs

Milan uses extension methods for IEndpointRouteBuilder while Tess using WebApplication. I prefer the IEndpointRouteBuilder approach because MS official document says so.

In my previous experience with Spring Boot, I was used to a more MVC style when implementing Web APIs. However, I am glad to see a new way to develop them. I’m not sure if Minimal API is suitable for “large” projects, but it really looks promising to me for many Web API applications.

Some C# notes

  1. Use escape sequences for special signs such as \n. Or use a verbatim statement
    // Escape sequences example
    Console.WriteLine("I need to use escape sequences for special signs such as \\ here.");
    // Verbatim statement example
    Console.WriteLine(
      @"
      My name is ""SilMOON"" and this is a verbatim statement.
      I can use special signs such as \ here.
      "
      );
    

    Noted that C#11 introduced raw string literals which is more convenient. I’m actually suprised that they didn’t add this feature earlier. :)

Server hosting tips

  1. Add non-root user.
    I. # useradd -m USERNAME
    II. # passwd USERNAME
    III. Add your user to the wheel or sudo group:
    • DEB based distros: # usermod -aG sudo USERNAME
    • RPM based distros: # usermod -aG wheel USERNAME
  2. Disable root logins.
    I. # vim /etc/ssh/sshd_config
    II. Set PermitRootLogin=no

  3. Change SSH port

  4. Use non-root user

  5. (Just my preference) Install zsh & oh-my-zsh

  6. Set up SSH keys
    • If no exsisting key, generate one first
    • On local machine: $ ssh-copy-id USERNAME@IP_ADDRESS (If SSH port changed: $ ssh-copy-id -p PORT USERNAME@IP_ADDRESS)
  7. Configure ufw firewall

  8. Install Fail2Ban

  9. (If possible) Use Docker rootless

  10. (From: https://docs.docker.com/engine/install/linux-postinstall/) If using regular Docker, don’t forget:
    • $ sudo groupadd docker
    • $ sudo usermod -aG docker $USER
    • Reboot
  11. (Optional) Disable SMTP port

Some Kotlin notes

  1. Use vararg for variable arguments:
    fun printLetters(vararg letters: String, count: Int): Unit {
     print("$count letters are ")
     for (letter in letters) print(letter)
     println()
    }
    

    Then we can use it by calling:

    printLetters("a", "c", "q", count = 3)
    

    Or use * to pass an array as parameters:

    val argArray = arrayOf("q","e","w")
    printLetters(*argArray, count = 3)
    

Check the usage of ports in Linux

We can use the netstat -anp command to check active connections and port usage.

-a shows all active connections.

-n shows applications an port number in numbers.

-p lists processes(pid) which occupied the port. And we can simply kill them using the pid if we need.

Some Java notes

  1. The this keyword has two meanings: to refer a field of the implicit parameter and to call another defined constructor in the same class. The super keyword also has two meanings: to call a superclass constructor and call a superclass method. Like using this keyword to call a constructor, the constructor call must be the first statement in the new constructor. In the following example, Manager is the subclass of Employee, the Employee class which is hidden for simplicity does not have the field bonus:
    public Manager(String name, double salary, int year, int month, int day)
    {
     super(name, salary, year, month, day); //is the same as Employee(name, salary, year, month, day)
     bonus = 0;
    }
    

    Likewise, the this keyword can be used in a similar way.

Fix DNS resolution issue for my domain

Yesterday I found that my domain name for my Mastodon instance couldn’t be resolved. So I check my Whois information on ICANN Lookup and found that my status became “serverHold”. Generally this code means your domain name potentially have risks of spam or other illegal matters, but I only use this domain for my small Mastodon instance and the email service it runs is simply for sending verification email to new users. But I still had to email to the registry of my domain and when they reactivate my domain name, I was told that my domain was also blacklisted by another anti-spam organization. As a result, I had to contact that organization in order to get my domain out of their blacklist. I was told that the reason I was blacklisted is that I ran an outgoing email service without setting verified rDNS. To solve this problem, I firstly set rDNS of my server, this step is quite easy thanks to Vultr’s easy to use interface. Next I need to apply for a delist key from their delist tool. In order to get the key, the anti-spam website need a postmaster email address with my domain name, so I create it using the email-forwarding tool provided by my domain name provider. And then I simply get the key and get my domain out of the blacklist successfully.