Thursday, July 16, 2020

How to re-install macos high Sierra

Sometimes, you just want to backup stuff in your old MacOs High Sierra and start over.

You saved all needed files on the google drive and ready for a new start.

Here is the steps to follow.


  1. shut down the laptop
  2. when the laptop start, press CMD + R during power up
  3. Once get into the restore mode, select Disk utilities and click continue 
  4. In the next screen select a disk images under "Disk Images" on the left, then click erase at the top.
  5. Once seeing "Erase process is complete, click Done to continue", just click Done
  6. Continue to do it until all the disk images under "Disk Images" are gone.
  7. Now select "Macintosh HD" under Internal on the left, the blue bar should show mostly free space. 
  8. We are done erasing old MacOS, it is time to start new.
  9. close Disk utilities window, return to restore mode main window.
  10. select "Reinstall MacOS"
  11. In the next window, you will notice the wifi connection is also grey out. Click the wifi icon and put in the wifi id and password.
  12. click continue, the wizard will connect to apple server in the cloud and guide you through exiting process of creating a new macOS, sit back and enjoy. (Don't forget to download the saved files from google drive once finish.)

Sunday, July 12, 2020

How Lombok saves developers' time

Nowadays, all the cool kids use lombok to make beautiful java code. So let's talk about it.

Project Lombok is a java library that automatically plugs into your editor and build tools to generate boilerplate code such as class constructors, field getter and setter, hashCode etc.

In order to use it, set lombok as one of the maven dependencies.

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

With the dependency, a lombok.jar will be introduced in the project compilation classpath. The lombok.jar contains a file named /META-INF/services/javax.annotation.processing.Processor. When javac sees this file in a compilation classpath, it runs annotation processors defined there during compilation. As a result, the lombok annotations such as @Getter is replaced by java getter code blocks. As you can see, lombok is a jar that works at compilation time.

The javac can understand the lombok annotations doesn't mean your IDE can understand them. Eclipse, for example, need to have a the lombok.jar registered, so that it can use it to compile your code before running it. The Eclipse installation is easy, lombok.jar did that for you. You just have to download the jar, run it with
java -jar lombok.jar

the rest of the work is handled by the jar. It scan your computer to find the eclipse and install itself into your chosen eclipse programs.

Now you can write code such as
package com.example.my.mydemo.dao;
import lombok.Getter;
import lombok.Setter;

@Setter @Getter
public class Client {
    private String name;
    private String email;
    private long id;
}

With the lombok annotation @Getter @Setter, javac or eclipse treat them as equivalent to the following code

package com.example.my.mydemo.dao;
public class Client {
    private String name;
    private String email;
    private long id;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
}

So, when other java code need to access getter and setters, it won't fail.
package com.example.my.mydemo.dao;

import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import com.example.my.mydemo.model.Client;

public class ClientDao {
    private final JdbcTemplate jdbcTemplate;
    private static final String CLIENTSELECT = "select name, email, id from "
            + "Client where id = ?";
    public ClientDao(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
    public Client getClient(String clientId) {
        Client client = jdbcTemplate.queryForObject(CLIENTSELECT, new Object[]{clientId},
                new BeanPropertyRowMapper<Client>(Client.class));
        return client;
    }

}

That is easy.

Even better, we can use @Data annotation to get many code for free, it is equivalent to @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode all together.


Tuesday, July 7, 2020

Top tools for full stack java developers

Full stack java developers wears the hat of both front end developers and back end developers. They just write the server/client code from start to end with css/html/js/java/sql/etc.

Let's take a peek into a typical full stack java developer's magic sack. It is just a peek, because a professional java developer's technical vocabulary requires a dictionary length file to enumerate.

Runtime

  • JDK -- When choosing java development kit (JDK), there are basically 2 options. Commercial version or free version. Oracle JDK LTS(Long Term Support) released every 3 years, which requires a commercial license. The latest oracle JDK 11 is not free. You got what you pay, oracle keep updating the JDK for bug fixes and security patches. Oracle OpenJDK is released every 6 months, it is free and open-source implementation of the java platform standard edition and it's been the official reference implementation of JAVA SE since version 7. For bug fixes and security patches we should upgrade oracle openJDK every 6 months. Besides oracle, other vendors such as Azul system also provides java SE 11 implementations. Their zulu 11 JVM, for example is java 11 openjdk builds. Their Zing JVM is Java Virtual Machine (JVM) and runtime platform for Java applications. Zing is compliant with the associated Java SE version standards. Zing's typical use cases are applications with requirements regarding low latency response time or huge heap sizes up to 20 TB by using its own pauseless garbage collection implementation (C4) and its own Just in time compiler implementation (Falcon). While Zulu is a general usage JVM which covers more general use cases as it is mainly openJDK with its Garbage collectors like CMS GC, G! GC, Parallel GC and the Hotspot JIT. Zulu is a branded version of OpenJDK (free to download and use without restrictions) with paid commercial support, while zing JVM charges per host.
  • NodeJS -- NodeJS JavaScript is an open source javascript runtime built on Chrome's V8 JavaScript engine. As Node. js is not the traditional programming language, but rather a runtime environment, it is easy to learn for both front and back-end developers. Node JS development has become a mature JS language and can be credited with having a large ecosystem. It has not just revolutionized backend development but also contributed in a big way to bringing performance to the front end.

IDE

  • Eclipse/IntelliJ IDEA with maven -- the most popular Java IDE are eclipse and Intellij IDEA. While eclipse is an open source free IDE, IntelliJ IDEA provides both free community version and charged ultimate version. All modern java developers use maven to manage java dependencies. 
  • Visual Studio Code with npm-- Visual Studio code is Microsoft open source IDE geared towards nodeJS development. It is the clear winner for full stack web developers. Atom used to be the top one IDE few years ago, now it is replaced by visual studio code. Visual Studio Code and Atom has similar features, but the fashion favors Visual Studio Code this year. Another popular IDE is WebStorm, a subset of IntelliJ IDEA, geared towards front end development. JetBrain's IDE provides unlicensed copy or licensed copy. It has tons of features and you get what you paid for, convenience and security. Other front end IDEs are text editors in their full glory. sublime text, for example, is the code editor used in coderpad, which has many short cuts to create code fast. It has tons of plugins you can find through Package Control, good for free-style editing of different languages. The npm to NodeJS is like maven to Java. When you download Node.js, you automatically get npm installed on your computer. The npm (Node Package Manager) is a command-line tool for interacting with online repository for open-source Node.js projects. 

Server

  • Apache -- Apache http webserver (httpd) is a free and open source program web server that runs 67% of all webservers in the world. Written in C language, it is fast, reliable, and secure. It is also adaptive to different environments using extensions and modules. For example, with mod_proxy, it can be configured to a multi-protocol proxy/gateway serve. A typical use case is to proxy requests to tomcat or nodejs, which need to be accessed from internet but don't have public IP. For another example, with mod_proxy_balancer, it can provide load balancing for all the supported protocols.
  • Tomcat -- Born out of the Apache Jakarta Project, Tomcat is an opensource application server written with java and designed to execute Java servlets and render web pages that use Java Server page coding. Tomcat can be configured in eclipse, intellij etc. to run the java servlets based code local during your development. It is also the embedded web server of springboot as one of the maven dependencies. While Tomcat is a java-phallic web server, apache http server is a general-purpose http server, which supports a number of advanced options that Tomcat doesn't. 
  • Jetty -- Tomcat is the most popular java servlet container/server, arguably the second popular servlet container/server is eclipse-foundation developed jetty. Due to its compactness and small footprint, Jetty is a great fit for constrained environments and for embedding in other products. 
  • GlassFish -- Ironically, tomcat and jetty were supposed to be java EE application servers. Though market selected them, neither Tomcat nor Jetty is technically a fully featured Java EE container. They lack support for many Java EE features and can not have the title of "java EE application servers". Oracle recommended 3 Java EE 8 Full Platform Compatible Implementations -- GlassFish, IBM WebSphere Application Server, wildfly. Tomcat and jetty are not in the list. GlassFish gets contributions from the same people who define Java EE standards. (Oracle has transferred Java EE to the Eclipse Foundation, and it is now called Jakarta EE after Java EE 8.) It’s the reference implementation Java EE application server that always support the latest Java EE features. 

Persistant Layer

  • MySql -- mysql is the most popular relational sql database. Its popularity is related to its adaptive to the major cloud providers. MySQL is free and open-source software under the terms of the GNU General Public License, and is also available under a variety of proprietary licenses. There are other relational sql database options such as mariadb, postgreSQL, oracle database. Relational database is a group of databases that stores structured information. The data written to the database has to match certain schema. In recent years, a new type of database, so called noSQL database began to gain popularity. The data written to the noSQL database can be free style, no schema restriction has to be put on the data. NoSQL databases come in a variety of types based on their data model. The main types are document, key-value, wide-column, and graph.
  • MongoDB -- MongoDB is the most popular noSQL database. MongoDB uses JSON-like documents with optional schemas. It is developed by MongoDB Inc. and licensed under the Server Side Public License. MongoDB stays at the CP edge of CAP graph. It is consistent, partition-tolerant, but not always available. Compare to relational databases, which lacks of partition-tolerant, MongoDB can be horizontally scale up without worrying about network partition. Data warehouses, data lakes store huge amount of structured and un-structured data, the storage have to be distributed among many VMs in different networks. Some servers unable to communicate to another servers across networks are unavoidable, therefore databases for the bigdata has to be partition-tolerant. That is key reason MongoDB are naturally selected by cloud.

Framework and Library

  • spring framework -- Spring is a powerful, lightweight framework used for application development using Java as a programming language. The Spring framework comprises of many modules such as core, beans, context, expression language, AOP, Aspects, Instrumentation, JDBC, ORM, OXM, JMS, Transaction, Web, Servlet, Struts etc. The root of spring framework is the IoC (Inversion of control) container. It receives metadata from either an XML file, Java annotations, or Java code. The container gets its instructions on what objects to instantiate, configure, and assemble from simple Plain Old Java Objects (POJO) by reading the configuration metadata provided.
  • Grails -- spring framework's closest competitor is grails framework, a powerful Groovy-based web application framework for the JVM. Both Grails and Spring Boot are "Full Stack Frameworks". "Groovy" is the primary reason why developers consider Grails over the simple and elegant Spring Boot. Groovy can be used as a scripting language for the Java platform. It is almost like a super version of Java which offers Java's enterprise capabilities. Groovy's use for scripting in the Jenkins CI/CD platform should help the JVM language maintain its popularity. However, as a programming language for JVM, I’d go with Kotlin or Scala for JVM.
  • Angular.js -- AngularJS is an open-source Front-end JavaScript framework. Its goal is to augment browser-based applications with Model–View–Controller (MVC) capability and reduce the amount of JavaScript needed to make web applications functional. Angular.js is currently the most popular Front-End javascript framework, the majority of the new front end stack is built on angularJS.
  • ReactJS -- The second popular Front-End javascript framework is ReactJS from facebook, ReactJS native is widely used for building cross-platform mobile apps.

Text Editor

  • sublime text -- popular text editor used by most front front end developers, it provides unlicensed and licensed versions. 
  • TextMate -- open source text editor which is handy when formatting language and markups such as xml, json, html.

Build and Deploy tool

  • Jenkins -- Jenkins is a free and open source automation server written in Java. It is used to continuously build and test software projects, enabling developers to set up a CI/CD environment. It use version control tools SVN, Git etc. to check out the code, it then run various maven commands such as mvn release:perform to build/test/release the artifacts to the repository. 
  • TeamCity -- an alternative CI/CD tool for Jenkins is TeamCity from JetBrains, the same company developing Intellij IDEA. It is commercial software and licensed under a proprietary license. Again, you get what you paid for.
  • Ansible -- free and open source automated deploy tool. With roles and playbooks, ansible allows the authorized user to execute tasks such as package deploy, OS update, server restart etc using remote SSH. A typical use case is login a set of servers and run red-hat native command yum to install rpms on redhat linux release, or use ansible-realm command package to detect the OS, then install the package accordingly. So far it is the most popular configuration management tool because it's easy to use. 
  • Grunt or Gulp -- Both Grunt and Gulp are Automated Task Runner on Node.js. Major Difference Between Gulp and Grunt Lies in How They Deal With Automation of Tasks Internally . Gulp uses node streams in memory for running different tasks and Grunt use intermediary files which are disk I/O operations for the same work. Memory vs. I/O operations, Gulp is clearly faster than Grunt. Gulp is a good choice if you prefer code over configuration, Gulp's stream style fluent api is cleaner than Gulp's configuration like api. Both tools are typically used to build, concat and minify javascript code for deployment.
  • Hubot -- open source tool written in CoffeeScript on Node.js, with out-of-box scripts and your own scripts, hubot can be customized to automate the code deployment with a simple slack command, email message, google home command etc.

VM Manager

  • Vagrant -- Vagrant is a free and open source tool for building and managing virtual machine environments in a single workflow. With Vagrant, developers can make local development environment as close to production environment as possible. 
  • Docker -- Where Docker relies on the host operating system, Vagrant includes the operating system within itself as part of the package. One big difference between Docker and Vagrant is that Docker containers run on Linux, but Vagrant files can contain any operating system.

Process Manager

  • PM2 -- PM2 is a production process manager for Node. js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks. Starting an application in production mode is as easy as: $ pm2 start app.js.

Communication

  • G suite  -- with google drive, gmail, google calendar, etc. you keep in touch with your team mates.
  • jira -- project management
  • confluence -- share knowledge
  • bitbucket/github/gitflow/svn -- share versioned code
  • slack -- chat tool
  • zoom -- online conference tool
  • citrix -- Citrix is an application that allows you to securely connect to a virtual desktop, server, application, or roaming profile through a terminal (or other computer).
  • Big IP edge client -- vpn connection.  
  • nomachine -- free, cross-platform, serverless remot e desktop tool that lets you setup a remote desktop server on your computer using the NX video protocol.  
  • cisco phone -- phone

Friday, June 26, 2020

Better splunk alerts with delta and predict keyword

Absolute value threshold triggered alert

The splunk triggers when a quantity hits certain threshold.

For example, a bookstore business want to get alert for abnormal ebook sell amount. A splunk trigger like the following could prompt the owner to check issues if the sell is too low during a particular hour.
The following query can be scheduled to run every hour at 0 minutes past the hour at number of results grater than 0.

index=Sell sourcetype=Ebook Stores IN (amazon109, ebay38,amazon339) (ACCOUNT_NAME=*-seller123-*)
| eval platform = case(MATCH(SERVER_NAME, "aws-*"),"AWS",1=1,"EBAY")
| bin _time span=1h
| stats count by _time, stores, platform
| where count < 10
| eval comment="see instruction http://bookstore.com/handle-low-sell.htm"

When triggered, we can post a message to slack channel with message

$name$
$description$
The sells amount dropped under 10 in the last hour

sells on store $result.stores$ in platform $result.platform$ is $result.count$, 
which is lower than the threshold in the last hour. 

Change triggered alert with delta keyword

This trigger won't be very useful if the bookstore is seasonal. In the busy days, this trigger might never get triggered and at slow days, this trigger might get triggered every single hour. What we are more concerned about is not the absolute amount of sell but the abnormal sudden spikes compare to the background curve.

In order to accomplish this goal, we need to modify the above query to compare the event corresponding to one bin to event corresponding to prior bin. For example, compare the sell count to the sell count one hours ago in order to get the difference.

index=Sell sourcetype=Ebook Stores IN (amazon109, ebay38,amazon339) (ACCOUNT_NAME=*-seller123-*)
| eval platform = case(MATCH(SERVER_NAME, "aws-*"),"AWS",1=1,"EBAY")
| bin _time span=1h
| stats count by _time, stores, platform
| delta count as sellchange p=1
| eval percentIncrease=(sellchange/count)
| where percentIncrease < -0.3
| eval comment="see instruction http://bookstore.com/handle-low-sell.htm"

Here we used a splunk keyword delta with p as parameter.
The delta keyword computes the difference between nearby results using the value of a specific numeric field. For each event where field is a number, the delta command computes the difference, in search order, between the field value for the event and the field value for the previous event. The delta command writes this difference into newfield. If the newfield argument is not specified, then the delta command uses delta(field). If field is not a number in either of the two values, no output field is generated.

By calculating the difference from hour to hour, we will detect sudden changes in counts, averages etc. between the hours, which generally means abnormal. This example has bin size 1 hour and p=1, that is hour over hour compare. For day over day comparison, we can use p=24, week over week comparison, we can use p=168. The p parameter has to be used together with the bin size. If bin size is 1h, p=1 means compare this hour with last hour. If bin size is 5m, p=1 means compare the latest 5 minutes with the previous 5 minutes. With small bin size, the trigger will be very sensitive to small and fast changes, with larger bin size, the trigger will be less fussy, small and rapid spikes can be smooth out while bigger problems get revealed.

Machine learning backed alert with predict keyword 

Splunk search result can be piped into machine learning algorithm, then we can use the previous data to predict the current data, if the actual data deviate from the prediction too much, an alarm should be triggered.

For example, the basic alarm can be modified to 

index=Sell sourcetype=Ebook Stores IN (amazon109, ebay38,amazon339) (ACCOUNT_NAME=*-seller123-*) earliest=-7d@h latest=now
| eval platform = case(MATCH(SERVER_NAME, "aws-*"),"AWS",1=1,"EBAY")
| timechart span=1h count 
| predict count algorithm=LLP period=24 holdback=24 future_timespan=23 upper99=high lower99=low as Prediction
| rename low(Prediction) as lowerThreshold
| rename high(Prediction) as UpperThreshold
| tail 24 | tail 23
| eval Result = case(count > UpperThreshold, "sellTooGood", count >= LowerThreshold, "Expected", count < LowerThreshold, "sellTooBad")
| where Result="sellTooGood" OR Result="sellTooBad"
| eval comment="see instruction http://bookstore.com/handle-low-sell.htm"

This query use LLP seasonal local prediction algorithm to make prediction. Based on the assumption that the sell amount has 24 hours cycle, we set period=24. future_timespan specify how many data points we want to predict, holdback specify how many latest points we don't want to use for the prediction. The upper99 and lower99 can be modified to upper90 lower90 etc. It decides how much we can tolerate false positive. When the LowerThreshold triggers alert. upper90 will have less false positive than upper99.

Alert strategy

When setting alerts, we are facing the eternal question how much we should alert. If the alert is too sensitive, we get lots of false alarms, on the other extreme,  we might miss critical events that could hurt us a lot for even one miss! A typical scenario is, an instructor bought 100 books in one hour, in the next hour, the sell count is normal, say 20. The change alert will be triggered, but that is a normal situation. If the 100 book sell event happens at mid-night and the alert triggered a pagerduty call, the responder might get annoyed. In another mid-night, a disk failure could also trigger the change alert, in that case, ignore it will result in financial loss or harm the business reputation. Of course we can amend the existing alert for this particular case, but another 2 similar situations could trigger the alert, the story goes on and on.

No matter what technology we use, we have to sample then decide to be or not to be, there is no silver bullet unfortunately. Someone has to apply domain knowledge to decide what is expected and what is not. However, we can use a set of alerts combined with other technologies to alleviate the problem if cut a precise decision threshold in one alert is hard.

One dimension we can engineer is the splunk sample strategy, we can use different strategies to sample the data. Lets call it quick-early, quick-late, slow-late strategies.
  • quick-early. If you want to have a "quick" alarm, then sample every 5 mins for the last 5 mins. This will have most false positives, but it will capture most of the fast changing abnormal signals as soon as possible.
  • quick-late. If you want to have a "quick" alarm but take into consideration more time, then sample every 5 mins, but for the last 15 minutes. This will get rid of the majority of false positives, however, the abnormal signals will be detected later than the previous strategy.
  • slow-late. If you want to have a "slow" alarm, then sample every 15 mins for the last 15 mins. This will have the lest false positives, but it has chance to ignore fast changing abnormals and is also slower to detect the abnormals than the quick-early strategy.
For example, we can create a splunk query that summarizes each hour over 15 hours and only trigger if the hour-based-alarm goes off for more than a few times. Set the alarm for a 5 hour run summarizing over 15 hours, and that should even out the fast changing spikes thus reduce the false positives.

Another dimension we can engineer is how we response to the alert. For example, if the alert is configured to trigger pagerduty, we can configure the pagerduty response strategy. We can have an alarm go off and then auto snooze or auto resolve if it does not go off again. This way we can have it alert us and set it to low priority, but escalate it to high priority if it happens again or let it naturally be resolved by pager duty if it does not reoccur in X number of hours. 

Like a work group need different types of team members, we can use a group of splunk alerts to monitor the same concern. For example, we can have one alert with low-priority but covers a lot of false positives, we can set the alert to be auto resolved if not repeating or simply log the alert message to a slack channel or send an email for later review. We can have other alerts with high-priority, which only capture the obvious issues and trigger pagerduty. 


Wednesday, June 24, 2020

How to build rpms

prepare the source file

first of all, you need all your source files ready under ~/RPMBUILD/SOURCES dircetory
For example if you wan to build jkd1.8.0 rpm, you may want the java8-local_policy.jar and java8-US_export_policy.jar from java 8 JCE and the jre-8u111-linux-x64.tar.gz from oracle website.

prepare the .spec file

once the source files are in place, you need to write a mybuild.spec file to instruct the rpm command how to pre, build, install, clean, files, preun, post the files in the rpm package.
this file has to be put in the ~/RPMBUILD/SPECS directory.

build rpm

now you can run the following command to build the rpm
rpmbuild -ba ~/RPMBUILD/SPECS/mybuild.spec

this command will put the resulting rpm in ~/RPMBUILD/RPMS/x86_64.

post to yum repo

You can optional set the rpm to be managed by yum.
Assuming you plan to place the repository in /var/www/html which is the default directory for Red Hat based Apache installations.
Also assuming you have run 

yum install yum-utils;
reposync -p /var/www/html/;

so that you can present this directory with apache.

now all you have to do is copy the rpm into /var/www/html/fedora/jdk8/
then run command
run createrepo /var/www/html/fedora/jdk8/

If your apache server is running, your new rpm should now be managed by yum.
If not, run it:
yum install httpd;
chekconfig httpd on;
service httpd start;


config yum client

On the client host you need to point the yum repo to the yum server you just setup,

for simplicity, lets use the yum server itself as client

create a /etc/yum.repos.d/local.repo file
[Local-Repository]
name=mylocal
baseurl=http://ip-of-my-server/fedora/jdk8
enabled=1
gpgcheck=0

final result

now once you type 
yum install rpm-name-set-in-spec-file

the rpm will be intalled




4 types of git branches

If you have worked as software engineer in cooperate environment, you should have already familiar with develop branch and master branch. Svn merge strategy is slightly different from git strategy, but they are quite similar. In git, the branch names are arbitrary, we can name branch whatever we like, and all the branch names are equal. However industry adopted some conventions. Usually we have a branch named develop, which is from master branch. All the developers contribute to this branch. From this branch, test releases are often created, which are the temporary packages deployed to the QA servers.

Once the develop branch is tested and stable, software developers or release engineers will merge the develop branch to the master branch. The master branch is usually used to create the package that will be released to production and deployed on the production servers.

Besides the develop branch and master branch, we usually encounter other 4 types of repository branches.

1. Bugfix branches are typically used for fixing bugs against a release branch. Conventionally these branches are prefixed with bugfix/
2. Feature branches are typically from and merged back into the development branch, they often used for specific feature work. Conventionally these branches are prefixed with feature/.

Bugfix branches and feature branches are where developers check in code, create pull request, check in code review updates. This is a safe branch to experiment. Any mistake only effect this particular branch, won't effect other developers working on other branches. The bugfix and feature only start to effect other developers after they are merged to the development. Sometimes, more than one developers updated the same line of the develop branch in their bugfix or feature branches, there will be merge conflict. The developer merge his/her branch earlier won't have problem, the developer merges his/her branch later will get merge conflict at the time of command "git push". 

The solution is to 
  • git checkout develop
  • git pull
  • git checkout bugfix/bugfixbranchname
  • git pull
  • git merge develop
At this point, the merge will fail, but the failure message will list all the files with conflict.
Go the files and manually fix the conflict lines, the 
  • git commit -am "solve conflict"
  • git push

3. Hotfix branches are typically used to quickly fix the production branch. They conventionally are prefixed with hotfix/. Hotfix often goes the fast path in emergency situations, they often directly from the master branch, and merge back to master branch. Then these changes are applied back to the development branch.

4. Release branches are typically branches from the develop branch and changes are merged back into the develop branch, they are used for release tasks and long-term maintenance. Some company use master branch as the release branch, then use tags to differentiate different releases. Some companies has multiple release branches names other than master. They conventionally are prefixed with release/.


Wednesday, June 17, 2020

How to group splunk stats by common string in field value

We all know splunk can make time chart. For example, we want to know how many http requests are received on a particular type of servers. A typical splunk query could be:

index=http_stats_10d sourcetype=FRONT_END_LB host=*-mobileweb-* | timechart count by host

The timechart will be grouped by host such as pvd-mobileweb-001, pvd-mobileweb-002, pvd-mobileweb-003, chi-mobileweb-001, chi-mobileweb-002, tor-mobileweb-001, tor-mobileweb-002, tor-mobileweb-003.

Now let's assume we want to group the timechart by data site prefix string pvd, chi and tor instead of the whole hostname string. The following technique will do the trick.

eval site=mvindex(split(host, "-"), 0)

the above command reads, split host string by "-" and take the the index 0 element from the result array, and assign it to variable site. This way we extracts the prefix from the host string.

Now we can revise our splunk query to group by site instead of by host.

index=http_stats_10d sourcetype=FRONT_END_LB host=*-mobileweb-*
| eval site=mvindex(split(host, "-"),0)
| timechart count by site


Friday, May 29, 2020

How to set up maven in mac os x

first download apache maven, the downloads url is: http://maven.apache.org/download.html

unpack it to a folder, say /Users/yourid/Downloads/apache-maven-3.3.3

modify your ~/.bashrc, make sure the following lines are there

export M2_HOME=/Users/yourid/Downloads/apache-maven-3.3.3
export PATH=$PATH:$PATH:$M2_HOME/bin

now you can use maven in command line and eclipse or intellij etc.

advanced maven command line

mvn dependency:resolve install
mvn versions:set -DnewVersion=1.2.2
mvn clean install -U
mvn dependency:tree

Eclipse common maven actions

right click a project,
preferences --> maven --> update project.
preferences --> Maven: select Download Artifact sources
preferences --> Maven --> installation: set the maven location
right click a project, run as --> maven install

Thursday, May 21, 2020

How to generate date string with shell command

Sometimes we need to generate date string, the shell command default format can brings us somewhere, but how about the date with format 20-05-10?
We can print date string using shell command date with format flags.

date +%y-%m-%d
for example will print today's date in short format as
20-05-13

sometimes, the generate date strings can be used to construct other shell commands with ``.
The date command wrapping inside `` will get executed first, the result string then concatenated with the rest of the strings to form a shell command.

For example, when the following command is executed

echo filename.`date +%y-%m-%d`.log

`date +%y-%m-%d` will execute first, generate a string 20-05-13. Then string 20-05-13 is concatenated with rest of the command to get a new shell command:

echo filename.20-05-13.log

the above command's running result is
filename.20-05-13.log
 
=================
demo>date
Wed May 13 15:05:10 EDT 2020
demo>date +%y-%m-%d
20-05-13
demo>echo filename.`date +%y-%m-%d`.log
filename.20-05-13.log
==================

Similarly, we can use the same technique to construct more sophisticated grep shell command:

ls myapp.`date +%y-%m-%d`*.log | xargs -I {} cat{} | grep -i 'exception\|error' -A 2 -B 2

the above command, list all myapp log files generated today. Among though files, we search for exception and error messages, print out the line with 2 lines before and 2 lines after.

Thursday, May 14, 2020

SQL table join equivalent for splunk index join

splunk have a feature to join 2 indexes data together by a field. This solution is similar to sql's table join by column.
Here we can have have these analogy:

  • splunk query<-> sql query, 
  • splunk index <->sql table, 
  • splunk field <-> sql column.
  • splunk subquery join <-> sql table join

Subquery join


For example, you have index service_request and another index service_bill

For service_request index, you have a splunk query to get all the services request for a particular vendor.
index="service_request" vendor=Dell

For service_bill index, you have a query to get all service bills that are pending
index="service_bill" PENDING

Now, the problem is the billing PENDING status field is not in service_request index, so if we want to generate stats such as the percentage of service requests that are in complete status has not been paid, we need to join the two indexes. To join them, we need common field, assume both index has request_id field. We can then write the following splunk query to join the two indexes.

index="service_request" vendor=Dell
| eval REQUEST_ID=request_id
| join REQUEST_ID [search index="service_bill" PENDING | fields REQUEST_ID]
| stats count AS total, count(eval(service_status="COMPLETE")) as outOfStatus
| stats avg(eval(outOfStatus/total)*100) as outOfStatusRate

There is an important detail: the splunk subsearch query result can have maximum 10500 records. If you are query a days of data, you might be fine, if you are querying 10 year of data, you are most likely exceed the limit.
If query
index="service_bill" PENDING
returns more than 10500 rows, your final stats will be wrong!

Another import details is, when join a query and a subquery by common field, the two field names have to be exact match, upper case and lower case letters are considered different. In the example, field name request_id in index="service_request" has to be mapped to upper case REQUEST_ID with "eval REQUEST_ID=request_id" in order to match the field name REQUEST_ID in index="service_bill" before we join them.

This limitation is set by splunk platform, we can not really do much about it. One thing we can do as splunk user is to prune the subquery to return only the records we needed.
for example, if the service_bill index also has a VENDOR field, use it to prune out those rows won't be relevant.
search index="service_bill" PENDING VENDOR="DELL"

and the join will be

index="service_request" vendor=Dell
| eval REQUEST_ID=request_id
| join REQUEST_ID [search index="service_bill" PENDING VENDOR="DELL" | fields REQUEST_ID]
| stats count AS total, count(eval(service_status="COMPLETE")) as outOfStatus
| stats avg(eval(outOfStatus/total)*100) as outOfStatusRate

that way, we can do stats with larger time span.

The index subquery join technique can also be applied to generate timechart. For example, we want to know further about the trending of payment pending time for those requests. We can add that field from the subquery

index="service_request" vendor=Dell
| eval REQUEST_ID=request_id
| join REQUEST_ID [search index="service_bill" PENDING VENDOR="DELL" | fields REQUEST_ID, PAYMENT_DUE_HOURS]
| timechart span=1h avg(PAYMENT_DUE_HOURS) by service_status

Subquery Inner join vs. Outer join

In the above example, 

...query... | join common_field [...subquery...] 
| timechart/stats/ect.

The "join" keyword did an inner join, the main query and subquery need to have a common field. After join, we actually appended a few fields from the subquery to each events in the main query. The augmented main query events can then be used normally. We can filter it, pipe it to stats command or timechart command etc. The final effect is an inner join, but the splunk implementation 
run subquery query 
search index="service_bill" PENDING VENDOR="DELL" 
for the time range the main query use, then perform an inner join. So if the above query has more than 10500 events, the results set get truncated.

There is another kind of query and subquery join in splunk

...query...| append [...subquery...]
|timechart/stats/etc.

The "append" keyword did an outer join, the two indexes event fields don't have anything common exact they are arranged by time, the event set A of main query and the event set B of subquery are simply outer joined together, so we get A+B number of events.

Subquery append will be useful if we want to generate the time chart of 2 field's ratio from different indexes that share no common field

For example, we have one index impression_stats to store the advertisement impression events, and another index buy_stats to store the advertisement click events. We want to get the time chart of ad impression count to ad click count during a time period.

We can use the following example query:

index="impression_stats" platform="blogspot" | bin _time=1h | stats count as impression by _time
| append [search index="buy_stats" sourcetype="web_ad" | bin _time=1h | stats count as buy by _time]
| stats max(impression) as a, max(buy) as b by _time
| eval c=rount((b/a),0)
| stats max(c) as "Click-to-Impression Ratio" by _time

Since we don't have to coordinate the results of the main query and subquery other than _time field, we can  reduce the amount of records in the subquery final with bin and stats. 
After put the records in buckets of 1 hour then count the number of events in that bucket, we reduce the original event set to its 1 hour interval time based statistics events sets. If we have to make stats for bigger time span thus need to have more events in the subarray, we can increase the time interval in "bin _time=1h" so that we reduce the results set more aggressively, in order to not exceed the 10500 maximum events counts in subquery results. The main query and subquery don't have common field, how they are outer joined? They are outer joined by _time field. So if subquery use bin side 1 hour, the main query have to use the same bin size 1 hour, otherwise, the later stats by  _time won't make sense.

Here we use the following technique to coordinate the counts from main query and subquery. 
| stats max(impression) as a, max(buy) as b by _time

At a particular _time value, we will have 2 events, one is from main query, another is from subquery. With outer join, the main query's impression field will has a positive value, the subquery's impression field will has a default/null value as 0. 
max(impression) 
will get the non-zero value from the two. For the same reason, 
max(buy) 
will get the non-zero value from the 2 events as well. 
So at the next step, we can get the ratio  with
| eval c=rount((b/a),0)
finally, we can draw the time chart with command
| stats max(c) as "Click-to-Impression Ratio" by _time

Of course, nothing prevent us from putting a multiple curves together with the same _time field as x-axis.

index="impression_stats" platform="blogspot" | bin _time=1h | stats count as impression by _time
| append [search index="buy_stats" sourcetype="web_ad" | bin _time=1h | stats count as buy by _time]
| stats max(impression) as a, max(buy) as b by _time
| eval c=rount((b/a),0)
| stats max(a) as "Impression", max(b) as "Click", max(c) as "Click-to-Impression Ratio" by _time

MarketAxess

MarketAxess: The Leader in e-Trading for Global Fixed Income MarketAxess Holdings Inc. (MarketAxess) is an international financial technol...